通配符的上下限與泛型方法

java零基礎入門-高級特性篇(七) 泛型? 下

本章閱讀有難度字逗,請謹慎閱讀鸠按,如有不適狈网,可以跳過宙搬。

本章繼續(xù)講解泛型的上下限和其他的知識點,由于概念的復雜性拓哺,這里繼續(xù)使用Book這個類來描述勇垛,使概念理解起來具備連續(xù)性。

泛型的通配符可以分為3種類型士鸥,無邊界通配符闲孤,設定上限的通配符,設定下限的通配符础淤。

上一章講解的<?>是無邊界通配符崭放,設定上限的通配符<? extends E>哨苛,設定下限的通配符<? super E>。

設定上限的通配符

首先來看一張圖币砂。有三個類建峭,數(shù)學書繼承教科書,教科書繼承書籍【龃荩現(xiàn)在定義一個List<? extend Book> books集合亿蒸,這是什么意思呢?<? extend Book>這個泛型表示通配符掌桩?匹配的類型只能是Book類型的子類边锁,Book類型是?類型的上限波岛,上限就是說這里茅坛?匹配的最高類型只能是Book了。

上限

看圖则拷,如果設置通配符上限<? extend Book>贡蓖,那么?可以是TextBook煌茬,也可以是MathBook斥铺,他們都是Book的子類。如果設置<? extend TextBook>坛善,這時候通配符晾蜘?的上限就是TextBook了,如果將Book類型作為通配類型眠屎,就會編譯報錯剔交,而TextBook的子類MathBook作為通配類型是可以的。如果設置<? extend MathBook>改衩,那么省容?只能是MathBook類型。

通配符上限

上例中主要看Student這個要讀書的可憐孩子燎字,readBook方法中設置了通配符的上限為Book,然后在主方法中設置的List泛型為MathBook阿宅,因為MathBook是Book的子類候衍,所以滿足通配符的條件,可以作為參數(shù)傳遞給readBook方法洒放。這里要注意的是蛉鹿,設置通配符上限的時候依然不可以使用add方法。為什么往湿?這里有點繞妖异,繞不過來就假設惋戏。

假設通配符?是MathBook他膳,那么參數(shù)就是List<MathBook>响逢,但是往List<MathBook>里面添加Book類型,這是不行的棕孙,因為Book是MathBook的父類舔亭,所以設置通配符上限也不可以使用add方法。

再來看循環(huán)蟀俊,在無邊界通配符的時候钦铺,要變量元素只能是Object類型,但是這里可以作為Book類型遍歷元素肢预,為什么矛洞?因為通配符?已經(jīng)設置了上限Book烫映,無論?是什么類型沼本,都是Book的子類,而子類是可以向上自動轉型的窑邦,如果參數(shù)是List<MathBook>擅威,依然可以使用Book類型來遍歷MathBook元素。

設定下限的通配符

再來看設定下限的通配符冈钦。定義List<? super Book> books郊丛;使用<? super Book>的形式設置通配符的下限,意思是通配符瞧筛?的類型只能是Book的父類厉熟,看圖

下限

設置<? super Book>以后,如果通配符较幌?類型為TextBook揍瑟,會編譯錯誤,因為TextBook不是Book的父類乍炉,而是子類绢片,MathBook是孫子,錯的更離譜了岛琼。如果設置<? super TextBook>底循,那么?是Book類型就是允許的槐瑞,因為Book是TextBook的父類熙涤,其他的請自行揣摩。

通配符下限

這里只需要修改Student類型,其他代碼可以保持不變祠挫。需要注意的是這里設置了下限是MathBook那槽,而傳入的參數(shù)恰好是List<MathBook>,所以這里是可以的等舔。如果將下限設置為TextBook骚灸,代碼就會報錯了,因為這里的參數(shù)只能是TextBook或者父類Book软瞎,傳入List<MathBook>就會發(fā)生編譯錯誤逢唤。

這里居然可以使用add方法了,為什么涤浇?假設通配符鳖藕?是Book,那么List<Book>是可以添加Book的子類MathBook類型的只锭。因為這里通配符不論是什么類型著恩,必須是MathBook的父類,所以在父類的List集合添加子類MathBook是完全可以的蜻展。

