最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 泛型詳解(超詳細的java泛型方法解析)

 更新時間:2021年07月01日 16:40:50   作者:太子爺哪吒  
這篇文章主要介紹了深入理解java泛型Generic,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下,希望對你有幫助

1. 為什么使用泛型

早期的Object類型可以接收任意的對象類型,但是在實際的使用中,會有類型轉(zhuǎn)換的問題。也就存在這隱患,所以Java提供了泛型來解決這個安全問題。

  • 來看一個經(jīng)典案例:
public static void main(String[] args) {
        //測試一下泛型的經(jīng)典案例
        ArrayList arrayList = new ArrayList();
        arrayList.add("helloWorld");
        arrayList.add("taiziyenezha");
        arrayList.add(88);//由于集合沒有做任何限定,任何類型都可以給其中存放
        for (int i = 0; i < arrayList.size(); i++) {
            //需求:打印每個字符串的長度,就要把對象轉(zhuǎn)成String類型
            String str = (String) arrayList.get(i);
            System.out.println(str.length());
        }
    }

運行這段代碼,程序在運行時發(fā)生了異常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

發(fā)生了數(shù)據(jù)類型轉(zhuǎn)換異常,這是為什么?

由于ArrayList可以存放任意類型的元素。例子中添加了一個String類型,添加了一個Integer類型,再使用時都以String的方式使用,導(dǎo)致取出時強制轉(zhuǎn)換為String類型后,引發(fā)了ClassCastException,因此程序崩潰了。

這顯然不是我們所期望的,如果程序有潛在的錯誤,我們更期望在編譯時被告知錯誤,而不是在運行時報異常。而為了解決類似這樣的問題(在編譯階段就可以解決),在jdk1.5后,泛型應(yīng)運而生。讓你在設(shè)計API時可以指定類或方法支持泛型,這樣我們使用API的時候也變得更為簡潔,并得到了編譯時期的語法檢查。

我們將第一行聲明初始化ArrayList的代碼更改一下,編譯器就會在編譯階段就能夠幫我們發(fā)現(xiàn)類似這樣的問題。現(xiàn)在再看看效果。

ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("helloWorld");
arrayList.add("taiziyenezha");
arrayList.add(88);// 在編譯階段,編譯器就會報錯

這樣可以避免了我們類型強轉(zhuǎn)時出現(xiàn)異常。

2. 什么是泛型

泛型:是一種把明確類型的工作推遲到創(chuàng)建對象或者調(diào)用方法的時候才去明確的特殊的類型。也就是說在泛型使用過程中,操作的數(shù)據(jù)類型被指定為一個參數(shù),而這種參數(shù)類型可以用在類、方法和接口中,分別被稱為泛型類泛型方法、泛型接口

注意:一般在創(chuàng)建對象時,將未知的類型確定具體的類型。當(dāng)沒有指定泛型時,默認類型為Object類型。

3. 使用泛型的好處

  • 避免了類型強轉(zhuǎn)的麻煩。
  • 它提供了編譯期的類型安全,確保在泛型類型(通常為泛型集合)上只能使用正確類型的對象,避免了在運行時出現(xiàn)ClassCastException。

4. 泛型的使用

泛型雖然通常會被大量的使用在集合當(dāng)中,但是我們也可以完整的學(xué)習(xí)泛型只是。泛型有三種使用方式,分別為:泛型類、泛型方法、泛型接口。將數(shù)據(jù)類型作為參數(shù)進行傳遞。

4.1 泛型類

泛型類型用于類的定義中,被稱為泛型類。通過泛型可以完成對一組類的操作對外開放相同的接口。最典型的就是各種集合框架容器類,如:List、Set、Map。

  • 泛型類的定義格式:

修飾符 class 類名<代表泛型的變量> { }

怕你不清楚怎么使用,這里我還是做了一個簡單的泛型類:

/**
 * @param <T> 這里解釋下<T>中的T:
 *           此處的T可以隨便寫為任意標識,常見的有T、E等形式的參數(shù)表示泛型
 *           泛型在定義的時候不具體,使用的時候才變得具體。
 *           在使用的時候確定泛型的具體數(shù)據(jù)類型。即在創(chuàng)建對象的時候確定泛型。
 */
