Kotlin泛型(協變和逆變)實戰

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章