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

Java基礎(chǔ)之java泛型通配符詳解

 更新時(shí)間:2021年07月25日 11:47:14   作者:碼農(nóng)小胖哥  
Java 泛型(generics)是 JDK 5 中引入的一個(gè)新特性, 泛型提供了編譯時(shí)類型安全檢測機(jī)制,該機(jī)制允許開發(fā)者在編譯時(shí)檢測到非法的類型,今天通過本文給大家介紹java泛型通配符的相關(guān)知識(shí),感興趣的朋友一起看看吧

前言

Java 泛型(generics)是 JDK 5 中引入的一個(gè)新特性, 泛型提供了編譯時(shí)類型安全檢測機(jī)制,該機(jī)制允許開發(fā)者在編譯時(shí)檢測到非法的類型。

泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個(gè)參數(shù)。

泛型帶來的好處

在沒有泛型的情況的下,通過對(duì)類型 Object 的引用來實(shí)現(xiàn)參數(shù)的“任意化”,“任意化”帶來的缺點(diǎn)是要做顯式的強(qiáng)制類型轉(zhuǎn)換,而這種轉(zhuǎn)換是要求開發(fā)者對(duì)實(shí)際參數(shù)類型可以預(yù)知的情況下進(jìn)行的。對(duì)于強(qiáng)制類型轉(zhuǎn)換錯(cuò)誤的情況,編譯器可能不提示錯(cuò)誤,在運(yùn)行的時(shí)候才出現(xiàn)異常,這是本身就是一個(gè)安全隱患。

那么泛型的好處就是在編譯的時(shí)候能夠檢查類型安全,并且所有的強(qiáng)制轉(zhuǎn)換都是自動(dòng)和隱式的。

public class GlmapperGeneric<T> {
        private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }

    public static void main(String[] args) {
        // do nothing
    }

  /**
    * 不指定類型
    */
  public void noSpecifyType(){
    GlmapperGeneric glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 需要強(qiáng)制類型轉(zhuǎn)換
    String test = (String) glmapperGeneric.get();
    System.out.println(test);
  }

  /**
    * 指定類型
    */
  public void specifyType(){
    GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 不需要強(qiáng)制類型轉(zhuǎn)換
    String test = glmapperGeneric.get();
    System.out.println(test);
  }
}

上面這段代碼中的 specifyType 方法中 省去了強(qiáng)制轉(zhuǎn)換,可以在編譯時(shí)候檢查類型安全,可以用在類,方法,接口上。

泛型中通配符

我們?cè)诙x泛型類,泛型方法,泛型接口的時(shí)候經(jīng)常會(huì)碰見很多不同的通配符,比如 T,E,K,V 等等,這些通配符又都是什么意思呢?

常用的 T,E,K,V,?

本質(zhì)上這些個(gè)都是通配符,沒啥區(qū)別,只不過是編碼時(shí)的一種約定俗成的東西。比如上述代碼中的 T ,我們可以換成 A-Z 之間的任何一個(gè) 字母都可以,并不會(huì)影響程序的正常運(yùn)行,但是如果換成其他的字母代替 T ,在可讀性上可能會(huì)弱一些。通常情況下,T,E,K,V,?是這樣約定的:

  • ?表示不確定的 java 類型
  • T (type) 表示具體的一個(gè)java類型
  • K V (key value) 分別代表java鍵值中的Key Value
  • E (element) 代表Element

?無界通配符

先從一個(gè)小例子看起,原文在這里。

我有一個(gè)父類 Animal 和幾個(gè)子類,如狗、貓等,現(xiàn)在我需要一個(gè)動(dòng)物的列表,我的第一個(gè)想法是像這樣的:

List<Animal> listAnimals

但是老板的想法確實(shí)這樣的:

List<? extends Animal> listAnimals

為什么要使用通配符而不是簡單的泛型呢?通配符其實(shí)在聲明局部變量時(shí)是沒有什么意義的,但是當(dāng)你為一個(gè)方法聲明一個(gè)參數(shù)時(shí),它是非常重要的。

static int countLegs (List<? extends Animal > animals ) {
    int retVal = 0;
    for ( Animal animal : animals )
    {
        retVal += animal.countLegs();
    }
    return retVal;
}

static int countLegs1 (List< Animal > animals ){
    int retVal = 0;
    for ( Animal animal : animals )
    {
        retVal += animal.countLegs();
    }
    return retVal;
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
     // 不會(huì)報(bào)錯(cuò)
    countLegs( dogs );
    // 報(bào)錯(cuò)
    countLegs1(dogs);
}

當(dāng)調(diào)用 countLegs1 時(shí),就會(huì)飄紅,提示的錯(cuò)誤信息如下:

