【RE:布丁JAVA學(xué)習(xí)】這大概是史上最詳細(xì)的JAVA泛型教程,不看后悔贮配。

引言

【RE:布丁JAVA】是一個(gè)java小白布丁薩瑪渾渾噩噩工作三年之后發(fā)現(xiàn)自己java基礎(chǔ)不行而重新學(xué)習(xí)java的系列谍倦,喜歡的同學(xué)可以點(diǎn)個(gè)<font color=red >關(guān)注</font>,如果有什么問(wèn)題可以在評(píng)論區(qū)發(fā)表<font color=red >評(píng)論</font>泪勒,謝謝??

愿:<font color=red >天下程序猿頭發(fā)烏黑亮麗</font>

概述

在我剛開(kāi)始學(xué)習(xí)JAVA的時(shí)候經(jīng)持缰看到<T> <K> <T,K> <? extends Number> 等等類(lèi)似的寫(xiě)法,當(dāng)時(shí)就很疑惑圆存,這些到底是什么為什么有的時(shí)候是'T'有的時(shí)候是'K'而有的時(shí)候是'?'叼旋,是有什么規(guī)則么?這些代表的又是什么呢沦辙?我想要使用<J>可以嗎夫植?
下面就要我們帶著這種種疑問(wèn)來(lái)看下我們今天的主題==泛型'==。

1、為什么要使用泛型

我們學(xué)習(xí)泛型详民,首先要明白==我們?yōu)槭裁匆褂梅盒?=

舉個(gè)有點(diǎn)不優(yōu)雅例子

小A過(guò)生日舉行了一個(gè)生意派對(duì)延欠,于是他準(zhǔn)備了一個(gè)箱子。告訴大家沒(méi)人可以把放進(jìn)去一個(gè)食物沈跨。到時(shí)候自己會(huì)把他們一個(gè)一個(gè)的吃掉由捎。于是小B放了蘋(píng)果、小C放了橘子饿凛。
但是狞玛,我放了一坨屎進(jìn)去。
然后小A在生日派對(duì)上就吃了shit發(fā)生了不可以思議的事情涧窒。
于是小A之后再辦這種事情的時(shí)候心肪,會(huì)讓自己的管家檢查放進(jìn)入的是不是食物。不是食物就是不讓放進(jìn)去纠吴。這樣他就不會(huì)吃屎了蒙畴。
而這個(gè)管家就可以認(rèn)為是泛型。為了約束放入箱子?xùn)|西的類(lèi)型呜象。

好了好了,看完上面這個(gè)例子同學(xué)們一定都知道了什么是泛型了碑隆,為什么使用泛型(為了防止吃shit )下面我們就開(kāi)認(rèn)真講一下恭陡。

2、什么是泛型

同學(xué)們都知道在我們開(kāi)發(fā)的時(shí)候錯(cuò)誤可以分為兩種上煤,

編譯時(shí)錯(cuò)誤

在編譯階段由java編譯器發(fā)現(xiàn)的錯(cuò)誤休玩。

編譯時(shí)錯(cuò)誤

如上圖所示,編譯器發(fā)現(xiàn)我們的代碼錯(cuò)誤劫狠,會(huì)提示我們拴疤,而我們開(kāi)發(fā)人員必須要修改錯(cuò)誤之后,才可以通過(guò)編譯独泞。這就是編譯時(shí)錯(cuò)誤

運(yùn)行時(shí)錯(cuò)誤

編譯時(shí)未報(bào)錯(cuò)呐矾,在運(yùn)行時(shí)拋出異常。


在這里插入圖片描述

如上圖所示在編譯的時(shí)候懦砂,是不會(huì)曝出錯(cuò)誤蜒犯。但是運(yùn)行的時(shí)候就會(huì)拋出==ClassCastException==的錯(cuò)誤,這樣就稱之為運(yùn)行時(shí)錯(cuò)誤荞膘。


在這里插入圖片描述

從JDK5開(kāi)始所有的Java集合都采用了泛型的機(jī)制罚随。在聲明集合變量的時(shí)候,可以使用‘<>’指定集合中的元素類(lèi)型羽资。

例子如下圖


在這里插入圖片描述

所以說(shuō):

