Java 中泛型的協變
在工作中遇到一個問題,用程式碼描述如下:
package test; import java.util.LinkedList; import java.util.List; public class ListTest { public void func(List<Base> list) { } public static void main(String args[]) { ListTest lt = new ListTest(); List<Derived> list = new LinkedList<Derived>(); lt.func(list); // 編譯報錯 } } class Base { } class Derived extends Base { }
這裡需要寫一個函式func,能夠以Base的list作為引數。原以為傳一個Derived的list也可以,因為Derived是Base的派生類,那Derived的list也應當是Base的list的派生類,結果編譯器報錯。
究其原因,在網上查了一些資料:Java的泛型並非協變的。
泛型的協變和逆變都是術語,前者指能夠使用比原始指定的派生型別的派生程度更小(不太具體的)的型別,後者指能夠使用比原始指定的派生型別的派生程度更大(更具體的)的型別。
例如C#中的泛型就是支援協變的:
IEnumerable<Derived> d = new List<Derived>(); IEnumerable<Base> b = d;
但是Java的泛型卻是不支援協變的,類似上面的程式碼在Java中無法通過編譯。
但有趣的是,Java中的數值卻是支援協變,例如:
Integer[] intArray = new Integer[10]; Number[] numberArray = intArray;
總結:Java的泛型不支援協變,更多的是從型別安全的角度考慮。這種設計不是一定必須的,例如C#就沒有采用這種設計。只能說Java的設計者在易用性和型別安全之間做了取捨。
最後回到最初的那個問題,要實現一個那樣的方法func,可以修改為:
public void func(List list) { }
或者採用引數化型別:
public <T> void func(List<T> list) { }
但是這樣也有問題,會模糊了func的引數型別。更好的辦法是不改func,在傳參時就傳一個Base型別的List,這就要求在將元素加入這個List時就要轉型成Base型別。
相關文章
- .NET泛型中的協變與逆變泛型
- 泛型協變與抗變(二)泛型
- C# 泛型的協變和逆變C#泛型
- Java中的泛型Java泛型
- C#泛型的逆變協變(個人理解)C#泛型
- 泛型、陣列列表與協變泛型陣列
- Java中的泛型方法Java泛型
- Java 中泛型的全面解析Java泛型
- 深入解析Java中的泛型Java泛型
- Java中建立泛型型別的例項Java泛型型別
- Java 中的泛型方法及 FunctionJava泛型Function
- Java 泛型中易混淆的地方Java泛型
- Java 泛型中的萬用字元Java泛型字元
- Java中泛型的詳細解析,深入分析泛型的使用方式Java泛型
- Java中的逆變與協變Java
- 【java】【泛型】泛型geneticJava泛型
- java泛型之泛型方法。Java泛型
- Java 中的泛型 集合(List,Set) MapJava泛型
- Java泛型知識點:泛型類、泛型介面和泛型方法Java泛型
- java泛型之泛型陣列。Java泛型陣列
- Java 泛型Java泛型
- Java泛型Java泛型
- java中泛型之型別萬用字元(?)Java泛型型別字元
- 教你如何攻克Kotlin中泛型型變的難點(上篇)Kotlin泛型
- 教你如何攻克Kotlin中泛型型變的難點(下篇)Kotlin泛型
- Java 泛型原理Java泛型
- Java+泛型Java泛型
- java泛型一二Java泛型
- Java(7)泛型Java泛型
- Java-泛型Java泛型
- java泛型剖析Java泛型
- JAVA泛型類Java泛型
- java 之泛型與可變引數詳解Java泛型
- 我理解的 Java 泛型Java泛型
- Java™ 教程(泛型的限制)Java泛型
- Java的泛型機制Java泛型
- Java泛型的那些事Java泛型
- Java泛型中<?> 和 <? extends Object>的異同分析Java泛型Object