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類型。
來自:http://my.oschina.net/roll1987/blog/527547
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!