所以,對(duì)于不確定或者不關(guān)心實(shí)際要操作的類型,可以使用無限制通配符(尖括號(hào)里一個(gè)問號(hào),即),表示可以持有任何類型。像 countLegs 方法中,限定了上屆,但是不關(guān)心具體類型是什么,所以對(duì)于傳入的 Animal 的所有子類都可以支持,并且不會(huì)報(bào)錯(cuò)。而 countLegs1 就不行。

上界通配符 < ? extends E>

上屆:用 extends 關(guān)鍵字聲明,表示參數(shù)化的類型可能是所指定的類型,或者是此類型的子類。

在類型參數(shù)中使用 extends 表示這個(gè)泛型中的參數(shù)必須是 E 或者 E 的子類,這樣有兩個(gè)好處:

  • 如果傳入的類型不是 E 或者 E 的子類,編譯不成功
  • 泛型中可以使用 E 的方法,要不然還得強(qiáng)轉(zhuǎn)成 E 才能使用
private <K extends A, E extends B> E test(K arg1, E arg2){
    E result = arg2;
    arg2.compareTo(arg1);
    //.....
    return result;
}

類型參數(shù)列表中如果有多個(gè)類型參數(shù)上限,用逗號(hào)分開

下界通配符 < ? super E>

下界: 用 super 進(jìn)行聲明,表示參數(shù)化的類型可能是所指定的類型,或者是此類型的父類型,直至 Object

在類型參數(shù)中使用 super 表示這個(gè)泛型中的參數(shù)必須是 E 或者 E 的父類。

private <T> void test(List<? super T> dst, List<T> src){
    for (T t : src) {
        dst.add(t);
    }
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
    List<Animal> animals = new ArrayList<>();
    new Test3().test(animals,dogs);
}
// Dog 是 Animal 的子類
class Dog extends Animal {

}

dst 類型 “大于等于” src 的類型,這里的“大于等于”是指 dst 表示的范圍比 src 要大,因此裝得下 dst 的容器也就能裝 src 。

上界通配符主要用于讀數(shù)據(jù),下界通配符主要用于寫數(shù)據(jù)。

?和 T 的區(qū)別

?和 T 都表示不確定的類型,區(qū)別在于我們可以對(duì) T 進(jìn)行操作,但是對(duì) ?不行,比如如下這種 :

// 可以
T t = operate();

// 不可以
?car = operate();

簡單總結(jié)下:

T 是一個(gè) 確定的 類型,通常用于泛型類和泛型方法的定義,?是一個(gè) 不確定 的類型,通常用于泛型方法的調(diào)用代碼和形參,不能用于定義類和泛型方法。

區(qū)別1:通過 T 來 確保 泛型參數(shù)的一致性

// 通過 T 來 確保 泛型參數(shù)的一致性
public <T extends Number> void
test(List<T> dest, List<T> src)

//通配符是 不確定的,所以這個(gè)方法不能保證兩個(gè) List 具有相同的元素類型
public void
test(List<? extends Number> dest, List<? extends Number> src)

像下面的代碼中,約定的 T 是 Number 的子類才可以,但是申明時(shí)是用的 String ,所以就會(huì)飄紅報(bào)錯(cuò)。

不能保證兩個(gè) List 具有相同的元素類型的情況

GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric<>();
List<String> dest = new ArrayList<>();
List<Number> src = new ArrayList<>();
glmapperGeneric.testNon(dest,src);

上面的代碼在編譯器并不會(huì)報(bào)錯(cuò),但是當(dāng)進(jìn)入到 testNon 方法內(nèi)部操作時(shí)(比如賦值),對(duì)于 dest 和 src 而言,就還是需要進(jìn)行類型轉(zhuǎn)換。

區(qū)別2:類型參數(shù)可以多重限定而通配符不行

使用 & 符號(hào)設(shè)定多重邊界(Multi Bounds),指定泛型類型 T 必須是 MultiLimitInterfaceA 和 MultiLimitInterfaceB 的共有子類型,此時(shí)變量 t 就具有了所有限定的方法和屬性。對(duì)于通配符來說,因?yàn)樗皇且粋€(gè)確定的類型,所以不能進(jìn)行多重限定。

區(qū)別3:通配符可以使用超類限定而類型參數(shù)不行

類型參數(shù) T 只具有 一種 類型限定方式:

T extends A

但是通配符 ? 可以進(jìn)行 兩種限定:

? extends A
? super A

`Class`和 `Class`區(qū)別

前面介紹了 ?和 T 的區(qū)別,那么對(duì)于,Class<T><Class<?>又有什么區(qū)別呢?
Class<T>Class<?>

最常見的是在反射場景下的使用,這里以用一段發(fā)射的代碼來說明下。

// 通過反射的方式生成  multiLimit
// 對(duì)象,這里比較明顯的是,我們需要使用強(qiáng)制類型轉(zhuǎn)換
MultiLimit multiLimit = (MultiLimit)
Class.forName("com.glmapper.bridge.boot.generic.MultiLimit").newInstance();

