Java基礎(chǔ)-泛型-泛型通配符與類型擦除

Java工程師知識樹 / Java基礎(chǔ)


  1. 通用通配符

  2. 類型擦除


通用通配符

泛型中有三種通配符形式:

  1. <?> :無限制通配符類型
  2. <? extends E> extends :關(guān)鍵字聲明了類型的上界吻商,表示參數(shù)化的類型可能是所指定的類型往声,或者是此類型的子類。
  3. <? super E> super :關(guān)鍵字聲明了類型的下界嗦玖,表示參數(shù)化類型可能是指定類型片橡,或者是此類型的父類妈经。

通配符在聲明局部變量時是沒有什么意義的,通配符一般是用作為一個方法聲明參數(shù)

通配符在聲明局部變量與為方法聲明參數(shù)代碼:

package com.wechat.management.type;

import java.util.ArrayList;
import java.util.List;

class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}

public class TestGenericStatement{

    public static void main(String[] args) {
        // 聲明局部變量類型時 <? extends Type> 中的 ? 只能是null
        List<? extends Fruit> list = new ArrayList<>();
        list.add(new Apple());//不可添加
        list.add(new Orange());//報錯 : add (capture<? extends com.wechat.management.type.Fruit>) in List cannot be applied to (com.wechat.management.type.Orange)
        list.add(null);// ? extends Fruit 只能添加null(無參數(shù)類型)

        list.contains(new Apple());//可以執(zhí)行是因為入?yún)镺bject o
        list.indexOf(new Apple());//可以執(zhí)行是因為入?yún)镺bject o

        // 聲明局部變量類型時 <? super Type> 中的 ? 是指Type的子類和自身
        List<? super Fruit> list2 = new ArrayList<>();
        list2.add(new Apple());
        list2.add(new Orange());
        list2.add(new Fruit());
        list2.add(new Object());//報錯 : add (capture<? super com.wechat.management.type.Fruit>) in List cannot be applied to (java.lang.Object)

        //--------------------------------------------------
        
        List<Apple> appleList = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();

        // 作為方法入?yún)r吹泡,<? super Type> 中的 ? 是指Type的父類
        addSuper(appleList);// 報錯:cannot be applied
        addSuper(objectList);// 可以添加 Type的父類

        // 作為方法入?yún)r骤星,<? extends Type> 中的 ? 是指Type的子類
        addExtends(appleList);// 可以添加 Type的子類
        addExtends(objectList);// 報錯:cannot be applied

        List<Fruit> fruitList = new ArrayList<>();
        addSuper(fruitList);// 可以添加 包含自身
        addExtends(fruitList);// 可以添加 包含自身
    }

    public static void addSuper(List<? super Fruit> list) {}

    public static void addExtends(List<? extends Fruit> list) {}

}

總結(jié):

  1. 聲明局部變量無意義,不要使用泛型通配符
  2. 聲明方法參數(shù)類型時爆哑,<? super Type> 中的 ? 是Type的父類洞难,<? extends Type> 中的 ? 是Type的子類。

注:介紹下 List<? extends Fruit> 聲明成員變量時為什么不能add任何類型揭朝,甚至Object都不行队贱,除了null,因為null代表任何類型潭袱。

import java.util.ArrayList;
import java.util.List;

class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}

public class TestGenericStatement{

    public static void main(String[] args) {
        List<? extends Fruit> list = new ArrayList<>();
//        list.add(new Apple());//不可添加
//        list.add(new Orange());//報錯 : add (capture<? extends com.wechat.management.type.Fruit>) in List cannot be applied to (com.wechat.management.type.Orange)
        list.add(null);// ? extends Fruit 只能添加null(無參數(shù)類型)

        list.contains(new Apple());//可以執(zhí)行是因為入?yún)镺bject o
        list.indexOf(new Apple());//可以執(zhí)行是因為入?yún)镺bject o
    }
}

不能add任何類型原因解析:

List< ? extends Fruit>可以解讀為:具有任何從Fruit繼承的類型柱嫌,但實際上,它意味著屯换,它沒有指定具體類型编丘。對于編譯器來說,當(dāng)你指定了一個List< ? extends Fruit>彤悔,add的參數(shù)也變成了? extends Fruit瘪吏。因此編譯器并不能了解這里到底需要哪種Fruit的子類型,因此編譯器不接受任何類型的參數(shù)蜗巧。

類型擦除

當(dāng)編譯器對帶有泛型的java代碼進(jìn)行編譯時掌眠,它會去執(zhí)行類型檢查和類型推斷,然后生成普通的不帶泛型的字節(jié)碼幕屹,這種普通的字節(jié)碼可以被一般的 Java 虛擬機接收并執(zhí)行蓝丙,這在就叫做類型擦除(type erasure)

Java中的泛型僅僅是給編譯器javac使用的,確保數(shù)據(jù)的安全性和免去強制類型轉(zhuǎn)換的問題望拖,但是渺尘,一旦編譯完成,所有和泛型有關(guān)的類型全部擦除说敏。

通過反射查看編譯后代碼:

import java.lang.reflect.Method;
import java.util.ArrayList;

public class InvokeDemo {

    public static void main(String[] args) throws Exception {
        ArrayList<Integer> strList = new ArrayList<>();
        strList.add(100);
        strList.add(200);
        
        //獲取ArrayList的Class對象鸥跟,反向的調(diào)用add()方法,添加數(shù)據(jù)
        Class listClass = strList.getClass(); //得到 strList 對象的字節(jié)碼 對象
        //獲取add()方法
        Method method = listClass.getMethod("add", Object.class);
        //調(diào)用add()方法
        method.invoke(strList, "數(shù)字");

        //遍歷集合
        for (Object obj : strList) {
            System.out.println(obj);
        }
    }
}

執(zhí)行結(jié)果:

100
200
數(shù)字
ArrayList<Integer> strList = new ArrayList<>();
strList.add(100);
strList.add(200);
System.out.println("Hello World!");

以上代碼反編譯后的代碼為:


擴(kuò)展閱讀:為什么Java的泛型要用"擦除"實現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盔沫,一起剝皮案震驚了整個濱河市医咨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌架诞,老刑警劉巖拟淮,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谴忧,居然都是意外死亡很泊,警方通過查閱死者的電腦和手機角虫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來委造,“玉大人戳鹅,你說我怎么就攤上這事』枵祝” “怎么了枫虏?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亮垫。 經(jīng)常有香客問我模软,道長,這世上最難降的妖魔是什么饮潦? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任燃异,我火速辦了婚禮,結(jié)果婚禮上继蜡,老公的妹妹穿的比我還像新娘回俐。我一直安慰自己,他們只是感情好稀并,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布仅颇。 她就那樣靜靜地躺著,像睡著了一般碘举。 火紅的嫁衣襯著肌膚如雪忘瓦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天引颈,我揣著相機與錄音耕皮,去河邊找鬼。 笑死蝙场,一個胖子當(dāng)著我的面吹牛凌停,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播售滤,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼罚拟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了完箩?” 一聲冷哼從身側(cè)響起赐俗,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗜憔,沒想到半個月后秃励,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡吉捶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年夺鲜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呐舔。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡币励,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出珊拼,到底是詐尸還是另有隱情食呻,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布澎现,位于F島的核電站仅胞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏剑辫。R本人自食惡果不足惜干旧,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妹蔽。 院中可真熱鬧椎眯,春花似錦、人聲如沸胳岂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乳丰。三九已至掌测,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間产园,已是汗流浹背汞斧。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淆两,地道東北人断箫。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像秋冰,于是被迫代替她去往敵國和親仲义。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容