Java中的泛型

一 泛型是什么
泛型最精準(zhǔn)的定義:參數(shù)化類(lèi)型。具體點(diǎn)說(shuō)就是處理的數(shù)據(jù)類(lèi)型不是固定的,而是可以作為參數(shù)傳入。定義泛型類(lèi)、泛型接口、泛型方法,這樣,同一套代碼,可以用于多種數(shù)據(jù)類(lèi)型。

二 泛型類(lèi)和泛型方法
2.1 泛型類(lèi)和接口
泛型類(lèi)和接口類(lèi)似,定義一個(gè)泛型類(lèi):

public class Som<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

Som就是一個(gè)泛型類(lèi),value的類(lèi)型是T,而T是參數(shù)化的。如果有多個(gè)類(lèi)型參數(shù),使用分號(hào)隔開(kāi),如<U,V>。
使用泛型類(lèi):

Som<String> som = new Som<>();
som.setValue("Hi");
//som.setValue(123);編譯不通過(guò)
String str = som.getValue();

在使用中指定具體的類(lèi)型實(shí)參。
2.2 泛型方法
定義一個(gè)泛型方法:

public static <V> V obtainV(V[] arr) {
    return arr[arr.length / 2];
}

obtainV就是一個(gè)泛型方法,返回值前有<V>,可以處理任意類(lèi)型數(shù)組。
使用泛型方法:

Integer [] arr = {1,2,3};
String [] arrStrs = {"1","2","3"};
int i = obtainV(arr);
String str = obtainV(arrStrs);

三 Java泛型的實(shí)現(xiàn)原理:類(lèi)型擦除
泛型是JDK1.5引入的,為了保持兼容,Java泛型的實(shí)現(xiàn)采用了類(lèi)型擦除。類(lèi)定義中的類(lèi)型參數(shù)會(huì)被替換為Object,運(yùn)行時(shí)不知道泛型的實(shí)際類(lèi)型參數(shù)。
編譯前代碼:

Som<String> som = new Som<>();
som.setValue("Hi");
String str = som.getValue();

編譯后生成的代碼:

Som som = new Som();
som.setValue("Hi");
String str = (String)som.getValue();

可以看到在使用泛型的地方,編譯后生成的代碼,編譯器自動(dòng)進(jìn)行了強(qiáng)制類(lèi)型轉(zhuǎn)換。
Java的泛型實(shí)現(xiàn)就是如此:在編譯期進(jìn)行泛型檢查,編譯后的代碼擦除了類(lèi)型信息,所有泛型都使用Object代替,并進(jìn)行了強(qiáng)制轉(zhuǎn)換。

四 類(lèi)型參數(shù)的限定
泛型的類(lèi)型擦除會(huì)把所有類(lèi)型參數(shù)當(dāng)做Object,但是我們也可以對(duì)參數(shù)類(lèi)型進(jìn)行上界限定。這樣類(lèi)型擦除就會(huì)轉(zhuǎn)換為限定類(lèi)型。
4.1 上界為某個(gè)具體類(lèi)或接口

public class Som<T extends Number> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

這樣使用Som類(lèi),類(lèi)型參數(shù)只接受Number及其子類(lèi)。
當(dāng)上界是泛型類(lèi)或者接口的時(shí)候,上界也需要類(lèi)型參數(shù)。如下:

public class Som<T extends Comparable<T>> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

4.2 上界為其他類(lèi)型參數(shù)

public class Som<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public <E extends T> void test(E e) {
        System.out.println("Som test: e");
    }
}

T是泛型類(lèi)Som的參數(shù)類(lèi)型,E的上界是T,也就是其它類(lèi)型參數(shù)。

五 泛型的通配符
泛型的通配符增強(qiáng)了方法的靈活性但也容易讓人困惑。Java中有無(wú)限定通配符<?>,上界限定通配符<? extends E>,下界限定通配符<? super E>這三種通配符。
5.1 無(wú)限定通配符<?>
需求:打印List中的元素。List是一個(gè)泛型類(lèi),有List<String>,List<Number>,List<Object>等可能。使用List<?>通配符,可以匹配任意List泛型。
代碼如下:

public static void printList(List<?> list) {
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}

