首先看看在Java中协变和逆变的栗子
public class Animal {
}
public class Cat extends Animal{
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
List<Cat> cats = new ArrayList<>();
List<? extends Animal> animals= cats;
}
这样是可以赋值成功的
这样是编译失败的,因为animal的类型是List<Animal>或者List<Animal的子类>,如果把new Cat放进去了,那么把取出来的时候到底是不是Cat类型取决于声明的泛型类型,这里根本不知道真正的类型是什么,只知道是List<Animal>或者List<Animal的子类>,那么可能是Cat 也可能是Dog。所以协变的特点是就是读取操作,写入的操作是不被允许的。那么逆变是可以写入,但是不能读取。
下一个栗子:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
List<Animal> animals1 = new ArrayList<>();
List<? super Animal> animals2 = animals1;
}
animals1 的类型是 List<Animal>,animals2的类型是List<Animal>或者List<Animal的父类型一直到Object>
animals2里面添加new Cat()是可以的,Cat是位于Animal下面的为什么可以?
根据多态,Cat就是Animal,所以这种操作时可以的。如果我读取呢?
不兼容类型,不允许读取,因为animals2的类型是List<Animal>或者List<Animal的父类型一直到Object>都可以,赋值给Animal,显然是不允许的。
Java中 的数组是天然支持协变的,解释下这句话:
List<String> 和List<Object>是不能直接赋值的,但是对于数组来说呢,比如:
Object[] objects = new String[]{"hello","world"};
这样做是可以的。将String类型的数组赋值给Object类型的数组,是可以的,这是协变。但是是有问题的:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
Object[] objects = new String[]{"hello","world"};
objects[0] = new Object();//编译通过,运行时报数组存储异常
}
接下去看下Kotlin
class TestClass<A>(private val value: A) {
fun getValue(): A {
return this.value
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
val testClass = TestClass<String>("hell world")
val result = testClass.getValue()
}
这样写是没有任何问题的,定义好什么类型,就按照泛型来使用
class TestClass<out T>(private val value: T) {
fun getValue(): T {
return this.value
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
val testClass = TestClass<String>("hell world")
var myClass: TestClass<Any> = testClass
}
这个是Kotlin的协变。类似于Java中的这种情况
List<String> list2 = new ArrayList();
List<? extends Object> list = list2;
class TestClass<in T> {
fun toString(value: T): String {
return value.toString()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
val testClass = TestClass<Number>()
var myClass: TestClass<Int> = testClass//父类型赋给子类型
}
这个是Kotlin的逆变。类似于Java中写这种情况
List<Object> list = new ArrayList();
List<? super String> list2 = list;