一、类型擦除
首先看下面这段代码:
按照Java重载来说,我参数列表不同,它是不会报错的,但是这里报了一个同名错误,这是因为 Java在编译的时候会把泛型,上面的<String>和<Integer>都给擦除掉。这就是java 的类型擦除。
ps:这里并没有真正的擦除
二、协变
我们可以利用通配符来实现泛型的协变:<? extends T>子类通配符;这个通配符定义了?继承自T,可以帮助我们实现向上转换:
现在list的类型是<? extends Fruit>,extends指出了泛型的上界为Person,<? extends T>称为子类通配符,意味着某个继承自Person的具体类型。使用通配符可以将ArrayList<man>向上转型了,也就实现了协变。实现了协变时,我们只能在list中get,而不能add。这是因为java把他向上转型了,这时候放入任何东西都是非法的,所以只能get。
三、逆变
逆变和协变相反,它是向下转换的,我们使用<? super T>来实现
<? super T>称为超类通配符,代表一个具体类型,而这个类型是man的超类。
就是说list中存放的是man类型或者man的子类。
总结:
协变:extends/向上转换/不能add/只能get(T及父类)
逆变:super/向下转换/不能get/只能add(T及子类)
逆变get元素的时候需要进行强制转换
这里借鉴了知乎上工藤新木的文章