至于循環(huán)中又變成了Object喉誊,是因為這里無法確定父類是什么類型,無法保證父類都有getName()這個方法纵顾。因為Object是Book的父類伍茄,如果參數(shù)是List<Object>,那么就無法使用Book里的方法了施逾,所以只能當成Object來操作敷矫。

泛型方法

泛型方法?前面不是講了么汉额?請注意曹仗,泛型方法需要在定義方法的時候,就對方法中的泛型類型進行定義蠕搜。

非泛型方法

以上兩個方法不是泛型方法怎茫,原因就是真正的泛型方法需要在方法中定義。如何定義泛型方法妓灌?

修飾符? <泛型類型參數(shù)> 返回值? 方法名(){...}

請注意轨蛤,在方法的修飾符與返回值之間定義泛型類型參數(shù),這時候的方法才是一個泛型方法虫埂。泛型方法為什么要在定義方法的時候定義泛型俱萍?因為泛型是一個參數(shù),參數(shù)就有作用域告丢,定義在類上面的泛型作用域是整個類,定義在方法上的泛型,作用域是整個方法岖免。

泛型方法

先看左邊一張圖岳颇,如果在類上面指定了泛型,而又在類中定義了泛型方法颅湘,而且泛型方法中的泛型參數(shù)和類中的泛型參數(shù)一樣话侧,那么類上的泛型類型參數(shù)會被方法中的泛型參數(shù)覆蓋,程序也會出現(xiàn)警告闯参。

原因就在右圖瞻鹏,泛型類,是在實例化類的時候指明泛型的具體類型鹿寨,泛型方法新博,是在調(diào)用方法的時候指明泛型的具體類型。就算泛型方法定義的泛型類型參數(shù)與類定義的不同也是可以的脚草,因為方法自己定義了泛型參數(shù)赫悄,不需要類定義的泛型參數(shù)。在創(chuàng)建類對象的時候馏慨,具體定義的泛型類型可以和對象調(diào)用方法時埂淮,具體定義的泛型類型不同。比如Book在創(chuàng)建對象的時候使用的類型是Integer写隶,而調(diào)用sayTheBookName的時候傳遞的參數(shù)卻是String倔撞,這是完全可以的。如果定義了泛型方法慕趴,那么方法中的泛型可以看做是獨立于類定義的泛型而存在的痪蝇。所以如果定義泛型方法,建議方法中的泛型不要與類上定義的泛型類型相同秩贰。

然后霹俺,就算不使用泛型類,也是可以直接使用泛型方法的毒费。比如上例中丙唧,去掉Book<T>后面的泛型定義,將T改為String觅玻,程序也不會報錯想际,而且泛型方法可以正常被調(diào)用。

在使用泛型方法的時候有幾個地方需要注意:

1)自動類型推斷溪厘。比如book.sayTheBookName("教科書")胡本,這里程序會根據(jù)傳入的參數(shù)自動的將E推斷為String類型。

2)在定義方法的時候畸悬,不要因為類型可以自動推斷而定義相同的泛型類型參數(shù)侧甫。

相同的泛型參數(shù)

這樣定義泛型方法是沒有問題的,可以正確編譯,也可以正確運行披粟。但是不建議這樣做咒锻,因為根據(jù)傳入的參數(shù),第一個E會被推斷為String類型守屉,而第二個E被推斷為Integer類型惑艇,這樣會造成理解上的歧義。

3)如果直接將泛型類型參數(shù)定義為類型是不會報錯的拇泛,但是如果在集合類型的泛型中滨巴,將泛型類型定義為一樣的參數(shù),就真的會報錯了俺叭。

無法推斷

上面“教科書”和1很容易推斷出是字符串和Integer類型恭取,但是如果調(diào)用方法時將有泛型的集合作為參數(shù),并且方法里面定義的集合泛型參數(shù)還是相同的绪颖,這時候程序就無法進行自動推斷了秽荤。這里最好將泛型方法再多定義一個泛型參數(shù),保證不會出現(xiàn)歧義柠横,這樣程序才能正確的進行類型推斷窃款。

public <M,O> int getAllNum(List<M> mathBook,List<O> englishBook){...}

這樣就可以避免歧義,正確推斷類型了牍氛。

泛型通配符和泛型方法

希望講到這里你還沒有暈晨继。

那么我們繼續(xù)看下一個問題。前面說的泛型通配符搬俊?可以代替任何一個類型紊扬,T這種形式的泛型類型參數(shù)不是也可以代替任何一個類型嗎?他們有什么區(qū)別呢唉擂?