==泛型就是為了把 ClassCastException 運(yùn)行時(shí)錯(cuò)誤轉(zhuǎn)換成編譯時(shí)錯(cuò)淘菩,是為了約束參數(shù)類(lèi)型而誕生的。==

泛型的主要用于==泛型類(lèi)==屠升、==泛型接口==潮改、==泛型方法==狭郑、==泛型數(shù)組==

下面就讓我們一次來(lái)介紹以下。

3进陡、泛型類(lèi)&泛型接口

首先我們先來(lái)看一個(gè)正常的類(lèi)愿阐,然后我們嘗試把他改造成一個(gè)泛型類(lèi)。


public class Printer {
    /**
     * 打印文字
     */
    Object printText;

    public Printer(Object printText) {
        this.printText = printText;
    }

    public Object getPrintText() {
        return printText;
    }

    public void setPrintText(Object printText) {
        this.printText = printText;
    }
    
    public static void main(String[] args) {
     Printer printer = new Printer("測(cè)試打印文本");
     // 運(yùn)行時(shí)錯(cuò)誤 拋出ClassCastException
     Integer o = (Integer) printer.getPrintText();
    }
}

在main方法中代碼調(diào)用printer類(lèi)趾疚,獲取printText進(jìn)行了強(qiáng)制轉(zhuǎn)換編譯可以通過(guò)但是運(yùn)行就會(huì)報(bào)錯(cuò)缨历,拋出ClassCastException錯(cuò)誤。
為了防止這種情況出現(xiàn)糙麦,我們就可以對(duì)printer類(lèi)進(jìn)行改造辛孵。

public class Printer<T> {
    /**
     * 打印文字
     */
    T printText;

    public Printer(T printText) {
        this.printText = printText;
    }

    public T getPrintText() {
        return printText;
    }

    public void setPrintText(T printText) {
        this.printText = printText;
    }

    public static void main(String[] args) {
        Printer<String> printer=new Printer<String>("這是測(cè)試打印文本");
        Integer o = (Integer) printer.getPrintText();// 編譯錯(cuò)誤
        String a = printer.getPrintText();// 合法
    }
}

就像在定義方法的時(shí)候可以聲明一些方法參數(shù),在定義類(lèi)的時(shí)候我們可以通過(guò)< T >的形式類(lèi)聲明類(lèi)型參數(shù)赡磅,在類(lèi)主題中可以直接引用 T魄缚。

這種帶有類(lèi)型參數(shù)的類(lèi)就被稱為泛型類(lèi)。

上面的printer類(lèi)就是一個(gè)泛型類(lèi)焚廊,他有一個(gè)類(lèi)型參數(shù)T冶匹,而在main方法中初始化printer類(lèi)的時(shí)候指定的T為String,所以在之后的get方法中編譯器會(huì)知道返回值為String咆瘟,所以使用Integer接收的時(shí)候會(huì)編譯錯(cuò)誤嚼隘。而使用String接收的時(shí)候就是合法的。

泛型類(lèi)格式:

修飾詞 class 類(lèi)名 <T> {...}

如:

public class printer <T> {
T content;
}

public class people <J> {
J name;
}

這里的T只是習(xí)慣叫法而已袒餐。如果你樂(lè)意也可以用其他字母代替 比如 B飞蛹、Y、H灸眼。都是可以的卧檐。

一個(gè)泛型類(lèi)也可以有多個(gè)類(lèi)型參數(shù),多個(gè)類(lèi)型參數(shù)放在一個(gè)<>中使用‘,’隔開(kāi)焰宣,例子如下:


public class Printer<T,K> {
    
    Map<T,K> map;

    public Map<T, K> getMap() {
        return map;
    }

    public void setMap(Map<T, K> map) {
        this.map = map;
    }

    public static void main(String[] args) {
        Printer<String,Integer> printer=new Printer<String, Integer>();
        printer.getMap().put("key",1);// 合法
        printer.getMap().put(1,"key");// 編譯錯(cuò)誤
    }
}

泛型接口與泛型類(lèi)的用法基本一致

泛型接口的格式

修飾詞 interface 接口名稱 <T> {...}

這里我們就舉一個(gè)例子看下:

public interface people <T> {
    T setName(T name);
}

