首先看看在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;