泛型的使用
jdk 5新特性
一、在集合中使用泛型:
- 集合接口或集合类在jdk 5时都修改为带泛型的结构
- 在实例化集合时,可以指明具体的泛型类型
- 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。比如:add(E e) ---> 实例化以后:add(Integer e)
- 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,就使用包装类。
- 如果实例化时,没有指明泛型的类型。默认类型为Object类型
二、如何自定义泛型结构(泛型类、泛型接口、泛型方法)
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 String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
}
@Test
public void test1(){
//如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
//要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型
Order order = new Order();
order.setOrderT(123);
order.setOrderT("tom");
//建议:实例化时指明类的泛型
Order<String> order1 = new Order<>("orderName", 1001, "Order的描述");
order1.setOrderT("啊啊啊");
}
注意点:
-
泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1, E2, E3>
-
实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
-
泛型不同的引用不能相互赋值。
@Test public void test4(){ ArrayList<String> list1 = null; ArrayList<Integer> list2 = new ArrayList<>(); //泛型不同的引用不能相互赋值 // list1 = list2; }
-
泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价 于Object。经验:泛型要使用一路都用。要不用,一路都不要用。
-
如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
-
在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。
-
异常类不能是泛型的
三、自定义泛型方法的使用
泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系;泛型方法可以声明为静态的。
//泛型方法所属的类是不是泛型类都没有关系
public <E> List<E> copyFromArrayToList(E[] arr){
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
//测试泛型方法
@Test
public void test4(){
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1,2,2,4};
//泛型方法在调用时,指明泛型参数的类型
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
四、泛型在继承方面的体现
虽然类A是类B的父类,但G 和 G 不具有子父类关系,二者是并列关系
补充:类A是类B的父类,A
@Test
public void test1(){
Object obj = null;
String str = null;
obj = str;
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;
List<Object> list1 = null;
List<String> list2 = null;
//此时的 list1 和 list2 不具有子父类关系
// list1 = list2;
}
@Test
public void test2(){
AbstractList<String> list1 = null;
List<String> list2 = null;
ArrayList<String> list3 = null;
list1 = list3;
list2 = list3;
}
五、通配符的使用
通配符:?
类A是类B的父类,G 和 G 是没有关系的,二者的共同父类是G<?>
@Test
public void test3(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;
print(list1);
print(list2);
}
public void print(List<?> list){
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
}
通配符的写入与读取
@Test
public void test3(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;
//
List<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
//添加(写入)
//对于List<?>就不能向其内部添加数据了。除了添加null以外
list.add(null);
//获取(读取):允许读取数据,读取的数据类型为Object
Object o = list.get(0);
System.out.println(o);
}
有限制条件的通配符的使用
? extends A:G<? extends A> 可以作为G 和 G的父类,其中B是A的子类
? super A:G<? super A> 可以作为G 和 G的父类,其中B是A的父类