- 什么是协变和逆变
- 什么情况下存在协变和逆变
- 数组是协变的
- 泛型是不变的?
- 协变的实现
- 逆变的实现
- 参考地址
Java中String类型是继承自Object的,姑且记做String ≦ Object,表示String是Object的子类型,String的对象可以赋给Object的对象。而Object的数组类型Object[],理解成是由Object构造出来的一种新的类型,可以认为是一种构造类型,记f(Object)。
那么可以这么来描述协变和逆变:
当A ≦ B时,如果有f(A) ≦ f(B),那么f叫做协变;
当A ≦ B时,如果有f(B) ≦ f(A),那么f叫做逆变;
如果上面两种关系都不成立则叫做不可变。
public class A {
}
public class B extends A {
}
A a = new B();
A[] as = new A[10];
as[0] = new B();
泛型是不变的?
不设置通配符的情况下,
ArrayList
无法编译。
原因是类型擦除的存在,最终都会编译成Object,所以不支持协变。
但是,如果配置通配符,就可以实现逆变和协变,这是因为编译后也不会都是Object,而是我们定的限定类型。
协变的实现协变通过 ?extends 实现,指定父类类型。
协变只读:
数据一旦创建禁止修改,这是因为他也不知道你第一次创建的时候,是使用了什么子类类型,第二次再修改和第一次的类型不一致肯定会导致问题,这就是不能改的原因。
Number number = new Integer("1");//子可以赋值给父
//协变
ArrayList< ? extends Number> list= new ArrayList();//子可以赋值给父
list.add(1); //error
Number number = list.get(1);
逆变的实现
逆变通过 ?super 实现,指定子类类型。
逆变只写:因为Number是Integer父类,指定子类的情况下,只要是父类都可以写入;但是如果取出来,就不知道取出后应该是什么父类类型了,这就是不能取的原因
Number number = new Integer("1");//子可以赋值给父
//逆变
ArrayList< ? super Integer> list2 = new ArrayList();//父可以赋值给子
list2.add(1);
Integer integer = list2.get(1);//error
参考地址
Java中的逆变与协变:https://blog.csdn.net/zero__007/article/details/52245475



