欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java泛型及其應(yīng)用

 更新時間:2019年04月06日 08:31:38   作者:aoho  
這篇文章主要介紹了Java泛型及其應(yīng)用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

引出泛型

我們通過如下的示例,引出為什么泛型的概念。

public class Test {

  public static void main(String[] args) {
    List list = new ArrayList();
    list.add("abc");
    list.add(2);

    for (int i = 0; i < list.size(); i++) {
      String name = (String) list.get(i); // error
      System.out.println("name:" + name);
    }
  }
}

當(dāng)獲取列表中的第二個元素時,會報錯,java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String。這是常見的類型轉(zhuǎn)換錯誤。

當(dāng)我們將元素放入到列表中,并沒有使用指定的類型,在取出元素時使用的是默認的 Object 類型。因此很容易出現(xiàn)類型轉(zhuǎn)換的異常。

我們想要實現(xiàn)的結(jié)果是,集合能夠記住集合內(nèi)元素各類型,且能夠達到只要編譯時不出現(xiàn)問題,運行時就不會出現(xiàn) java.lang.ClassCastException 異常。泛型剛好能滿足我們的需求。

什么是泛型?

泛型,即參數(shù)化類型。一提到參數(shù),最熟悉的就是定義方法時有形參,然后調(diào)用此方法時傳遞實參。那么參數(shù)化類型怎么理解呢?顧名思義,就是將類型由原來的具體的類型參數(shù)化,類似于方法中的變量參數(shù),此時類型也定義成參數(shù)形式(可以稱之為類型形參),然后在使用/調(diào)用時傳入具體的類型(類型實參)。

泛型的本質(zhì)是為了參數(shù)化類型,即在不創(chuàng)建新的類型的情況下,通過泛型指定的不同類型來控制形參具體限制的類型。在泛型使用過程中,操作的數(shù)據(jù)類型被指定為一個參數(shù),這種參數(shù)類型可以用在類、接口和方法中,分別被稱為泛型類、泛型接口和泛型方法。

泛型的特點

Java 語言中引入泛型是一個較大的功能增強。不僅語言、類型系統(tǒng)和編譯器有了較大的變化,已支持泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經(jīng)成為泛型化的了。這帶來了很多好處:

  1. 類型安全。 泛型的主要目標(biāo)是提高 Java 程序的類型安全。通過知道使用泛型定義的變量的類型限制,編譯器可以在一個高得多的程度上驗證類型假設(shè)。
  2. 消除強制類型轉(zhuǎn)換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉(zhuǎn)換。這使得代碼更加可讀,并且減少了出錯機會。
  3. 潛在的性能收益。 泛型為較大的優(yōu)化帶來可能。在泛型的初始實現(xiàn)中,編譯器將強制類型轉(zhuǎn)換(沒有泛型的話,程序員會指定這些強制類型轉(zhuǎn)換)插入生成的字節(jié)碼中。

命名類型參數(shù)

推薦的命名約定是使用大寫的單個字母名稱作為類型參數(shù)。對于常見的泛型模式,推薦的名稱是:

  1. K:鍵,比如映射的鍵
  2. V:值,比如 List 和 Set 的內(nèi)容,或者 Map 中的值
  3. E:元素
  4. T:泛型
public class Generic<T> { 
  //key的類型為T 
  private T key;

  public Generic(T key) { 
  	//泛型構(gòu)造方法形參key的類型也為T
    this.key = key;
  }

  public T getKey() { 
  	//泛型方法getKey的返回值類型為T
    return key;
  }
}

如上定義了一個普通的泛型類,成員變量的類型為 T,T的類型由外部指定。泛型方法和泛型構(gòu)造函數(shù)同樣如此。

Generic<Integer> genericInteger = new Generic<Integer>(123456); //1

Generic<String> genericString = new Generic<String>("key_vlaue"); // 2

System.out.println("key is " + genericInteger.getKey());
System.out.println("key is " + genericString.getKey());

泛型的類型參數(shù)只能是類類型(包括自定義類),不能是簡單類型。傳入的實參類型需與泛型的類型參數(shù)類型相同,即為Integer/String。

如上所述,定義的泛型類,就一定要傳入泛型類型實參么?

并不是這樣,在使用泛型的時候如果傳入泛型實參,則會根據(jù)傳入的泛型實參做相應(yīng)的限制,此時泛型才會起到本應(yīng)起到的限制作用。如果不傳入泛型類型實參的話,在泛型類中使用泛型的方法或成員變量定義的類型可以為任何的類型。

Generic genericString = new Generic("111111");
Generic genericInteger = new Generic(4444);

System.out.println("key is " + genericString.getKey());
System.out.println("key is " + genericInteger.getKey());

如上的代碼片段,將會輸出如下的結(jié)果:

key is 111111
key is 4444

在不傳入泛型類型實參的情況下,泛型類中使用的泛型防范或成員變量可以為 Integer 或 String 等等其他任意類型。不過需要注意的是,泛型的類型參數(shù)只能是類類型,不能是簡單類型。且不能對確切的泛型類型使用 instanceof 操作。對于不同傳入的類型實參,生成的相應(yīng)對象實例的類型是不是一樣的呢?具體看如下的示例:

