最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java泛型extends及super區(qū)別實(shí)例解析

 更新時(shí)間:2020年08月07日 15:02:31   作者:小甜瓜安東泥  
這篇文章主要介紹了Java泛型extends及super區(qū)別實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

<? extends T>和<? super T>是Java泛型中的“通配符(Wildcards)”和“邊界(Bounds)”的概念。

  • <? extends T>:是指“上界通配符(Upper Bounds Wildcards)”
  • <? super T>:是指“下界通配符(Lower Bounds Wildcards)”

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

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

class Fruit {}
class Apple extends Fruit {}

然后有一個(gè)最簡(jiǎn)單的容器:Plate類。盤(pán)子里可以放一個(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è)“水果盤(pán)子”,邏輯上水果盤(pán)子當(dāng)然可以裝蘋(píng)果:

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

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

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

所以問(wèn)題就來(lái)了。實(shí)際上,編譯器腦袋里認(rèn)定的邏輯是這樣的:

  • 蘋(píng)果 IS-A 水果
  • 裝蘋(píng)果的盤(pán)子 NOT-IS-A 裝水果的盤(pán)子

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

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

什么是上界?

下面代碼就是“上界通配符(Upper Bounds Wildcards)”:

Plate<? extends Fruit>

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

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

如果把Fruit和Apple的例子再擴(kuò)展一下,食物分成水果和肉類,水果有蘋(píng)果和香蕉,肉類有豬肉和牛肉,蘋(píng)果還有兩種青蘋(píng)果和紅蘋(píng)果。

//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ū)域。

什么是下界?

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

Plate<? super Fruit>

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

上下界通配符的副作用

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

還是以剛才的Plate為例。我們可以對(duì)盤(pán)子做兩件事,往盤(pán)子里set()新東西,以及從盤(pán)子里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;}
}

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

<? extends Fruit>會(huì)使往盤(pán)子里放東西的set( )方法失效。但取東西get( )方法還有效。比如下面例子里兩個(gè)set()方法,插入Apple和Fruit都報(bào)錯(cuò):

Plate<? extends Fruit> pfruit=new Plate<Apple>(new Apple());
  
//不能存入任何元素
pfruit.set(new Fruit());  //Error
pfruit.set(new Apple());  //Error

//讀取出來(lái)的東西只能存放在Fruit或它的基類里。
Fruit newFruit1=pfruit.get();
Object newFruit2=pfruit.get();
Apple newFruit3=pfruit.get();  //Error

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

所以通配符<?>和類型參數(shù)的區(qū)別就在于:

對(duì)編譯器來(lái)說(shuō)所有的T都代表同一種類型。比如下面這個(gè)泛型方法里,三個(gè)T都指代同一個(gè)類型,要么都是String,要么都是Integer。

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

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

因此為了安全起見(jiàn),Plate<? extends Fruit>里什么都放不進(jìn)去。

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

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

Plate<? super Fruit> pfruit=new Plate<Fruit>(new Fruit());

//存入元素正常
pfruit.set(new Fruit());
pfruit.set(new Apple());

//讀取出來(lái)的東西只能存放在Object類里。
Apple newFruit3=pfruit.get();  //Error
Fruit newFruit1=pfruit.get();  //Error
Object newFruit2=pfruit.get();

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

PECS原則

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

  • 頻繁往外讀取內(nèi)容的,適合用上界Extends。
  • 經(jīng)常往里插入的,適合用下界Super。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)連接kubernates集群的兩種方式詳解

    Java實(shí)現(xiàn)連接kubernates集群的兩種方式詳解

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)連接kubernates集群的兩種方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • spring 和 spring boot 中的屬性配置方式

    spring 和 spring boot 中的屬性配置方式

    這篇文章主要介紹了spring 和 spring boot 中的屬性配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java多線程中的互斥鎖解析

    Java多線程中的互斥鎖解析

    這篇文章主要介紹了Java多線程中的互斥鎖解析,Java語(yǔ)言中,引入了對(duì)象互斥鎖的概念,來(lái)保證共享數(shù)據(jù)操作的完整性,每個(gè)對(duì)象都對(duì)應(yīng)于一個(gè)可稱為互斥鎖的標(biāo)記,這個(gè)標(biāo)記用來(lái)保證在任一時(shí)刻,只能有一個(gè)線程訪問(wèn)該對(duì)象,需要的朋友可以參考下
    2023-09-09
  • JAVA實(shí)現(xiàn)301永久重定向方法

    JAVA實(shí)現(xiàn)301永久重定向方法

    本篇文章給大家總結(jié)了JAVA中實(shí)現(xiàn)永久重定向的方法以及詳細(xì)代碼,對(duì)此有需要的朋友可以參考學(xué)習(xí)下。
    2018-04-04
  • Java Applet查找素?cái)?shù)小程序代碼實(shí)例

    Java Applet查找素?cái)?shù)小程序代碼實(shí)例

    這篇文章主要介紹了Java Applet查找素?cái)?shù)小程序代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 詳解springboot中mybatis注解形式

    詳解springboot中mybatis注解形式

    在本文中小編給大家分享了關(guān)于springboot中mybatis注解形式的介紹,有興趣的可以跟著學(xué)習(xí)下。
    2018-10-10
  • smslib發(fā)短信實(shí)例代碼(電腦發(fā)短信)

    smslib發(fā)短信實(shí)例代碼(電腦發(fā)短信)

    smslib發(fā)短信實(shí)例,大家可以參考使用開(kāi)發(fā)自己的程序
    2013-12-12
  • Java遍歷集合的三種方式

    Java遍歷集合的三種方式

    本文主要對(duì)于遍歷集合獲取其對(duì)象,總結(jié)的三種簡(jiǎn)單的方式進(jìn)行介紹,文章中舉了兩個(gè)案例進(jìn)行對(duì)比,具有很好的參考價(jià)值,下面就跟小編一起來(lái)看下吧
    2016-12-12
  • Java編程ssh整合常見(jiàn)錯(cuò)誤解析

    Java編程ssh整合常見(jiàn)錯(cuò)誤解析

    這篇文章主要介紹了Java編程ssh整合常見(jiàn)錯(cuò)誤解析,如果有什么不足之處,歡迎留言補(bǔ)充。
    2017-10-10
  • Java集合操作之List接口及其實(shí)現(xiàn)方法詳解

    Java集合操作之List接口及其實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Java集合操作之List接口及其實(shí)現(xiàn)方法,詳細(xì)分析了Java集合操作中List接口原理、功能、用法及操作注意事項(xiàng),需要的朋友可以參考下
    2015-07-07

最新評(píng)論

梅河口市| 白城市| 西城区| 旬阳县| 玉环县| 江永县| 遂平县| 阆中市| 拉孜县| 上杭县| 鄢陵县| 乌鲁木齐县| 英吉沙县| 武川县| 宿迁市| 新绛县| 鄢陵县| 会泽县| 梓潼县| 依安县| 乌兰察布市| 新源县| 大悟县| 伊吾县| 体育| 榆林市| 湖北省| 松阳县| 冷水江市| 南岸区| 柯坪县| 广宁县| 昭苏县| 法库县| 洛川县| 新安县| 阳春市| 上犹县| 辉县市| 年辖:市辖区| 崇州市|