泛型,也是经常问的。其实很容易理解的。
泛型指的就是容器所装对象的类型,只不过这个类型事先无法确定,就先用T来表示。
看起来就像这个样子:container<T>。
因为这是设计阶段,所以并不知道将来会装啥,就用个占位符来代替。就好像我设计个岗位,岗位里放小张还是小李,还不知道。
这和变量的变量名和变量值也是一回事,只不过在泛型里,它的类型是个变量。
我们常觉得程序分编译器和运行期,编译器是未知的,运行期是知道的。
但泛型的未知和已知,都是在编译器,在运行期它反而是“擦除”的。泛型的未知就是在设计容器类的时候,已知就是在设计场景类的时候。
container<T> 泛型的已知会类似container<Apple>。
大部分场景,用到这儿就好了。
还有稍微深度一些的,也很简单,就是container<T extends Fruit>。这个时候就只能为container装Fruit以及它的子类。如果设计类时写成container<T extends Apple>,那就只能放Apple及它的子类,而不能放Banana类型。有extends的写法时,那么除了针对Object类型所能做的操作,还可以根据extends的源对象做一些操作了。
泛型中,是没有super关键字的。要和通配符类型作区分。
说到通配符类型了。容易搞混的,就是通配符类型,写法就类似这样子:<? extends Fruit>、<? super Fruit>。
List<? extends Fruit>修饰的是=号之后的集合类型。比如:List<? extends Fruit> a = new ArrayList<Apple>;
<? extends Fruit>表示这个集合中只会放继承自Fruit类型的类型的对象,比如Banana、Apple,它既有可能放Banana,也有可能放Apple。运行期是不知道的,所以就不让你再放任何东西。但是可以取,因为取到的一定是Fruit类型或是其子类,那么用Fruit类型去装就可以了,这个是可以确定的。
<? super Fruit>表示这个集合中只会放Fruit类型的父类的对象,比如Food。所以只要是Fruit的子类,都可以放。但是取对象的时候,不能确定是Food还是Fruit还是Apple,那么就会转换成一个最不会错的类型,也就是Object。
所以,通配符类型的存取数据要小心。在总结下,extends是不让放的,因为确定不了类型,但可以取,因为知道一定是原类型的子类。super的取是有限制的,因为确定不了哪个父类,只能成为Object,但放是没问题的,因为这个集合一定是它们父类的集合。
网友评论