public class GenericsClassDemo<T> {
    //t這個成員變量的類型為T,T的類型由外部指定
    private T t;
    //泛型構(gòu)造方法形參t的類型也為T,T的類型由外部指定
    public GenericsClassDemo(T t) {
        this.t = t;
    }
    //泛型方法getT的返回值類型為T,T的類型由外部指定
    public T getT() {
        return t;
    }
}

泛型在定義的時候不具體,使用的時候才變得具體。在使用的時候確定泛型的具體數(shù)據(jù)類型。即:在創(chuàng)建對象的時候確定泛型。

例如:Generic<String> genericString = new Generic<String>("helloGenerics");

此時,泛型標識T的類型就是String類型,那我們之前寫的類就可以這么認為:

public class GenericsClassDemo<String> {
    private String t;
    public GenericsClassDemo(String t) {
        this.t = t;
    }
    public String getT() {
        return t;
    }
}

當(dāng)你的泛型類型想變?yōu)镮nteger類型時,也是很方便的。直接在創(chuàng)建時,T寫為Integer類型即可:

Generic<Integer> genericInteger = new Generic<Integer>(666);

  • 注意: 定義的泛型類,就一定要傳入泛型類型實參么?

并不是這樣,在使用泛型的時候如果傳入泛型實參,則會根據(jù)傳入的泛型實參做相應(yīng)的限制,此時泛型才會起到本應(yīng)起到的限制作用。如果不傳入泛型類型實參的話,在泛型類中使用泛型的方法或成員變量定義的類型可以為任何的類型。即跟之前的經(jīng)典案例一樣,沒有寫ArrayList的泛型類型,容易出現(xiàn)類型強轉(zhuǎn)的問題。

4.2 泛型方法

泛型方法,是在調(diào)用方法的時候指明泛型的具體類型 。

  • 定義格式:

修飾符 <代表泛型的變量> 返回值類型 方法名(參數(shù)){ }

例如:

/**
     *
     * @param t 傳入泛型的參數(shù)
     * @param <T> 泛型的類型
     * @return T 返回值為T類型
     * 說明:
     *   1)public 與 返回值中間<T>非常重要,可以理解為聲明此方法為泛型方法。
     *   2)只有聲明了<T>的方法才是泛型方法,泛型類中的使用了泛型的成員方法并不是泛型方法。
     *   3)<T>表明該方法將使用泛型類型T,此時才可以在方法中使用泛型類型T。
     *   4)與泛型類的定義一樣,此處T可以隨便寫為任意標識,常見的如T、E等形式的參數(shù)常用于表示泛型。
     */
    public <T> T genercMethod(T t){
        System.out.println(t.getClass());
        System.out.println(t);
        return t;
    }

調(diào)用方法時,確定泛型的類型

public static void main(String[] args) {
    GenericsClassDemo<String> genericString  = new GenericsClassDemo("helloGeneric"); //這里的泛型跟下面調(diào)用的泛型方法可以不一樣。
    String str = genericString.genercMethod("hello");//傳入的是String類型,返回的也是String類型
    Integer i = genericString.genercMethod(123);//傳入的是Integer類型,返回的也是Integer類型
}

這里我們可以看下結(jié)果:

class java.lang.String

hello

class java.lang.Integer
123

這里可以看出,泛型方法隨著我們的傳入?yún)?shù)類型不同,他得到的類型也不同。泛型方法能使方法獨立于類而產(chǎn)生變化。

4.3 泛型接口

泛型接口與泛型類的定義及使用基本相同。泛型接口常被用在各種類的生產(chǎn)器中。

  • 定義格式
修飾符 interface接口名<代表泛型的變量> {  }

看一下下面的例子,你就知道怎么定義一個泛型接口了:

/**
 * 定義一個泛型接口
 */
public interface GenericsInteface<T> {
    public abstract void add(T t); 
}

使用格式

  • 1、定義類時確定泛型的類型
