重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
這篇文章將為大家詳細講解有關Java中數組協變和范型不變性的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
為宿遷等地區用戶提供了全套網頁設計制作服務,及宿遷網站建設行業解決方案。主營業務為網站建設、網站設計、宿遷網站設計,以傳統方式定制建設網站,并提供域名空間備案等一條龍服務,秉承以專業、用心的態度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
一、協變、不變、逆變
假設,我為一家餐館寫了這樣一段代碼
class Soup{ public void add(T t) {} } class Vegetable { } class Carrot extends Vegetable { }
有一個范型類Soup
那么問題來了,Soup
第一反應,Soup
Soupsoup = new Soup (); soup.add(new Tomato());
第一句沒問題,Soup
但是,兩句放在一起卻有了問題。soup的實際類型是Soup
那么,Soup
(1)如果Soup
(2)如果Soup
(3)如果Soup
理解了協變、不變和逆變的概念,再看Java的實現。Java的一般泛型是不變的,也就是說Soup
二、數組協變
Java中,數組是基本類型,不是泛型,不存在Array
與泛型的不變性不同,Java的數組是協變的。也就是說,Carrot[]是Vegetable[]的子類。而上一節中的例子已經表明,協變有時會引發問題。比如下面這段代碼
Vegetable[] vegetables = new Carrot[10]; vegetables[0] = new Tomato(); // 運行期錯誤
因為數組是協變的,編譯器允許把Carrot[10]賦值給Vegetable[]類型的變量,所以這段代碼可以順利通過編譯。只有在運行期,JVM真的試圖往一堆胡蘿卜中插入一個西紅柿的時候,才發現大事不好。所以,上面的代碼在運行期會拋出一個java.lang.ArrayStoreException類型的異常。
數組協變性,是Java的著名歷史包袱之一。使用數組時,千萬要小心!
如果把例子中的數組替換為List,情況就不同了。就像這樣
ArrayListvegetables = new ArrayList (); // 編譯期錯誤 vegetables.add(new Tomato());
ArrayList是一個泛型類,它是不變的。所以,ArrayList
兩段代碼雖然都會報錯,但通常情況下,編譯期錯誤總比運行期錯誤好處理一些。
三、當泛型也想要協變、逆變
泛型是不變的,但某些場景里我們還是希望它能協變起來。比如,有一個天天喝蔬菜湯減肥的小姐姐
class Girl { public void drink(Soupsoup) {} }
我們希望drink方法可以接受各種不同的蔬菜湯,包括Soup
要實現這一點,應該采用一種類似于協變性的寫法
public void drink(Soup extends Vegetable> soup) {}
意思是,參數soup的類型是泛型類Soup
但是,這種方法有一個限制。編譯器只知道泛型參數是Vegetable的子類,卻不知道它具體是什么。所以,所有非null的泛型類型參數均被視為不安全的。說起來很拗口,其實很簡單。直接上代碼
public void drink(Soup extends Vegetable> soup) { soup.add(new Tomato()); // 錯誤 soup.add(null); // 正確 }
方法內的第一句會在編譯期報錯。因為編譯器只知道add方法的參數是Vegetable的子類,卻不知道它具體是Carrot、Tomato、或者其他的什么類型。這時,傳遞一個具體類型的實例一律被視為不安全的。即使soup真的是Soup
但是方法內的第二句是正確的。因為參數是null,它可以是任何合法的類型。編譯器認為它是安全的。
同樣,也有一種類似于逆變的方法
public void drink(Soup super Vegetable> soup) {}
這時,Soup
這種情況就不存在上面的限制了,下面的代碼毫無問題
public void drink(Soup super Vegetable> soup) { soup.add(new Tomato()); }
Tomato是Vegetable的子類,自然也是Vegetable父類的子類。所以,編譯期就可以確定類型是安全的。
關于“Java中數組協變和范型不變性的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。