首頁 > Java > java教程 > 主體

Java中extends T和super T是什麼

PHPz
發布: 2023-05-09 11:19:17
轉載
1302 人瀏覽過

? 通配符型別

  • 表示型別的上界,表示參數化型別的可能是T 或是T的子類別;

  • # 表示類型下界(Java Core中叫超型別限定),表示參數化型別是此型別的超型別(父型別),直到Object;

上界不能往裡面存,只能往外取

比如,我們現在定義:List首先你很容易誤解它為繼承於T的所有類別的集合,你可能認為,你定義的這個List可以用來put任何T的子類,那麼我們看下面的程式碼:

import java.util.LinkedList;
import java.util.List;

public class test {
    public static void main(String[] args) {
        List<? extends Father> list = new LinkedList<>();
        list.add(new Son());
    }
}
class Human{
}
class Father extends Human{
}
class Son extends Father{
}
class LeiFeng extends Father {
}
登入後複製

list.add(new Son());這行會報錯:The method put(Son) is undefined for the type List

List 表示“具有任何從Son繼承類型的列表” ,編譯器無法確定List所持有的類型,所以無法安全的向其中新增物件。可以加null,因為null 可以表示任何類型。所以List 的add 方法不能加入任何有意義的元素,但可以接受現有的子型別List 賦值。

你也許試圖這樣做:

List<? extends Father> list = new LinkedList<Son>();
list.add(new Son());
登入後複製

即使你指明了為Son類型,也不能用add方法添加一個Son物件。

list中為什麼不能加入Father類別和Father類別的子類別呢,我們來分析下。

List表示上限是Father,下面這樣的賦值都是合法的

   List<? extends Father> list1 = new ArrayList<Father>();
   List<? extends Father> list2 = new ArrayList<Son>();
   List<? extends Father> list3 = new ArrayList<LeiFeng>();
登入後複製

如果List支持add方法的話:

  • list1可以add Father和所有Father的子類別;

  • #list2可以add Son和所有Son的子類別;

  • list3可以add LeiFeng和所有LeiFeng的子類別。

下面程式碼是編譯不通過的:

list1.add(new Father());//error
list1.add(new Son());//error
登入後複製

原因是編譯器只知道容器內是Father或它的衍生類,但具體是什麼型別不知道。可能是Father?可能是Son?也可能是LeiFeng,XiaoMing?編譯器看到後面用Father賦值以後,集合裡並沒有限定參數型別是「Father「。而是標上一個佔位符:CAP#1,來表示捕獲一個Father或Father的子類,具體是什麼類不知道,代號CAP#1。然後無論是想往裡面插入Son或LeiFeng或Father編譯器都不知道能不能跟這個CAP#1匹配,所以就都不允許。

所以通配符和型別參數的差別就在於,對編譯器來說所有的T都代表同一種型別。例如下面這個泛型方法裡,三個T都指同一個類型,要嘛都是String,要嘛都是Integer。

public <T> List<T> fill(T... t);
登入後複製

但通配符沒有這種約束,List單純的就表示:集合裡放了一個東西,是什麼我不知道。

所以這裡的錯誤就在這裡,List裡面什麼都放不進去。

List list不能進行add,但是,這種形式還是很有用的,雖然不能使用add方法,但是可以在初始化的時候一個Season指定不同的類型。例如:

List<? extends Father> list1 = getFatherList();//getFatherList方法会返回一个Father的子类的list
登入後複製

另外,由於我們已經保證了List中保存的是Father類別或他的某一個子類,所以,可以用get方法直接得到值:

List<? extends Father> list1 = new ArrayList<>();
Father father = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。
Object object = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。
Human human = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。
Son son = (Son)list1.get(0);
登入後複製

下界< ;? super T>不影響往裡存,但往外取只能放在Object物件裡

下界用super進行聲明,表示參數化的類型可能是所指定的類型,或是此類型的父類型,直至Object。

//super只能添加Father和Father的子类,不能添加Father的父类,读取出来的东西只能存放在Object类里
List<? super Father> list = new ArrayList<>();
list.add(new Father());
list.add(new Human());//compile error 
list.add(new Son());
Father person1 = list.get(0);//compile error 
Son son = list.get(0);//compile error 
Object object1 = list.get(0);
登入後複製

因為下界規定了元素的最小粒度的下限,實際上是放鬆了容器元素的類型控制。既然元素是Father的基底類,那往裡面存粒度比Father小的都可以。出於對型別安全的考慮,我們可以加入Father物件或其任何子類別(如Son)對象,但由於編譯器並不知道List的內容究竟是Father的哪個超類,因此不允許加入特定的任何超類(如Human)。而當我們讀取的時候,編譯器在不知道是什麼類型的情況下只能回傳Object對象,因為Object是任何Java類別的最終祖先類別。但這樣的話,元素的類型資訊就全部遺失了。

PECS原則

最後看看什麼是PECS(Producer Extends Consumer Super)原則,已經很好理解了:

  • 頻繁往外讀取內容的,適合用上界Extends。

  • 常往內插入的,適合用下界Super。

#

以上是Java中extends T和super T是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板