public class GenericTest {

  public static void main(String[] args) {

    Generic<Integer> name = new Box<String>("111111");
    Generic<String> age = new Box<Integer>(712);

    System.out.println("name class:" + name.getClass()); 
    System.out.println("age class:" + age.getClass()); 
    System.out.println(name.getClass() == age.getClass());  // true
  }

}

由輸出結(jié)構(gòu)可知,在使用泛型類時,雖然傳入了不同的泛型實參,但并沒有真正意義上生成不同的類型,傳入不同泛型實參的泛型類在內(nèi)存上只有一個,即還是原來的最基本的類型(本例中為 Generic),當(dāng)然在邏輯上我們可以理解成多個不同的泛型類型。

究其原因,在于 Java 中的泛型這一概念提出的目的,其只是作用于代碼編譯階段。在編譯過程中,對于正確檢驗泛型結(jié)果后,會將泛型的相關(guān)信息擦除。也就是說,成功編譯過后的 class 文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。

泛型類型在邏輯上看以看成是多個不同的類型,實際上都是相同的基本類型。

通配符

Ingeter 是 Number 的一個子類,同時 Generic<Ingeter> 與 Generic<Number> 實際上是相同的一種基本類型。那么問題來了,在使用 Generic<Number> 作為形參的方法中,能否使用Generic<Ingeter> 的實例傳入呢?在邏輯上類似于 Generic<Number> 和 Generic<Ingeter> 是否可以看成具有父子關(guān)系的泛型類型呢?下面我們通過定義一個方法來驗證。

public void show(Generic<Number> obj) {
  System.out.println("key value is " + obj.getKey());
}

進行如下的調(diào)用

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

show(genericInteger); //error Generic<java.lang.Integer> cannot be applied to Generic<java.lang.Number>

通過提示信息我們可以看到 Generic<Integer> 不能被看作為 Generic<Number> 的子類。由此可以看出:同一種泛型可以對應(yīng)多個版本(因為參數(shù)類型是不確定的),不同版本的泛型類實例是不兼容的。

我們不能因此定義一個 show(Generic<Integer> obj)來處理,因此我們需要一個在邏輯上可以表示同時是Generic和Generic父類的引用類型。由此類型通配符應(yīng)運而生。

T、K、V、E 等泛型字母為有類型,類型參數(shù)賦予具體的值。除了有類型,還可以用通配符來表述類型,? 未知類型,類型參數(shù)賦予不確定值,任意類型只能用在聲明類型、方法參數(shù)上,不能用在定義泛型類上。將方法改寫成如下:

public void show(Generic<?> obj) {
  System.out.println("key value is " + obj.getKey());
}

此處 ? 是類型實參,而不是類型形參。即和 Number、String、Integer 一樣都是實際的類型,可以把 ? 看成所有類型的父類,是一種真實的類型。可以解決當(dāng)具體類型不確定的時候,這個通配符就是 ?;當(dāng)操作類型時,不需要使用類型的具體功能時,只使用 Object 類中的功能。那么可以用 ? 通配符來表未知類型。

泛型上下邊界

在使用泛型的時候,我們還可以為傳入的泛型類型實參進行上下邊界的限制,如:類型實參只準(zhǔn)傳入某種類型的父類或某種類型的子類。為泛型添加上邊界,即傳入的類型實參必須是指定類型的子類型。

public void show(Generic<? extends Number> obj) {
  System.out.println("key value is " + obj.getKey());
}

我們在泛型方法的入?yún)⑾薅▍?shù)類型為 Number 的子類。

Generic<String> genericString = new Generic<String>("11111");
Generic<Integer> genericInteger = new Generic<Integer>(2222);


showKeyValue1(genericString); // error
showKeyValue1(genericInteger);

當(dāng)我們的入?yún)?String 類型時,編譯報錯,因為 String 類型并不是 Number 類型的子類。

類型通配符上限通過形如 Generic<? extends Number> 形式定義;相對應(yīng)的,類型通配符下限為Generic<? super Number>形式,其含義與類型通配符上限正好相反,在此不作過多闡述。

泛型數(shù)組

在 java 中是不能創(chuàng)建一個確切的泛型類型的數(shù)組的,即:

List<String>[] ls = new ArrayList<String>[10]; 

如上會編譯報錯,而使用通配符創(chuàng)建泛型數(shù)組是可以的:

List<?>[] ls = new ArrayList<?>[10]; 

//List<String>[] ls = new ArrayList[10];

JDK1.7 對泛型的簡化,所以另一種聲明也是可以的。

由于JVM泛型的擦除機制,在運行時 JVM 是不知道泛型信息的。泛型數(shù)組實際的運行時對象數(shù)組只能是原始類型( T[]為Object[],Pair[]為Pair[] ),而實際的運行時數(shù)組對象可能是T類型( 雖然運行時會擦除成原始類型 )。成功創(chuàng)建泛型數(shù)組的唯一方式就是創(chuàng)建一個被擦出類型的新數(shù)組,然后對其轉(zhuǎn)型。