其實泛型方法和方法中使用通配符在某些情況下是可以相互替代的餐屎。

效果一樣

1)這是他們第一個相同的地方,他們都可以接收一個未知的類型

2)你可能會說玩祟,通配符可以設置上下限啊腹缩,不好意思,這個功能泛型方法也有

泛型方法的上下限

將上面的方法修改成通配符上限和泛型方法上限也沒有任何問題空扎。需要注意的是藏鹊,使用泛型方法的上下限時,需要在方法定義的時候設置上下限转锈,而不是在參數(shù)里面設置上下限盘寡。

不同的地方在于,當設置泛型通配符上下限的時候撮慨,會存在一個只能讀不能寫的情況竿痰,就是無法往集合添加元素脆粥,因為不能確定類型。但是使用泛型方法的時候菇曲,就可以對集合進行添加操作冠绢,因為調(diào)用泛型方法的時候,類型就已經(jīng)確定了常潮。所以如果需要對集合元素進行讀取之外的操作,可以使用泛型方法楷力。

再一個就是當多個泛型類型參數(shù)之間有依賴關系的時候喊式,可以使用泛型方法。

泛型的依賴

這里有2個對象萧朝,依賴對象和被依賴對象岔留,T extends B,T是依賴對象检柬,B是被依賴對象献联。如果依賴對象不確定,可以使用泛型通配符何址,但是如果被依賴對象不確定里逆,則不可以使用泛型通配符。

依賴對象不確定

依賴對象使用通配符沒有問題用爪,程序可以運行原押。因為通配符類型的上限就是B。

被依賴對象不確定

如果被依賴對象不確定偎血,則無法確定T類型的上限诸衔,導致程序編譯出錯。所以如果多個泛型類型之間有依賴關系颇玷,使用泛型方法會比較適合笨农。

泛型的擦除

泛型類型信息只在編譯的時候發(fā)揮作用,一旦被加載到虛擬機泛型信息會被全部丟棄帖渠。所以在編譯階段List<Book>和List<TextBook>可以看做兩個不同的類型谒亦,但是一旦加載到虛擬機,他們就是同樣的類型阿弃。泛型被丟了诊霹,那他是個什么類型?用專業(yè)的話說就是擦除到泛型的上限渣淳。比如沒有指定上限的時候脾还,擦除后的類型是Object,如果制定了類型的上限比如<? extends Book>入愧,那么擦除后的類型就是Book鄙漏。關于泛型的擦除會涉及到反射知識嗤谚,這里老規(guī)矩,先混臉熟怔蚌。

泛型知識一般多用于對代碼進行高層次抽象巩步,比如編寫一些工具方法,框架桦踊,比如在集合框架中就有大量的泛型使用椅野,所以有一定的難度,初學者掌握集合的泛型使用即可籍胯。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竟闪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子杖狼,更是在濱河造成了極大的恐慌炼蛤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶涩,死亡現(xiàn)場離奇詭異理朋,居然都是意外死亡,警方通過查閱死者的電腦和手機绿聘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門嗽上,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斜友,你說我怎么就攤上這事炸裆。” “怎么了鲜屏?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵烹看,是天一觀的道長。 經(jīng)常有香客問我洛史,道長惯殊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任也殖,我火速辦了婚禮土思,結果婚禮上,老公的妹妹穿的比我還像新娘忆嗜。我一直安慰自己己儒,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布捆毫。 她就那樣靜靜地躺著闪湾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绩卤。 梳的紋絲不亂的頭發(fā)上途样,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天江醇,我揣著相機與錄音,去河邊找鬼何暇。 笑死陶夜,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的裆站。 我是一名探鬼主播条辟,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宏胯!你這毒婦竟也來了捂贿?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤胳嘲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扣草,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體了牛,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年辰妙,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹰祸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡密浑,死狀恐怖蛙婴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尔破,我是刑警寧澤街图,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站懒构,受9級特大地震影響餐济,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胆剧,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一絮姆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秩霍,春花似錦篙悯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至匿垄,卻和暖如春移宅,著一層夾襖步出監(jiān)牢的瞬間归粉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工漏峰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留糠悼,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓浅乔,卻偏偏與公主長得像倔喂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子靖苇,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容