對(duì)于上述代碼,在運(yùn)行期,如果反射的類型不是 MultiLimit 類,那么一定會(huì)報(bào) java.lang.ClassCastException 錯(cuò)誤。

對(duì)于這種情況,則可以使用下面的代碼來代替,使得在在編譯期就能直接 檢查到類型的問題:

Class<T>在實(shí)例化的時(shí)候,T 要替換成具體類。Class<?>它是個(gè)通配泛型,? 可以代表任何類型,所以主要用于聲明時(shí)的限制情況。比如,我們可以這樣做申明:

// 可以
public Class<?> clazz;
// 不可以,因?yàn)?T 需要指定類型
public Class<T> clazzT;

所以當(dāng)不知道定聲明什么類型的 Class 的時(shí)候可以定義一 個(gè)Class。

那如果也想public Class<T> clazzT;這樣的話,就必須讓當(dāng)前的類也指定 T ,

public class Test3<T> {
    public Class<?> clazz;
    // 不會(huì)報(bào)錯(cuò)
    public Class<T> clazzT;

到此這篇關(guān)于java泛型通配符詳解的文章就介紹到這了,更多相關(guān)java泛型通配符詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java偽泛型知識(shí)點(diǎn)詳解

    java偽泛型知識(shí)點(diǎn)詳解

    在本篇文章里小編給大家整理的是一篇關(guān)于java偽泛型知識(shí)點(diǎn)詳解內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)參考下。
    2021-06-06
  • mongo分布式鎖Java實(shí)現(xiàn)方法(推薦)

    mongo分布式鎖Java實(shí)現(xiàn)方法(推薦)

    下面小編就為大家?guī)硪黄猰ongo分布式鎖Java實(shí)現(xiàn)方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Java Commons-IO的安裝及使用教程詳解

    Java Commons-IO的安裝及使用教程詳解

    本文講解Apache Commons-IO庫的安裝與使用,包括下載、IDE導(dǎo)入及FileUtils方法示例,如文件復(fù)制,幫助簡化Java I/O操作,避免資源泄漏等問題,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • 一文帶你初識(shí)java中的String類

    一文帶你初識(shí)java中的String類

    String代表字符串,Java 程序中的所有字符串字面值(如 "abc" )都作為此類的實(shí)例實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于java中String類的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • 關(guān)于Java企業(yè)級(jí)項(xiàng)目開發(fā)思想

    關(guān)于Java企業(yè)級(jí)項(xiàng)目開發(fā)思想

    Java企業(yè)級(jí)項(xiàng)目開發(fā)思想。偶遇,讀有所得,遂分享給大家,本文不涉及案例,只談思想和理念,需要的朋友可以參考。
    2017-09-09
  • 使用IntelliJ IDEA查看類的繼承關(guān)系圖形(圖文詳解)

    使用IntelliJ IDEA查看類的繼承關(guān)系圖形(圖文詳解)

    這篇文章主要介紹了使用IntelliJ IDEA查看類的繼承關(guān)系圖形,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的工作或?qū)W習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • MyBatis 參數(shù)類型為String時(shí)常見問題及解決方法

    MyBatis 參數(shù)類型為String時(shí)常見問題及解決方法

    這篇文章主要介紹了MyBatis 參數(shù)類型為String時(shí)常見問題及解決方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • spring?boot如何配置靜態(tài)路徑詳解(404出現(xiàn)的坑)

    spring?boot如何配置靜態(tài)路徑詳解(404出現(xiàn)的坑)

    這篇文章主要給大家介紹了關(guān)于spring?boot如何配置靜態(tài)路徑的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Java map 優(yōu)雅的元素遍歷方式說明

    Java map 優(yōu)雅的元素遍歷方式說明

    這篇文章主要介紹了Java map 優(yōu)雅的元素遍歷方式說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 詳解@Autowired(required=false)注入注意的問題

    詳解@Autowired(required=false)注入注意的問題

    這篇文章主要介紹了@Autowired(required=false)注入注意的問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04

最新評(píng)論

吴忠市| 炎陵县| 玛沁县| 鄂伦春自治旗| 攀枝花市| 福安市| 安岳县| 泸西县| 宁蒗| 聂拉木县| 汾阳市| 宿松县| 陈巴尔虎旗| 滦平县| 新安县| 社会| 上林县| 丹阳市| 陇南市| 达日县| 交城县| 富锦市| 南汇区| 梧州市| 平顶山市| 固原市| 喀什市| 宁强县| 民勤县| 桦川县| 桑植县| 蓬溪县| 万载县| 元阳县| 莱西市| 化隆| 甘德县| 金塔县| 高青县| 正宁县| 洱源县|