看起來(lái)很簡(jiǎn)單,但是此時(shí)的list是無(wú)法進(jìn)行add操作的,因?yàn)長(zhǎng)ist的類(lèi)型是未知的。這就是<?>的只讀性,稍后會(huì)有介紹。

5.2 有限通配符<? extends E>
同樣是一個(gè)打印List元素的例子,但是只接受類(lèi)型參數(shù)是Number及其子類(lèi)。

public static void printList(List<? extends Number> list) {
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}

和<?>一樣,<? extends E>也具有只讀性。

5.3 <?>和<? extends E>的只讀性
通配符<?>和<? extends E>具有只讀性,即可以對(duì)其進(jìn)行讀取操作但是無(wú)法進(jìn)行寫(xiě)入。

public static void printList(List<?> list) {
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
    //一下操作不可以
    list.add(1);
    list.add("123");
}

原因在于:?就是表示類(lèi)型完全無(wú)知,? extends E表示是E的某個(gè)子類(lèi)型,但不知道具體子類(lèi)型,如果允許寫(xiě)入,Java就無(wú)法確保類(lèi)型安全性。假設(shè)我們?cè)试S寫(xiě)入,如果我們傳入的參數(shù)是List<Integer>,此時(shí)進(jìn)行add操作,可以添加任何類(lèi)型元素,就無(wú)法保證List<Integer>的類(lèi)型安全了。

5.4 超類(lèi)型<? super E>
超類(lèi)型通配符允許寫(xiě)入,例子如下:

public static void printList(List<? super String> list) {
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
    list.add("123");
    list.add("456");
}

這個(gè)很好理解,list的參數(shù)類(lèi)型是String的上界,必然可以添加String類(lèi)型的元素。

六 泛型與數(shù)組
Java不能創(chuàng)建泛型數(shù)組,以Som泛型類(lèi)為例,以下代碼編譯報(bào)錯(cuò):

Som<String> [] soms = new Som<String>[8];

原因是像Integer[]和Number[]之間有繼承關(guān)系,而List<Integer>和List<Number>沒(méi)有,如果允許泛型數(shù)組,那么編譯時(shí)無(wú)法發(fā)現(xiàn),運(yùn)行時(shí)也不是立即就能發(fā)現(xiàn)的問(wèn)題會(huì)出現(xiàn)。參看以下代碼:

Som<Integer>[] soms = new Som<Integer>[3];
Object[] objs = soms;
objs[0] = new Som<String>();

那我們?cè)趺创娣欧盒蛯?duì)象呢?可以使用原生數(shù)組或者泛型容器。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,610評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,939評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,004評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,173評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,247評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,580評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評(píng)論 2 380

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

  • 文章作者:Tyan博客:noahsnail.com 1. 什么是泛型 Java泛型(Generics)是JDK 5...
    SnailTyan閱讀 779評(píng)論 0 3
  • 本文包括:JDK5之前集合對(duì)象使用問(wèn)題泛型的出現(xiàn)泛型應(yīng)用泛型典型應(yīng)用自定義泛型——泛型方法自定義泛型——泛型類(lèi)泛型...
    廖少少閱讀 1,922評(píng)論 5 16
  • 引言:泛型一直是困擾自己的一個(gè)難題,但是泛型有時(shí)一個(gè)面試時(shí)老生常談的問(wèn)題;今天作者就通過(guò)查閱相關(guān)資料簡(jiǎn)單談?wù)勛约簩?duì)...
    cp_insist閱讀 1,859評(píng)論 0 4
  • 在編程中,我們希望寫(xiě)出一些更加泛化的代碼,通俗點(diǎn)舉例就是說(shuō),我不關(guān)心你是什么類(lèi)型,只要你能提供某種方法即可。對(duì)此,...
    過(guò)往入夢(mèng)閱讀 223評(píng)論 0 0
  • 當(dāng)晚,小路給家里打了個(gè)電話,跟媽媽詳細(xì)說(shuō)了大舅媽的情況。“大舅舅可能沒(méi)機(jī)會(huì)跟你詳細(xì)說(shuō)”,電話那頭,老媽停頓了一下,...
    小樹(shù)洞君閱讀 1,490評(píng)論 0 4