日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java 泛型 super extends 边界

發(fā)布時(shí)間:2025/3/21 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 泛型 super extends 边界 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 為什么要用通配符和邊界?

使用泛型的過(guò)程中,經(jīng)常出現(xiàn)一種很別扭的情況 比如我們有Fruit類,和它的派生類Apple

class Fruit {} class Apple extends Fruit {}

然后有一個(gè)最簡(jiǎn)單的容器:Plate類 盤子里可以放一個(gè)泛型的“東西” 我們可以對(duì)這個(gè)東西做最簡(jiǎn)單的“放”和“取”的動(dòng)作:set( )和get( )方法

class Plate<T>{private T item;public Plate(T t){item=t;}public void set(T t){item=t;}public T get(){return item;} }

現(xiàn)定義一個(gè)“水果盤”,邏輯上水果盤當(dāng)然可以裝蘋果

Plate<Fruit> p = new Plate<Apple>(new Apple());

但實(shí)際上Java編譯器不允許這個(gè)操作。會(huì)報(bào)錯(cuò),“裝蘋果的盤子”無(wú)法轉(zhuǎn)換成“裝水果的盤子”。

error: incompatible types: Plate<Apple> cannot be converted to Plate<Fruit>

實(shí)際上,編譯器認(rèn)定的邏輯是這樣的:

  • 蘋果 IS-A 水果
  • 裝蘋果的盤子 NOT-IS-A 裝水果的盤子

所以,就算容器里裝的東西之間有繼承關(guān)系,但容器之間是沒(méi)有繼承關(guān)系 所以我們不可以把Plate<Apple>的引用傳遞給Plate<Fruit>

為了讓泛型用起來(lái)更舒服,Sun的大師們就想出了<? extends T>和<? super T>的辦法,來(lái)讓”水果盤子“和”蘋果盤子“之間發(fā)生正當(dāng)關(guān)系

2 上界

下面就是上界通配符(Upper Bounds Wildcards)

Plate<? extends Fruit>

一個(gè)能放水果以及一切是水果派生類的盤子 再直白點(diǎn)就是:啥水果都能放的盤子 這和我們?nèi)祟惖倪壿嬀捅容^接近了 Plate<? extends Fruit>和Plate<Apple>最大的區(qū)別就是:Plate<? extends Fruit>是Plate<Fruit>及Plate<Apple>的基類 直接的好處就是,我們可以用“蘋果盤”給“水果盤”賦值了

Plate<? extends Fruit> p = new Plate<Apple>(new Apple());

再擴(kuò)展一下,食物分成水果和肉類,水果有蘋果和香蕉,肉類有豬肉和牛肉,蘋果還有兩種青蘋果和紅蘋果

//Lev 1 class Food{}//Lev 2 class Fruit extends Food{} class Meat extends Food{}//Lev 3 class Apple extends Fruit{} class Banana extends Fruit{} class Pork extends Meat{} class Beef extends Meat{}//Lev 4 class RedApple extends Apple{} class GreenApple extends Apple{}

在這個(gè)體系中,上界通配符Plate<? extends Fruit>覆蓋下圖中藍(lán)色的區(qū)域

3 下界

相對(duì)應(yīng)的下界通配符(Lower Bounds Wildcards)

Plate<? super Fruit>

表達(dá)的就是相反的概念:一個(gè)能放水果以及一切是水果基類的盤子 Plate<? super Fruit>是Plate<Fruit>的基類,但不是Plate<Apple>的基類 對(duì)應(yīng)剛才那個(gè)例子,Plate<? super Fruit>覆蓋下圖中紅色的區(qū)域。

4 上下界通配符的副作用

邊界讓Java不同泛型之間的轉(zhuǎn)換更容易了。但不要忘記,這樣的轉(zhuǎn)換也有一定的副作用。那就是容器的部分功能可能失效。

還是以剛才的Plate為例。我們可以對(duì)盤子做兩件事,往盤子里set( )新東西,以及從盤子里get( )東西

class Plate<T>{private T item;public Plate(T t){item=t;}public void set(T t){item=t;}public T get(){return item;} }

4.1 上界<? extends T>不能往里存,只能往外取

<? extends Fruit>會(huì)使往盤子里放東西的set( )方法失效 但取東西get( )方法還有效

比如下面例子里兩個(gè)set()方法,插入Apple和Fruit都報(bào)錯(cuò)

Plate<? extends Fruit> p = new Plate<Apple>(new Apple());//不能存入任何元素 p.set(new Fruit()); //Error p.set(new Apple()); //Error//讀取出來(lái)的東西只能存放在Fruit或它的基類里。 Fruit newFruit1=p.get(); Object newFruit2=p.get(); Apple newFruit3=p.get(); //Error

編譯器只知道容器內(nèi)是Fruit或者它的派生類,但具體是什么類型不知道 可能是Fruit?可能是Apple?也可能是Banana,RedApple,GreenApple?編譯器在看到后面用Plate<Apple>賦值以后,盤子里沒(méi)有被標(biāo)上有“蘋果”。而是標(biāo)上一個(gè)占位符:capture#1,來(lái)表示捕獲一個(gè)Fruit或Fruit的子類,具體是什么類不知道,代號(hào)capture#1 然后無(wú)論是想往里插入Apple或者M(jìn)eat或者Fruit編譯器都不知道能不能和這個(gè)capture#1匹配,所以就都不允許

所以通配符<?>和類型參數(shù)<T>的區(qū)別就在于,對(duì)編譯器來(lái)說(shuō)所有的T都代表同一種類型 比如下面這個(gè)泛型方法里,三個(gè)T都指代同一個(gè)類型,要么都是String,要么都是Integer...

public <T> List<T> fill(T... t);

但通配符<?>沒(méi)有這種約束,Plate<?>單純的就表示:盤子里放了一個(gè)東西,是什么我不知道

4.2 下界<? super T>不影響往里存,但往外取只能放在Object對(duì)象里

使用下界<? super Fruit>會(huì)使從盤子里取東西的get( )方法部分失效,只能存放到Object對(duì)象里。set( )方法正常。

Plate<? super Fruit> p=new Plate<Fruit>(new Fruit());//存入元素正常 p.set(new Fruit()); p.set(new Apple());//讀取出來(lái)的東西只能存放在Object類里。 Apple newFruit3=p.get(); //Error Fruit newFruit1=p.get(); //Error Object newFruit2=p.get();

因?yàn)橄陆缫?guī)定了元素的最小粒度的下限,實(shí)際上是放松了容器元素的類型控制 既然元素是Fruit的基類,那往里存粒度比Fruit小的都可以。但往外讀取元素就費(fèi)勁了,只有所有類的基類Object對(duì)象才能裝下。但這樣的話,元素的類型信息就全部丟失。

5 PECS原則

最后看一下什么是PECS(Producer Extends Consumer Super)原則,已經(jīng)很好理解了

  • 頻繁往外讀取內(nèi)容的,適合用上界Extends
  • 經(jīng)常往里插入的,適合用下界Super
  • from:?https://cloud.tencent.com/developer/article/1353548?

    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的Java 泛型 super extends 边界的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。