1.符号解释
乍一看是List集合,里面的? super T 和? extends T是什么鬼。实际上,这是两类泛型的设计。
?:通配符,表示任何,List<?>和List<Object>效果一样
T:T是某类型,只有在使用时才确定类型,“使用时才确定”这句话是不是有点熟悉?在多态、接口中都有体现。
super T:super T代表T和T的超类(T和它的父辈)
extends T: 代表T和T的子类。
2.什么是类型转换?
集合的使用场景,无非就是两种:添加和读取
在对这两类集合进行读取或添加元素时,都要涉及类型转换的问题。Java中的类型转换分为两种:
1.安全的类型转换(向上类型转换):子类转为父类
2.不安全的类型转换(向下类型转换):父类转为子类
原因解释:
2.1向上类型转换为什么是安全的?
因为它是多态的实现形式,不会报编译异常、运行时异常,因此是安全的。举个常见的实现多态的语句:Animal a=new Cat(); 。
2.2向下类型转换为什么是不安全的?
为了方便论述,创建一个对象:Animal a=new Animal(),Animal和Cat是包含与被包含的关系,随便拿只猫,都可直接判定猫是动物,体现在代码上: Animal a=new Cat(); 但随意拿只动物,不能直接判定它就是猫,也许它是只狗或者其他动物呢?体现在代码上:Cat cat=(Cat) a(强行认为它是只猫就可能引起异常,这也符合人类的逻辑认知)。因此子、父类间的类型转换必须遵从向上转换原则。
回到最初的问题,考虑向上转换原则,将两种集合指定存放的元素类型记为D:
1.对于<? super T>,D是T或者T的超类。插入:当插入T或T的子类时,类型转为D时可能涉及向上转型,是安全的,其他插入情况均不安全;读取:由于不清楚D具体所指哪种类型,比如集合里面放的是Number,但取元素时用Interger来接,可能涉及向下转型(不安全)。所以<? super T>不用作读取,仅作插入使用,插入元素要求是T或T的子类。
2.对于<? extends T>,D是T或者T的子类。读取:将接收元素的变量类型指定为T,从D到T涉及向上转型,是安全的。插入:由于不清楚D具体所指哪种类型,比如集合里面已经存放的是Integer,但要插入的元素是Number类型,可能涉及向下转型(不安全)。所以对于<? extends T>不用作插入,仅作读取使用,接收元素的变量类型必须为T类型。