老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業提供網站建設、域名注冊、服務器等服務

Java中數組協變和范型不變性的示例分析

這篇文章將為大家詳細講解有關Java中數組協變和范型不變性的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

為宿遷等地區用戶提供了全套網頁設計制作服務,及宿遷網站建設行業解決方案。主營業務為網站建設、網站設計、宿遷網站設計,以傳統方式定制建設網站,并提供域名空間備案等一條龍服務,秉承以專業、用心的態度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

一、協變、不變、逆變

假設,我為一家餐館寫了這樣一段代碼

class Soup {
 public void add(T t) {}
}

class Vegetable { }

class Carrot extends Vegetable { }

有一個范型類Soup,表示用食材T做的湯,它的方法add(T t)表示向湯中添加食材T。類Vegetable表示蔬菜,類Carrot表示胡蘿卜。當然,Carrot是Vegetable的子類。

那么問題來了,Soup和Soup之間是什么關系呢?

第一反應,Soup應該是Soup的子類,因為胡蘿卜湯顯然是一種蔬菜湯。如果真是這樣,那就看看下面的代碼。其中Tomato表示西紅柿,是Vegetable的另一個子類

Soup soup = new Soup();
soup.add(new Tomato());

第一句沒問題,Soup是Soup的子類,所以可以將Soup的實例賦給變量soup。第二句也沒問題,因為soup聲明為Soup類型,它的add方法接收一個Vegetable類型的參數,而Tomato是Vegetable,類型正確。

但是,兩句放在一起卻有了問題。soup的實際類型是Soup,而我們給它的add方法傳遞了一個Tomato的實例!換言之,我們在用西紅柿做胡蘿卜湯,肯定做不出來。所以,把Soup視為Soup的子類在邏輯上雖然是通順的,在使用過程中卻是有缺陷的。

那么,Soup和Soup究竟應該是什么關系呢?不同的語言有不同的理解和實現。總結起來,有三種情況。

(1)如果Soup是Soup的子類,則稱泛型Soup是協變的

(2)如果Soup和Soup是無關的兩個類,則稱泛型Soup是不變的

(3)如果Soup是Soup的父類,則稱泛型Soup是逆變的。(不過逆變不常見)

理解了協變、不變和逆變的概念,再看Java的實現。Java的一般泛型是不變的,也就是說Soup和Soup是毫無關系的兩個類,不能將一個類的實例賦值給另一個類的變量。所以,上面那段用西紅柿做胡蘿卜湯的代碼,其實根本無法通過編譯。

二、數組協變

Java中,數組是基本類型,不是泛型,不存在Array這樣的東西。但它和泛型很像,都是用另一個類型構建的類型。所以,數組也是要考慮變性的。

與泛型的不變性不同,Java的數組是協變的。也就是說,Carrot[]是Vegetable[]的子類。而上一節中的例子已經表明,協變有時會引發問題。比如下面這段代碼

Vegetable[] vegetables = new Carrot[10];
vegetables[0] = new Tomato(); // 運行期錯誤

因為數組是協變的,編譯器允許把Carrot[10]賦值給Vegetable[]類型的變量,所以這段代碼可以順利通過編譯。只有在運行期,JVM真的試圖往一堆胡蘿卜中插入一個西紅柿的時候,才發現大事不好。所以,上面的代碼在運行期會拋出一個java.lang.ArrayStoreException類型的異常。

數組協變性,是Java的著名歷史包袱之一。使用數組時,千萬要小心!

如果把例子中的數組替換為List,情況就不同了。就像這樣

ArrayList vegetables = new ArrayList(); // 編譯期錯誤
vegetables.add(new Tomato());

ArrayList是一個泛型類,它是不變的。所以,ArrayList和ArrayList之間并無繼承關系,這段代碼在編譯期就會報錯。

兩段代碼雖然都會報錯,但通常情況下,編譯期錯誤總比運行期錯誤好處理一些。

三、當泛型也想要協變、逆變

泛型是不變的,但某些場景里我們還是希望它能協變起來。比如,有一個天天喝蔬菜湯減肥的小姐姐

class Girl {
 public void drink(Soup soup) {}
}

我們希望drink方法可以接受各種不同的蔬菜湯,包括Soup和Soup。但受到不變性的限制,它們無法作為drink的參數。

要實現這一點,應該采用一種類似于協變性的寫法

public void drink(Soup soup) {}

意思是,參數soup的類型是泛型類Soup,而T是Vegetable的子類(也包括Vegetable自己)。這時,小姐姐終于可以愉快地喝上胡蘿卜湯和西紅柿湯了。

但是,這種方法有一個限制。編譯器只知道泛型參數是Vegetable的子類,卻不知道它具體是什么。所以,所有非null的泛型類型參數均被視為不安全的。說起來很拗口,其實很簡單。直接上代碼

public void drink(Soup soup) {
 soup.add(new Tomato()); // 錯誤
 soup.add(null); // 正確
}

方法內的第一句會在編譯期報錯。因為編譯器只知道add方法的參數是Vegetable的子類,卻不知道它具體是Carrot、Tomato、或者其他的什么類型。這時,傳遞一個具體類型的實例一律被視為不安全的。即使soup真的是Soup類型也不行,因為soup的具體類型信息是在運行期才能知道的,編譯期并不知道。

但是方法內的第二句是正確的。因為參數是null,它可以是任何合法的類型。編譯器認為它是安全的。

同樣,也有一種類似于逆變的方法

public void drink(Soup soup) {}

這時,Soup中的T必須是Vegetable的父類。

這種情況就不存在上面的限制了,下面的代碼毫無問題

public void drink(Soup soup) {
 soup.add(new Tomato());
}

Tomato是Vegetable的子類,自然也是Vegetable父類的子類。所以,編譯期就可以確定類型是安全的。

關于“Java中數組協變和范型不變性的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。


分享題目:Java中數組協變和范型不變性的示例分析
文章轉載:http://www.xueling.net.cn/article/geecoi.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: 午夜无遮挡男女啪啪免费软件 | 成人午夜亚洲精品无码55 | 三年片中国在线观看免费大全 | freesexvideos性少妇kant | 成人福利一区 | 成人一区在线视频 | 亚洲精品国产高清 | 成人久久色 | 欧洲成人在线视频 | 69视频播放 | 国产美女裸体无遮挡免费视频 | 伊人大杳焦在久久综合网 | 97热这里只有精品国产 | 在线观看日本精品 | 免费的又色又爽又黄的视频本 | 亚洲国产精品无码久久久高潮 | 老师洗澡让我吃她胸视频 | 日本免费www | 国产精品久久久久久久白皙女 | 色影天堂 | 精品影视一区二区 | 黄网站色视频免费大全 | 亚洲精品在线a | 亚洲欧美成人综合久久久 | 久久综合热 | 日韩在线三区 | 成人nv在线观看 | 国产一区视频在线 | 人妻丰满熟妇AV无码区乱 | 中文字幕无码日韩专区免费 | 武侠欧美另类人妻 | 91久久久爱一区二区三区 | 国产chinesehdxxxx三p| 久久夜夜夜 | 欧美日韩综合一区二区 | 秋霞午夜一区二区三区视频 | 一区二区三区免费 | 鲁一鲁AV2019在线 | 日本高清有码视频 | 91av视频在线观看免费 | 亚洲成A人片在线观看国产 亚洲国产一区自拍 |