public class GenericsImp implements GenericsInteface<String> {
    @Override
    public void add(String s) {
        System.out.println("設(shè)置了泛型為String類型");
    }
}
  • 2、始終不確定泛型的類型,直到創(chuàng)建對象時,確定泛型的類型
public class GenericsImp<T> implements GenericsInteface<T> {
    @Override
    public void add(T t) {
        System.out.println("沒有設(shè)置類型");
    }
}

確定泛型:

public class GenericsTest {
    public static void main(String[] args) {
        GenericsImp<Integer> gi = new GenericsImp<>();
        gi.add(66);
    }
}

5. 泛型通配符

當(dāng)使用泛型類或者接口時,傳遞的數(shù)據(jù)中,泛型類型不確定,可以通過通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object類中的共性方法,集合中元素自身方法無法使用。

5.1 通配符基本使用

泛型的通配符:不知道使用什么類型來接收的時候,此時可以使用?,?表示未知通配符。

此時只能接受數(shù)據(jù),不能往該集合中存儲數(shù)據(jù)。

舉個例子大家理解使用即可:

// ?代表可以接收任意類型
// 泛型不存在繼承、多態(tài)關(guān)系,泛型左右兩邊要一樣
//ArrayList<Object> list = new ArrayList<String>();這種是錯誤的
//泛型通配符?:左邊寫<?> 右邊的泛型可以是任意類型
ArrayList<?> list1 = new ArrayList<Object>();
ArrayList<?> list2 = new ArrayList<String>();
ArrayList<?> list3 = new ArrayList<Integer>();

注意:泛型不存在繼承、多態(tài)關(guān)系,泛型左右兩邊要一樣,jdk1.7后右邊的泛型可以省略

而泛型通配符?,右邊的泛型可以是任意類型。

泛型通配符?主要應(yīng)用在參數(shù)傳遞方面,讓我們一起瞧瞧唄:

public static void main(String[] args) {
    ArrayList<Integer> list1 = new ArrayList<Integer>();
    test(list1);
    ArrayList<String> list2 = new ArrayList<String>();
    test(list2);
}
public static void test(ArrayList<?> coll){
}

嘿嘿,是不是見識到了通配符的厲害,可以傳遞不同類似進去方法中了!

5.2 通配符高級使用

之前設(shè)置泛型的時候,實際上是可以任意設(shè)置的,只要是類就可以設(shè)置。但是在JAVA的泛型中可以指定一個泛型的上限下限。

泛型的上限:

  • 格式 類型名稱 <? extends 類 > 對象名稱
  • 意義只能接收該類型及其子類

泛型的下限:

  • 格式: 類型名稱 <? super 類 > 對象名稱
  • 意義: 只能接收該類型及其父類型

比如:現(xiàn)已知Object類,Animal類,Dog類,Cat類,其中Animal是Dog,Cat的父類

class Animal{}//父類
class Dog extends Animal{}//子類
class Cat extends Animal{}//子類

首先我們先看下,泛型的上限<? extends 類 >:

//        ArrayList<? extends Animal> list = new ArrayList<Object>();//報錯
        ArrayList<? extends Animal> list2 = new ArrayList<Animal>();
        ArrayList<? extends Animal> list3 = new ArrayList<Dog>();
        ArrayList<? extends Animal> list4 = new ArrayList<Cat>();

可以看出,泛型的上限只能是該類型的類型及其子類。

  • 我們再來看看泛型的下限<? super 類 >:
        ArrayList<? super Animal> list5 = new ArrayList<Object>();
        ArrayList<? super Animal> list6 = new ArrayList<Animal>();
//        ArrayList<? super Animal> list7 = new ArrayList<Dog>();//報錯
//        ArrayList<? super Animal> list8 = new ArrayList<Cat>();//報錯

可以看出,泛型的下限只能是該類型的類型及其父類。

  • 一般泛型的上限和下限也是用來參數(shù)的傳遞:

再比如:現(xiàn)已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    getElement(list1);
    getElement(list2);//報錯
    getElement(list3);
    getElement(list4);//報錯
    getElement2(list1);//報錯
    getElement2(list2);//報錯
    getElement2(list3);
    getElement2(list4);
}
// 泛型的上限:此時的泛型?,必須是Number類型或者Number類型的子類
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此時的泛型?,必須是Number類型或者Number類型的父類
public static void getElement2(Collection<? super Number> coll){}
118060630

學(xué)到這里,我們泛型也就學(xué)完了!

6. 總結(jié)

這篇文章就到這里了,如果這篇文章對你也有所幫助,希望您能多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • springboot集成nacos實現(xiàn)自動刷新的示例代碼

    springboot集成nacos實現(xiàn)自動刷新的示例代碼

    研究nacos時發(fā)現(xiàn),springboot版本可使用@NacosValue實現(xiàn)配置的自動刷新,本文主要介紹了springboot集成nacos實現(xiàn)自動刷新的示例代碼,感興趣的可以了解一下
    2023-11-11
  • Maven插件的安裝及使用

    Maven插件的安裝及使用

    這篇文章主要介紹了Maven插件的安裝及使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java京東面試題之為什么HashMap線程不安全

    Java京東面試題之為什么HashMap線程不安全

    那天,小二去京東面試,面試官老王一上來就甩給了他一道面試題:為什么 HashMap 是線程不安全的?這個問題哪能難的住小二,這篇文章詳細解答該題目
    2021-11-11
  • Spring Boot連接超時導(dǎo)致502錯誤的實戰(zhàn)案例

    Spring Boot連接超時導(dǎo)致502錯誤的實戰(zhàn)案例

    這篇文章主要給大家介紹了關(guān)于Spring Boot連接超時導(dǎo)致502錯誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 讓Java程序自動重啟的實現(xiàn)方法(推薦)

    讓Java程序自動重啟的實現(xiàn)方法(推薦)

    下面小編就為大家?guī)硪黄孞ava程序自動重啟的實現(xiàn)方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • Java中的collection集合類型總結(jié)

    Java中的collection集合類型總結(jié)

    Java的集合類型都是對java.util包中Collection接口的繼承,這里我們主要介紹依賴于collection的一些主分支,一起來看一下Java中的collection集合類型總結(jié)
    2016-05-05
  • Java設(shè)計模式之中介模式(Mediator模式)介紹

    Java設(shè)計模式之中介模式(Mediator模式)介紹

    這篇文章主要介紹了Java設(shè)計模式之中介模式(Mediator模式)介紹,本文講解了為何使用Mediator模式、如何使用中介模式等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • Java?Collection?接口和常用方法綜合詳解

    Java?Collection?接口和常用方法綜合詳解

    Collection派生出三個子接口,Set代表不可重復(fù)的無序集合、List代表可重復(fù)的有序集合、Queue是java提供的隊列實現(xiàn),通過它們不斷的擴展出很多的集合類,接下來我們詳細介紹一下
    2021-11-11
  • 使用mybatis格式化查詢出的日期

    使用mybatis格式化查詢出的日期

    這篇文章主要介紹了使用mybatis格式化查詢出的日期,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java編程實現(xiàn)提取文章中關(guān)鍵字的方法

    Java編程實現(xiàn)提取文章中關(guān)鍵字的方法

    這篇文章主要介紹了Java編程實現(xiàn)提取文章中關(guān)鍵字的方法,較為詳細的分析了Java提取文章關(guān)鍵字的原理與具體實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11

最新評論

阿瓦提县| 岫岩| 静海县| 淳化县| 陇南市| 海丰县| 巢湖市| 桂平市| 太原市| 祁连县| 门源| 会泽县| 曲水县| 西盟| 泰来县| 江西省| 德庆县| 嘉荫县| 安图县| 丰镇市| 边坝县| 天峻县| 镇原县| 都安| 章丘市| 北宁市| 那曲县| 樟树市| 海阳市| 永寿县| 安义县| 芦山县| 凤台县| 永清县| 高青县| 刚察县| 襄垣县| 繁昌县| 施秉县| 当涂县| 恩平市|