4霉囚、泛型方法

在一個(gè)方法中,如果方法的參數(shù)或者返回值中帶有<font color=red>< T ></font>形式的類(lèi)型參數(shù)宛徊,那么這個(gè)方法稱為泛型方法佛嬉。在普通的類(lèi)或者泛型類(lèi)中都可以創(chuàng)建泛型方法。

泛型方法結(jié)構(gòu)

// 返回值 闸天、參數(shù) 暖呕、 方法體 都可以引用 K類(lèi)型參數(shù)
修飾詞 <K> 返回值 方法名稱(參數(shù)) {方法體}

例子如下


public class Printer<T> {

    T printText;
    
    // 不是泛型方 T只是引用了類(lèi)的類(lèi)型變量而已。并沒(méi)有自己定義
    public T getPrintText() {
        return printText;
    }
    // 是泛型方法 自己定義了類(lèi)型變量K
    public <K> K print(K text) {
        System.out.println("打印文本:" + text);
        return text;
    }

    public static void main(String[] args) {

        Printer printer=new Printer();
        printer.print("測(cè)試打印文本");
    }
}

例子中的getPrintText()方法雖然有T但是并不是泛型方 T只是引用了類(lèi)的類(lèi)型變量而已苞氮。并沒(méi)有自己定義湾揽。
而print()方法是泛型方法因?yàn)樽约憾x了類(lèi)型變量K。

5、泛型數(shù)組

泛型數(shù)組是指數(shù)組的類(lèi)型是‘T’的數(shù)組库物,如‘T[]’霸旗;

例子

public class Printer<T> {
    // 泛型數(shù)組
    public T[] content;

    public T[] getContent() {
        return content;
    }

    public void setContent(T[] content) {
        this.content = content;
    }

    public static void main(String[] args) {
        Printer<String> printer = new Printer<String>();
        printer.setContent(new String[]{"元素1", "元素2"});
        System.out.println(printer.getContent()[0]);
    }
}

==注意==:在泛型類(lèi)中不能用泛型數(shù)組來(lái)創(chuàng)建數(shù)組實(shí)例。

public class Printer<T> {
    // 泛型數(shù)組
    public T[] content = new T[10]; //編譯出錯(cuò)戚揭,不能用泛型數(shù)組來(lái)創(chuàng)建數(shù)組實(shí)例诱告。
}

5、extends關(guān)鍵詞

在定義泛型的時(shí)候民晒,我們可以使用extends關(guān)鍵字來(lái)限定類(lèi)型參數(shù)精居,語(yǔ)法格式為

<T extends 類(lèi)名>/<T extends 接口名>
比如我們剛開(kāi)始的例子中,我們想要放入箱子的食物都是甜品潜必,那么我們就可以寫(xiě) <T extends 甜品>

例子:

public class Printer<T extends Number> {

    public T content;

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }

    public static void main(String[] args) {
        Printer<Integer> printer = new Printer<Integer>(); // 合法靴姿;Integer是Number子類(lèi)
        Printer<Double> printer1 = new Printer<Double>();  // 合法; Double是Number子類(lèi)
        Printer<String> printer2 = new Printer<String>();  // 編譯錯(cuò)誤磁滚;String不是Number子類(lèi)
    }
}

在上面的例子中佛吓,我們?cè)趐rint類(lèi)中定義了一個(gè) <T extends Number>,代表引入的參數(shù)類(lèi)型必須是Number的子類(lèi)。
根據(jù)下圖我們知道 Integer 和 Double都是Number的子類(lèi)垂攘,所以合法维雇,而String并不是Number的子類(lèi),所以會(huì)出現(xiàn)編譯錯(cuò)誤晒他。

在這里插入圖片描述

6谆沃、"?" 通配符

‘?’是表示一個(gè)不確定的類(lèi)型。由于不是像‘T’一樣是一個(gè)確定的類(lèi)型仪芒,所以‘?’無(wú)法用于定義變量或者類(lèi)脖母。一般用于集合中尔邓。

‘?’可以使用有上限和下限對(duì)類(lèi)型進(jìn)行約束

‘?’的上限‘<? extends 類(lèi)名/接口>’

List<? extends Number> list = new ArrayList<>();

