本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-06-25
把元素的类型设计成一个参数,这个类型参数就是泛型。
import org.junit.Test;
import java.util.*;
public class GenericTest {
@Test
public void test1() {
// 必须是包装类,而不能是基本数据类型 int
ArrayList<Integer> list = new ArrayList<Integer>();
// 后面的泛型参数一样 可以省略
// ArrayList<Integer> list = new ArrayList<>();
list.add(123);
list.add(456);
list.add(789);
// list.add("123"); // 编译时就会报错
for (Integer number: list) {
System.out.println(number);
}
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
int n = iterator.next(); // 直接就能用int来接收
System.out.println(n);
}
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("jack", 123);
// map.put("jack", "male"); // 编译就会报错
// 泛型的嵌套
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
while(iterator1.hasNext()) {
Map.Entry<String, Integer> next = iterator1.next();
String key = next.getKey();
Integer value = next.getValue();
System.out.println(key + "===>" + value);
}
}
}
// Order.java
public class Order<T> {
String orderName;
int orderId;
// 上面添加了类型参数,在类的内部结构中就能使用类的泛型
T orderT;
public Order() {};
public Order(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
public T getOrderT() {
return this.orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
}
// GenericTest2.java
import org.junit.Test;
public class GenericTest2 {
@Test
public void test1() {
// 如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型 所以建议如果定义了实例化是就应该使用
Order order = new Order();
order.setOrderT(123);
order.setOrderT("ABC");
Order<String> order1 = new Order<>();
Order<String> order2 = new Order<>("orderA", 1, "服装订单");
order2.setOrderT("汽车订单");
System.out.println(order2.getOrderT());
}
@Test
public void test2() {
SubOrder sub1 = new SubOrder();
// 由于子类SubOrder在继承带泛型的父类时,指明了泛型类型 public class SubOrder extends Order<Integer> {}
// 则实例化子类对象时,不需要在指明泛型
sub1.setOrderT(123);
// public class SubOrder1<T> extends Order<T> {}
SubOrder1<String> subOrder1 = new SubOrder1<>();
subOrder1.setOrderT("123");
}
}
需要注意的点:
泛型类可能有多个参数,此时可以将多个参数一起放在尖括号内,比如 Order<T, K, E>
泛型类的构造器如下:public Order() {}
而不是 public Order<T>() {}
泛型不同的引用不能相互赋值
@Test
public void test() {
Person p1 = null;
Person p2 = null;
p1 = p2; // 这样是可以的
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = null;
list1 = list2; // 这样编译就会报错
}
泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等于Object。
如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
泛型的指定中不能使用基本数据类型,可以使用包装类替代。
在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型,但在静态方法中不能使用类的泛型。
public class Order<T> {
T orderT;
public Order() {};
public Order(T orderT) {
this.orderT = orderT;
}
public static void show() {
// 在静态方法的方法体里面访问会报错
System.out.println(orderT);
}
// 在静态方法的参数里面使用也会报错
public static void say(T orderT) {
System.out.println(orderT);
}
// 因为静态方法会早于类加载的时候加载,此时泛型还没有指定,泛型会在类的对象创建的时候指定,
// 所以在静态方法中不能使用类的泛型
// 上面的都不是泛型方法,泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系
// 如果是一个泛型方法,那么是可以使用泛型的,因为它会在方法调用的指定。
// 见下面 泛型方法 部分的示例
}
异常类不能声明为泛型类
子类和父类的泛型继承
class Father<T1, T2> {}
// 子类不保留父类的泛型
// 1、没有类型
class Son1 extends Father {}
// 等价于 class Son extends Father<Object, Object> {}
class Son1<A, B> extends Father {}
// 等价于 class Son<A, B> extends Father<Object, Object> {}
// 2、具体类型
class Son2 extends Father<Integer, String>{}
class Son2<A, B> extends Father<Integer, String>{}
// 子类保留父类的泛型
// 1、全部保留
class Son3<T1, T2> extends Father<T1, T2> {}
class Son3<T1, T2, A> extends Father<T1, T2> {}
// 2、部分保留
class Son4<T2> extends Father<Integer, T2> {}
class Son4<T2, A> extends Father<Integer, T2> {}
T<A>
和T<B>
二者不具备子父类关系,二者是并列关系。但A<T>
和B<T>
是父子类关系,例如 List<String> list = new ArrayList<String>();
这样的赋值操作。有的场景需要封装方法技能处理T<A>
也能处理T<B>
,此时可以使用?
通配符来解决,T<?>
就是T<A>
和T<B>
共同的父类。import org.junit.Test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest2 {
@Test
public void test() {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<?> list = null;
list = list1;
list = list2;
list1.add(123);
list2.add("123");
list = list2;
// list.add("AA"); // 编译报错 error
// list.add(null); // 编译通过,但是会报错,因为上面设值list本质还是null不是一个ArrayList
// 对于List<?> list 就不能向其内部添加数据,但是除了null除外
Object o = list.get(0); // 编译通过 可以读取数据,读取的类型是Object
print(list1);
print(list2);
}
public void print(List<?> list) {
Iterator<?> iterator = list.iterator();
while(iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
}
/*
* 有限制的统配符的使用
* ? extends Perosn
* ? super Person
*/
@Test void test4() {
// 假设存在 Person Student BoyStudent 为 继承关系
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = null;
List<Person> list4 = null;
List<Object> list5 = null;
list1 = list3;
list1 = list4;
// list1 = list5; // error extend要求必须继承于或者等于Person
// list2 = list3; // error super要求必须是Person的父类或等于Person
list2 = list4;
list2 = list5;
list1 = list3;
Person map = list1.get(0);
// 可以不用是Object,因为约束最“大”的类就是Person了
list2 = list4;
Object o = list2.get(0);
// 这里要用Object,因为list2约束最小的类就是Person,可能会比它大,所以不能用Person来接收
// 写入数据
// 编译不通过,因为extend约束要小于Person
// 那如果Student的子类BoyStudent更小于Person,显然可以有
// List<BoyStudent> boys 也能赋值给list1
// 此时如果add一个new Student() 就是父类赋值给子类,所以不允许
list1.add(new Student());
// list2的约束,必须是Person或者Person的父类
// 所以Person是最小的,即使List<?>是大于Person的父类,也能add,因为也是属于子类赋值给父类
// 既然Person 那么Person的子类也就更可以了
list2.add(new Person());
list2.add(new Student());
}
}
// 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系
// 可以声明成static
public <E> List<E> copyFromArrayToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for(E e: arr) {
list.add(e);
}
return list;
}
@Test
public void test() {
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1, 2, 3 ,4};
List<Integer> integers = order.copyFromArrayToList(arr);
System.out.println(integers);
}