協(xié)變、逆變、不變
Scala 語言中協(xié)變、逆變、不變是指擁有泛型的類型,在聲明和賦值時的對應(yīng)關(guān)系
協(xié)變:聲明時泛型是父類,賦值時泛型可以是父類也可以是子類
逆變:聲明時泛型是子類,賦值時泛型可以是子類也可以是父類
不變:聲明時泛型是什么類型,賦值時也只能是什么類型
示例說明
準(zhǔn)備工作
現(xiàn)有類聲明如下:
// Dog 類繼承自 Animal 類
class Animal
class Dog extends Animal
協(xié)變
聲明語法:
// 協(xié)變類型,泛型前面有一個'加號'
class MyList1[+V]
示例代碼:
val list1_1: MyList1[Animal] = new MyList1[Dog]() // 正確
val list1_2: MyList1[Animal] = new MyList1[Animal]() // 正確
val list1_3: MyList1[Dog] = new MyList1[Animal]() // 出錯
說明:
協(xié)變類型聲明時泛型是父類,賦值時泛型可以是父類,也可以是子類
逆變
聲明語法:
// 逆變類型,泛型前面有一個'減號'
class MyList2[-V]
示例代碼:
val list2_2: MyList2[Dog] = new MyList2[Dog]() // 正確
val list2_3: MyList2[Dog] = new MyList2[Animal]() // 正確
val list2_1: MyList2[Animal] = new MyList2[Dog]() // 出錯
說明:
逆變類型聲明時泛型是子類,賦值時泛型可以是子類,也可以是父類
不變
聲明語法:
// 不變類型,泛型前面'沒有符號'
class MyList3[V]
示例代碼:
val list3_2: MyList3[Dog] = new MyList3[Dog]() // 正確
val list3_3: MyList3[Dog] = new MyList3[Animal]() // 出錯
val list3_1: MyList3[Animal] = new MyList3[Dog]() // 出錯
說明:
不變類型聲明時泛型是子類,賦值時泛型只能是子類
完整代碼
// Dog 類繼承自 Animal 類
class Animal
class Dog extends Animal
// 聲明擁有泛型的類,泛型前面有一個'加號'
class MyList1[+V]
// 聲明擁有泛型的類,泛型前面有一個'減號'
class MyList2[-V]
// 聲明擁有泛型的類,泛型前面'沒有符號'
class MyList3[V]
def main(args: Array[String]): Unit = {
// 協(xié)變類型聲明時泛型是父類,賦值時泛型可以是父類,也可以是子類
val list1_1: MyList1[Animal] = new MyList1[Dog]() // 正確
val list1_2: MyList1[Animal] = new MyList1[Animal]() // 正確
val list1_3: MyList1[Dog] = new MyList1[Animal]() // 出錯
// 逆變類型聲明時泛型是子類,賦值時泛型可以是子類,也可以是父類
val list2_2: MyList2[Dog] = new MyList2[Dog]() // 正確
val list2_3: MyList2[Dog] = new MyList2[Animal]() // 正確
val list2_1: MyList2[Animal] = new MyList2[Dog]() // 出錯
// 不變類型聲明時泛型是子類,賦值時泛型只能是子類
val list3_2: MyList3[Dog] = new MyList3[Dog]() // 正確
val list3_1: MyList3[Animal] = new MyList3[Dog]() // 出錯
val list3_3: MyList3[Dog] = new MyList3[Animal]() // 出錯
}
對比Java
Java 中只有不變,沒有協(xié)變也沒有不變,聲明時泛型是什么類型,賦值時泛型也必須是什么類型
示例代碼如下:
class Animal {}
class Dog extends Animal {}
static class MyList<X extends Animal> {}
public static void main(String[] args) {
MyList<Animal> m1 = new MyList<Animal>(); // 正確
MyList<Dog> m2 = new MyList<Dog>(); // 正確
MyList<Animal> m3 = new MyList<Dog>(); // 錯誤
MyList<Dog> m4 = new MyList<Animal>(); // 錯誤
}