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類型。
PS:透過限制參數類型:
public void func(List<? extends Base> list) { }

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

2025年的前4個JavaScript框架:React,Angular,Vue,Svelte

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?

Spring Boot Snakeyaml 2.0 CVE-2022-1471問題已修復

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?

如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?
