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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java中super()_Java 泛型中 extends 和 super 的区别是什么?

發布時間:2025/3/21 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中super()_Java 泛型中 extends 和 super 的区别是什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

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

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

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

使用泛型的過程中,經常出現一種很別扭的情況。比如按照題主的例子,我們有 Fruit 類,和它的派生類 Apple 類。

class Fruit {} class Apple extends Fruit {}

然后有一個最簡單的容器:Plate 類。盤子里可以放一個泛型的“東西”。我們可以對這個東西做最簡單的“放”和“取”的動作: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;} }

現在我定義一個“水果盤子”,邏輯上水果盤子當然可以裝蘋果。

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

但實際上 Java 編譯器不允許這個操作。會報錯,“裝蘋果的盤子”無法轉換成“裝水果的盤子”。

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

所以我的尷尬癥就犯了。實際上,編譯器腦袋里認定的邏輯是這樣的:

蘋果 IS-A 水果

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

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

為了讓泛型用起來更舒服,Sun 的大腦袋們就想出了 <? extends T> 和 <? super T> 的辦法,來讓”水果盤子“和”蘋果盤子“之間發生關系。

什么是上界?

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

Plate<?extends Fruit>

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

//Lev 1classFood{}//Lev 2classFruitextendsFood{}classMeatextendsFood{}//Lev 3 classAppleextendsFruit{} classBananaextendsFruit{} classPorkextendsMeat{} classBeefextendsMeat{}//Lev 4 classRedAppleextendsApple{} classGreenAppleextendsApple{}

在這個體系中,下界通配符 Plate<?extends Fruit> 覆蓋下圖中藍色的區域。

什么是下界?

相對應的,“下界通配符(Lower Bounds Wildcards)”:

1Plate<? super Fruit>

表達的就是相反的概念:一個能放水果以及一切是水果基類的盤子。Plate<?super Fruit> 是 Plate<Fruit> 的基類,但不是 Plate<Apple> 的基類。對應剛才那個例子,Plate<?super Fruit> 覆蓋下圖中紅色的區域。

上下界通配符的副作用

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

還是以剛才的 Plate 為例。我們可以對盤子做兩件事,往盤子里 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;} }

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

<? extends Fruit> 會使往盤子里放東西的 set() 方法失效。但取東西 get() 方法還有效。比如下面例子里兩個 set() 方法,插入 Apple 和 Fruit 都報錯。

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

原因是編譯器只知道容器內是 Fruit 或者它的派生類,但具體是什么類型不知道。可能是 Fruit?可能是 Apple?也可能是 Banana,RedApple,GreenApple?編譯器在看到后面用 Plate 賦值以后,盤子里沒有被標上有“蘋果”。而是標上一個占位符:CAP#1,來表示捕獲一個 Fruit 或 Fruit 的子類,具體是什么類不知道,代號 CAP#1。然后無論是想往里插入 Apple 或者 Meat 或者 Fruit 編譯器都不知道能不能和這個 CAP#1 匹配,所以就都不允許。

所以通配符 <?> 和類型參數的區別就在于,對編譯器來說所有的 T 都代表同一種類型。比如下面這個泛型方法里,三個 T 都指代同一個類型,要么都是 String,要么都是 Integer。

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

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

所以題主問題里的錯誤就在這里,Plate<?extends Fruit> 里什么都放不進去。

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

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

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

因為下界規定了元素的最小粒度的下限,實際上是放松了容器元素的類型控制。既然元素是 Fruit 的基類,那往里存粒度比 Fruit 小的都可以。但往外讀取元素就費勁了,只有所有類的基類 Object 對象才能裝下。但這樣的話,元素的類型信息就全部丟失。

PECS 原則

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

  • 頻繁往外讀取內容的,適合用上界 Extends。
  • 經常往里插入的,適合用下界 Super。

總結

以上是生活随笔為你收集整理的java中super()_Java 泛型中 extends 和 super 的区别是什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。