public class GenericArray<T> {
  private Object[] array; //維護Object[]類型數(shù)組
  @SupperessWarning("unchecked")
  public GenericArray(int v) {
    array = new Object[v];
  }
  public void put(int index, T item) {
    array[index] = item;
  }
  public T get(int index) { 
  	return (T)array[index]; 
  } //數(shù)組對象出口強轉(zhuǎn)
  public T[] rep() { return (T[])array; } //運行時無論怎樣都是Object[]類型 
  public static void main (String[] args){
    GenericArray<Integer> ga = new GenericArray<Integer>(10);
    // Integer[] ia = ga.rep(); //依舊ClassCastException
    Object[] oa = ga.rep(); //只能返回對象數(shù)組類型為Object[]
    ga.put(0, 11);
    System.out.println(ga.get(0)); // 11
  }
}

在運行時,數(shù)組對象的出口做轉(zhuǎn)型輸出,入口方法在編譯期已實現(xiàn)類型安全,所以出口方法可以放心強制類型轉(zhuǎn)換,保證成功。

小結(jié)

本文主要講了 Java 泛型的相關(guān)概念和應(yīng)用。泛型使編譯器可以在編譯期間對類型進行檢查以提高類型安全,減少運行時由于對象類型不匹配引發(fā)的異常。由泛型的誕生介紹相關(guān)的概念,在保證代碼質(zhì)量的情況下,如何使用泛型去簡化開發(fā)。

以上所述是小編給大家介紹的Java泛型及其應(yīng)用詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 解決Mybatis-plus和pagehelper依賴沖突的方法示例

    解決Mybatis-plus和pagehelper依賴沖突的方法示例

    這篇文章主要介紹了解決Mybatis-plus和pagehelper依賴沖突的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Struts2+Hibernate實現(xiàn)數(shù)據(jù)分頁的方法

    Struts2+Hibernate實現(xiàn)數(shù)據(jù)分頁的方法

    這篇文章主要介紹了Struts2+Hibernate實現(xiàn)數(shù)據(jù)分頁的方法,結(jié)合實例形式分析了Struts2結(jié)合Hibernate實現(xiàn)數(shù)據(jù)分頁的原理,步驟與相關(guān)實現(xiàn)代碼,需要的朋友可以參考下
    2016-03-03
  • Idea熱加載插件JRebel激活以及使用教程

    Idea熱加載插件JRebel激活以及使用教程

    JRebel是一款JVM插件,它使得Java代碼修改后不用重啟系統(tǒng),立即生效,下面這篇文章主要給大家介紹了關(guān)于Idea熱加載插件JRebel激活以及使用的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • xxl-job對比ElasticJob使用示例詳解

    xxl-job對比ElasticJob使用示例詳解

    這篇文章主要為大家介紹了xxl-job對比ElasticJob使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • springboot實現(xiàn)執(zhí)行sql語句打印到控制臺

    springboot實現(xiàn)執(zhí)行sql語句打印到控制臺

    這篇文章主要介紹了springboot實現(xiàn)執(zhí)行sql語句打印到控制臺的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 一個Java配置文件加密解密工具類分享

    一個Java配置文件加密解密工具類分享

    在 JavaEE 配置文件中,例如 XML 或者 properties 文件,由于某些敏感信息不希望普通人員看見,則可以采用加密的方式存儲,程序讀取后進行解密
    2014-04-04
  • Spring?Boot開發(fā)RESTful接口與http協(xié)議狀態(tài)表述

    Spring?Boot開發(fā)RESTful接口與http協(xié)議狀態(tài)表述

    這篇文章主要為大家介紹了Spring?Boot開發(fā)RESTful接口與http協(xié)議狀態(tài)表述,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • java實現(xiàn)鏈表反轉(zhuǎn)

    java實現(xiàn)鏈表反轉(zhuǎn)

    這篇文章主要為大家詳細介紹了java實現(xiàn)鏈表反轉(zhuǎn),分別通過迭代法、遞歸法實現(xiàn)java鏈表反轉(zhuǎn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Spring實現(xiàn)Quartz自動配置的方法詳解

    Spring實現(xiàn)Quartz自動配置的方法詳解

    這篇文章主要介紹了Spring實現(xiàn)Quartz自動配置的方法詳解,如果想在應(yīng)用中使用Quartz任務(wù)調(diào)度功能,可以通過Spring Boot實現(xiàn)Quartz的自動配置,以下介紹如何開啟Quartz自動配置,以及Quartz自動配置的實現(xiàn)過程,需要的朋友可以參考下
    2023-11-11
  • java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實例詳解

    java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實例詳解

    在本篇文章里小編給大家分享的是關(guān)于java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實例內(nèi)容,需要的朋友們可以學(xué)習(xí)下。
    2020-05-05

最新評論