‘?’的下限‘<? super 類(lèi)名/接口>’

List<? super Number> list = new ArrayList<>();

關(guān)于通配符還有很多東西可以講,比如List<? extends Number> 無(wú)法add除了null只為的元素捶牢,這個(gè)我之后準(zhǔn)備專門(mén)開(kāi)一篇講解哟沫,如果有想要知道的同學(xué)可以點(diǎn)個(gè)關(guān)注饺蔑。

7、注意事項(xiàng)

1嗜诀、泛型只在編譯期間有效猾警,在編譯之后的字節(jié)碼文件中就會(huì)被清除。
所以以下兩個(gè)list對(duì)象是相等的

List<Srting> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();

System.out.println(list1.getClass()==list2.getClass()) // 打印true

因?yàn)榉盒驮诰幾g之后隆敢,所以編譯器也是不允許在一個(gè)類(lèi)定義兩個(gè)同名的方法发皿,參數(shù)分別是List<T>List<K>

public class Printer<T,K> {
   public void print(List<T> list){
       
   }
   // 編譯錯(cuò)誤,非法的方法重載
   public void print(List<K> list2){
       
   }
}

2拂蝎、不可以對(duì)泛型進(jìn)行強(qiáng)制轉(zhuǎn)換穴墅,這樣存在安全隱患,會(huì)導(dǎo)致拋出ClassCastException異常。

        Collection list1 = new ArrayList<Integer>();
        list1.add(1);
        List<String> list2 = new ArrayList<String>();
        list2 = (ArrayList<String>) list1;
        for (String s:list2){
            System.out.println(s); // 拋出異常ClassCastException
        }

3玄货、不能對(duì)泛型進(jìn)行instanceof操作皇钞。

   public void print(List<K> list){
       // 編譯錯(cuò)誤
       if(list instanceof Collection<String>){
           
       }
   }

8、參考

8松捉、結(jié)語(yǔ)

本片文章主要講了泛型的使用夹界,我們知道了泛型主要是為了是編譯器在編譯的時(shí)候能夠判斷我們的參數(shù)是否正確,從而避免運(yùn)行時(shí)錯(cuò)誤隘世。并且可以簡(jiǎn)化代碼編寫(xiě)可柿,無(wú)需進(jìn)行多余的強(qiáng)制轉(zhuǎn)換。
然后我們學(xué)習(xí)了如何定義 泛型類(lèi)以舒、泛型方法趾痘、泛型接口 等。
如果文章有什么錯(cuò)誤后者同學(xué)們有疑問(wèn)的地方蔓钟,歡迎評(píng)論留言永票,
如果您喜歡,歡迎<font color=red>關(guān)注滥沫、點(diǎn)贊</font> 謝謝??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侣集,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兰绣,更是在濱河造成了極大的恐慌世分,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缀辩,死亡現(xiàn)場(chǎng)離奇詭異臭埋,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)臀玄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)瓢阴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人健无,你說(shuō)我怎么就攤上這事荣恐。” “怎么了累贤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵叠穆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我臼膏,道長(zhǎng)硼被,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任渗磅,我火速辦了婚禮祷嘶,結(jié)果婚禮上屎媳,老公的妹妹穿的比我還像新娘。我一直安慰自己论巍,他們只是感情好烛谊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著嘉汰,像睡著了一般丹禀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞋怀,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天双泪,我揣著相機(jī)與錄音,去河邊找鬼密似。 笑死焙矛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的残腌。 我是一名探鬼主播村斟,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抛猫!你這毒婦竟也來(lái)了蟆盹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闺金,失蹤者是張志新(化名)和其女友劉穎逾滥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體败匹,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寨昙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掀亩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毅待。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖归榕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吱涉,我是刑警寧澤刹泄,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站怎爵,受9級(jí)特大地震影響特石,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳖链,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一姆蘸、第九天 我趴在偏房一處隱蔽的房頂上張望墩莫。 院中可真熱鬧,春花似錦逞敷、人聲如沸狂秦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)裂问。三九已至,卻和暖如春牛柒,著一層夾襖步出監(jiān)牢的瞬間堪簿,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工皮壁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留椭更,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓蛾魄,卻偏偏與公主長(zhǎng)得像虑瀑,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子畏腕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351