泛型(2)
1、泛型在继承上的体现
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G并不是G的子类型!
比如:String是Object的子类,但是List并不是List的子类。
class A <T> extends superA<String>{......}
只有泛型类相同时,父类与子类之间才能体现继承关系。
例如:父类SuperA<String>与子类A<String>之间存在继承关系,类A的实例对象可以被SuperA引用体现多态性;但SuperB<Object>与B<String>之间没有继承关系。
2、通配符的使用
当我们声明一个变量/形参时,这个变量/形参的类型是一个泛型类或泛型接口,例如:Comparator类型,但是我们仍然无法确定这个泛型类或泛型接口的类型变量的具体类型,此时我们考虑使用类型通配符 ? 。
(1) 通配符的理解
使用类型通配符:?
比如:List<?>,Map<?,?>
List<?>是List<String>、List<Object>等各种泛型List的父类。
(2) 通配符的读与写
写操作:
将任意元素加入到其中不是类型安全的:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // 编译时错误
因为我们不知道c的元素类型,我们不能向其中添加对象。add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。
唯一可以插入的元素是null,因为它是所有引用类型的默认值。
读操作:
另一方面,读取List<?>的对象list中的元素时,永远是安全的,因为不管 list 的真实类型是什么,它包含的都是Object。
@Test
public void test1(){List<?>list = null;//通配符‘?’不确定类型List<String> list1 =Arrays.asList(new String[]{"Qum","Dit","TuSu"});list = list1;Object obj = list.get(0);//get得到Object的接收值System.out.println(obj);//可以读取,不能写入
}
总结:使用通配符的集合,可读不可写。其他泛型类型的集合可以赋值给使用通配符的集合。
@Test
public void test4(){List<?>list = new ArrayList<>();List <String> list1 = null;List <Integer>list2 = null;list = list1;//使用通配符作为泛型类型可以传入任意泛型类型的集合元素。list = list2;//list1 = list2;编译时错误,泛型类型不同不能传入集合元素。
}
(3) 使用注意点
注意点1:编译错误:不能用在泛型方法声明上,返回值类型前面<>不能使用?
public static <?> void test(ArrayList<?> list){
}
注意点2:编译错误:不能用在泛型类的声明上
class GenericTypeClass<?>{
}
注意点3:编译错误:不能用在创建对象上,右边属于创建集合对象
ArrayList<?> list2 = new ArrayList<?>();
(4) 有限制的通配符
- <?>
- 允许所有泛型的引用调用
- 通配符指定上限:<? extends 类/接口 >
- 使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
@Test
public void test2(){List<? extends Person> list = null;List<Object> list1 = null;List<Object> list2 = null;List<Person> list3 = null;List<Student> list4 = null;//list = list2;list = list3;//extend,继承于。 Person、Person的子类可以传入list = list4;
}
- 无法写入数据,除了null
- 通配符指定下限:<? super 类/接口 >
- 使用时指定的类型必须是操作的类或接口,或者是操作的类的父类或接口的父接口,即>=
@Test
public void test3(){List<? super Person> list = null;List<Object> list1 = null;List<Object> list2 = null;List<Person> list3 = null;List<Student> list4 = null;list = list2;list = list3;//super,写入父类, Person或者其父类可以传入//list = list4;
}
- 可以写入Person及其子类的数据。
- 说明:
- extends Number> //(无穷小 , Number]
//只允许泛型为Number及Number子类的引用调用
<? super Number> //[Number , 无穷大)
//只允许泛型为Number及Number父类的引用调用
<? extends Comparable>
//只允许泛型为实现Comparable接口的实现类的引用调用