背景介紹:java中的泛型,是在java5.0後才引用的,泛型,可讓咱們更安全的操做容器,而不用擔憂出現讓人很是不快的ClassCastException異常,可是泛型沒有多態的概念,Sun的那羣大腦殼,就想到了一個解決辦法,就是上界通配符<? extends T>,跟下界通配符(<? super T>),下面就介紹一下我的對它的理解吧,
首先,咱們先定義幾個類:java
Leve2 class Food{} Leve2 class Fruit{} class Meat{} Leve3 class Apple{} class WaterMelon{}
繼承關係圖以下:安全
而後咱們定義2個不使用通配符的方法:app
/** * 不使用上界通配符 */ public static void isUpMethod(List<Fruit> list){ } /** * 不使用下界通配符 */ public static void isDownMethod(List<Fruit> list){ }
接着,咱們使用2個List,放函數裏面存參數:函數
List<Apple> apples = new ArrayList<>(); apples.add(new Apple()); apples.add(new Apple()); apples.add(new Apple()); //兩個方法編譯會報錯 //isUpMethod(apples); //isDownMethod(apples); List<Fruit> fruits = new ArrayList<>(); fruits.add(new Fruit()); fruits.add(new Fruit()); fruits.add(new Fruit()); //編譯經過 isUpMethod(fruits); isDownMethod(fruits);
有同窗就會問了,List的泛型指定了Fruit類型,另一個List泛型指定了Apple確定編譯不過去啊,可是,別忘了,Apple是Fruit的子類,咱們理解中 Fruit fruit = new Apple();是可行的,由於java的多態;
可是,泛型是沒有多態的,它可不認爲Apple是Fruit的子類,若是這樣的話,爲代碼重用代碼很大的麻煩,由於泛型只是編譯級別,在運行期間,泛型是會擦除的;
PS:指定泛型集合後,往內添加的元素能夠是Fruit的子類,由於會自動向上轉型,觸發多態
若是想isUpdownMethod或者isDownMethod函數,接收其泛型類的子類或者父類,這時候,咱們就可使用上界通配符了<? extends Fruit>跟下界通配符<? super Fruit>
咱們定義一個以下函數:ui
/** * 上界通配符 */ public static void upMethod(List<? extends Fruit> list){ //編譯報錯 //使用通配符後,不能在往集合類中添加元素 //list.add(); //使用通配符後,是能夠取出元素的 //全部取出的元素,都是上界父類元素 Fruit fruit = list.get(0); } /** * 下界通配符 */ public static void downMethod(List<? super Fruit> list){ //下界通配符能夠往容器內添加元素 //可是有限制,必須是Fruit的子類或者自己,父類是添加不進去的 list.add(new Apple()); //取出元素的類型都爲Object Object object = list.get(0); }
而後,咱們試試使用往函數類傳輸LIST集合泛型指定是子類的集合:spa
List<Apple> apples = new ArrayList<>(); apples.add(new Apple()); apples.add(new Apple()); apples.add(new Apple()); List<Fruit> fruits = new ArrayList<>(); fruits.add(new Fruit()); fruits.add(new Fruit()); fruits.add(new Fruit()); List<Food> foods = new ArrayList<>(); foods.add(new Food()); foods.add(new Food()); foods.add(new Food()); //編譯經過 upMethod(apples); upMethod(fruits); //編譯經過 downMethod(fruits); downMethod(foods);
上界通配符<? extends Fruit>
簡介:code
- 上界通配符中的上界,指的是泛型內的類型,最高是Fruit類,最低不限,只要是繼承了Fruit類,均可以經過編譯,這也就是爲何叫 "上界",最高類型就是Fruit類
描述:
在upMethod函數中,使用上界通配符後,限定了條件,傳參對象的泛型,必須是Fruit類或者其子類,才能經過編譯,不然,編譯就會失敗,
- 特性:
- 在使用上界通配符後,咱們不能在往集合內添加元素,那是由於,雖然指定了泛型的類型是Fruit類或者其子類,可是Fruit類可能並不止一個子類,可能除了Apple外還有Banana或者Watermelon類,若是你傳遞進來的是Apple集合,可是往裏面添加Banana,這種狀況下,往外取元素的時候很大的可能性會出現異常,由於取出的元素不是Apple而是Banana.因此,避免出現這種狀況,使用上界通配符後,是不能再往集合內添加元素,
- 能夠往外取元素,全部取出的元素都是Fruit類,由於,編譯器只知道是Fruit的子類,可是殊不知道是具體哪一個子類,因此取出的元素是最高層的類,也就是Fruit類
---------------------------------分割線----------------------------------------對象
下界通配符<? super Fruit>描述:
簡介:繼承
- 下界通配符中的下界,指的是泛型內的類型,最低是Fruit類,最高到超類Object,只要是Fruit的父類,均可以經過編譯,這也就是爲何叫 "下界",由於最低是Fruit類
描述:
在downMethod函數中,使用下界通配符後,限定了條件,傳參對象的泛型,必須是Fruit類或者其父類,才能經過編譯,不然,編譯就會失敗,
- 特性:
- 能夠往集合內添加元素,可是限制條件是往內添加的元素,必須是Fruit的子類,由於雖然知道是Fruit的基類 但也不知道是往上數多少級的基類 只有Fruit以及它的子類 編譯器才能判定能觸發多態,
- 能夠往外取元素,可是取出來的元素都是Object,由於取出來的有多是Food,比Fruit範圍大,不能賦值給Fruit對象。只有Object能夠,由於沒有類比Object大。
---------------------------------分割線----------------------------------------內存
有人可能會問,爲何使用上界通配符後,不能往裏存元素了,可是使用下界通配符能往裏面存元素,緣由以下:
上界通配符指定了上限,最高就是Fruit類,往裏存元素,不是Fruit就是其子類啊,理論上是能夠往內存的,那是由於使用上界通配符後,雖然有上限,可是沒有下限啊,編譯器,只知道是Fruit類或者是Fruit的子類,可是具體是哪一個類型的子類,編譯器也不知道,爲了防止出現類型轉換錯誤,因此,就禁止再往內添加元素(若是是我,我也會這麼作,避免出現這樣的狀況)
下界通配符能往內存元素是由於下界通配符,規定了最小粒度的下限,是Fruit類.其實是放鬆了對元素的類型控制,既然元素是Fruit類的父類,那往裏存Fruit子類確定能夠的,由於Fruit的子類,也是其Fruit父類的子類,
- 上界通配符<? extends Fruit> 能夠當作<?> 類型都不知道,確定不讓往裏面添加元素,由於沒有下限;也能夠當作是一個能夠放某種Fruit的集合,不是一個能夠聽任何Fruit的大雜燴集合
- 下界通配符<? super Fruit> 能夠當作<Fruit>,肯定了類型最低是Fruit,因此能夠往內添加元素,可是必須是Fruit或者其子類;也能夠當作是一個能夠聽任何Fruit的集合
---------------------------------分割線----------------------------------------
總結:
- 上界通配符<? extends T> 指的是,引用內的泛型範圍,最高是T類,最低不限
- 能夠取元素
- 不能添加元素
- 下界通配符<? super T> 指的是,引用內的泛型範圍,最低是T類,最高是超類Object
- 能夠取元素,可是取出的元素是Object
- 能夠添加元素,添加的元素,必須是T類或者其子類
到這,文章就結束了!
以上,均爲本人理解,若是理解錯誤,歡迎指正
歡迎轉載,請註明出處跟做者,謝謝!