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

詳解Java 中泛型的實現(xiàn)原理

 更新時間:2021年03月03日 14:41:12   作者:robothy  
這篇文章主要介紹了詳解Java 中泛型的實現(xiàn)原理,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下

泛型是 Java 開發(fā)中常用的技術(shù),了解泛型的幾種形式和實現(xiàn)泛型的基本原理,有助于寫出更優(yōu)質(zhì)的代碼。本文總結(jié)了 Java 泛型的三種形式以及泛型實現(xiàn)原理。

泛型

泛型的本質(zhì)是對類型進行參數(shù)化,在代碼邏輯不關(guān)注具體的數(shù)據(jù)類型時使用。例如:實現(xiàn)一個通用的排序算法,此時關(guān)注的是算法本身,而非排序的對象的類型。

泛型方法

如下定義了一個泛型方法, 聲明了一個類型變量,它可以應(yīng)用于參數(shù),返回值,和方法內(nèi)的代碼邏輯。

class GenericMethod{
 public <T> T[] sort(T[] elements){
  return elements;
 }
}

泛型類

與泛型方法類似,泛型類也需要聲明類型變量,只不過位置放在了類名后面,作用的范圍包括了當(dāng)前中的成員變量類型,方法參數(shù)類型,方法返回類型,以及方法內(nèi)的代碼中。

子類繼承泛型類時或者實例化泛型類的對象時,需要指定具體的參數(shù)類型或者聲明一個參數(shù)變量。如下,SubGenericClass 繼承了泛型類 GenericClass,其中類型變量 ID 的值為 Integer,同時子類聲明了另一個類型變量 E,并將E 填入了父類聲明的 T 中。

class GenericClass<ID, T>{
 
}

class SubGenericClass<T> extends GenericClass<Integer, T>{
 
}

泛型接口

泛型接口與泛型類類似,也需要在接口名后面聲明類型變量,作用于接口中的抽象方法返回類型和參數(shù)類型。子類在實現(xiàn)泛型接口時需要填入具體的數(shù)據(jù)類型或者填入子類聲明的類型變量。

interface GenericInterface<T> {
 T append(T seg);
}

泛型的基本原理

泛型本質(zhì)是將數(shù)據(jù)類型參數(shù)化,它通過擦除的方式來實現(xiàn)。聲明了泛型的 .java 源代碼,在編譯生成 .class 文件之后,泛型相關(guān)的信息就消失了??梢哉J(rèn)為,源代碼中泛型相關(guān)的信息,就是提供給編譯器用的。泛型信息對 Java 編譯器可以見,對 Java 虛擬機不可見。

Java 編譯器通過如下方式實現(xiàn)擦除:

  • 用 Object 或者界定類型替代泛型,產(chǎn)生的字節(jié)碼中只包含了原始的類,接口和方法;
  • 在恰當(dāng)?shù)奈恢貌迦霃娭妻D(zhuǎn)換代碼來確保類型安全;
  • 在繼承了泛型類或接口的類中插入橋接方法來保留多態(tài)性。

Java 官方文檔原文

Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.

下面通過具體代碼來說明 Java 中的類型擦除。

實驗原理:先用 javac 將 .java 文件編譯成 .class 文件,再使用反編譯工具 jad 將 .class 文件反編成回 Java 代碼,反編譯出來的 Java 代碼內(nèi)容反映的即為 .class 文件中的信息。

如下源代碼,定義 User 類,實現(xiàn)了 Comparable 接口,類型參數(shù)填入 User,實現(xiàn) compareTo 方法。

class User implements Comparable<User> {
 String name;
	
 public int compareTo(User other){
  return this.name.compareTo(other.name);
 }
}

JDK 中 Comparable 接口源碼內(nèi)容如下:

package java.lang;
public interface Comparable<T>{
 int compareTo(T o);
}

我們首先反編譯它的接口,Comparable 接口的字節(jié)碼文件,可以在 $JRE_HOME/lib/rt.jar 中找到,將它復(fù)制到某個目錄。使用 jad.exe(需要另外安裝)反編譯這個 Comparable.class 文件。

$ jad Comparable.class

反編譯出來的內(nèi)容放在 Comparable.jad 文件中,文件內(nèi)容如下:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: Comparable.java

package java.lang;

// Referenced classes of package java.lang:
//   Object

public interface Comparable
{

 public abstract int compareTo(Object obj);
}

對比源代碼 Comparable.java 和反編譯代碼 Comparable.jad 的內(nèi)容不難發(fā)現(xiàn),反編譯之后的內(nèi)容中已經(jīng)沒有了類型變量 T 。compareTo 方法中的參數(shù)類型 T 也被替換成了 Object。這就符合上面提到的第 1 條擦除原則。這里演示的是用 Object 替換類型參數(shù),使用界定類型替換類型參數(shù)的例子可以反編譯一下 Collections.class 試試,里面使用了大量的泛型。

使用 javac.exe 將 User.java 編譯成 .class 文件,然后使用 jad 將 .class 文件反編譯成 Java 代碼。

$ javac User.java
$ jad User.class

User.jad 文件內(nèi)容如下:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: User.java


class User
 implements Comparable
{

 User()
 {
 }

 public int compareTo(User user)
 {
  return name.compareTo(user.name);
 }

 // 橋接方法
 public volatile int compareTo(Object obj)
 {
  return compareTo((User)obj);
 }

 String name;
}

對比編輯的源代碼 User.java 和反編譯出來的代碼 User.jad,容易發(fā)現(xiàn):類型參數(shù)沒有了,多了一個無參構(gòu)造方法,多了一個 compareTo(Object obj) 方法,這個就是橋接方法,還可以發(fā)現(xiàn)參數(shù) obj 被強轉(zhuǎn)成 User 再傳入 compareTo(User user) 方法。通過這些內(nèi)容可以看到擦除規(guī)則 2 和規(guī)則 3 的實現(xiàn)方式。

強轉(zhuǎn)規(guī)則比較好理解,因為泛型被替換成了 Object,要調(diào)用具體類型的方法或者成員變量,當(dāng)然需要先強轉(zhuǎn)成具體類型才能使用。那么插入的橋接方法該如何理解呢?

如果我們只按照下面方式去使用 User 類,這樣確實不需要參數(shù)類型為 Object 的橋接方法。

User user = new User();
User other = new User();
user.comparetTo(other);

但是,Java 中的多態(tài)特性允許我們使用一個父類或者接口的引用指向一個子類對象。

Comparable<User> user = new User();

而按照 Object 替換泛型參數(shù)原則,Comparable 接口中只有 compareTo(Object) 方法,假設(shè)沒有橋接方法,顯然如下代碼是不能運行的。所以 Java 編譯器需要為子類(泛型類的子類或泛型接口的實現(xiàn)類)中使用了泛型的方法額外生成一個橋接方法,通過這個方法來保證 Java 中的多態(tài)特性。

Comparable<User> user = new User();
Object other = new User();
user.compareTo(other);

而普通類中的泛型方法在進行類型擦除時不會產(chǎn)生橋接方法。例如:

class Dog{
 <T> void eat(T[] food){
 }
}

類型擦除之后變成了:

class Dog
{

 Dog()
 {
 }

 void eat(Object aobj[])
 {
 }
}

小結(jié)

Java 中的泛型有 3 種形式,泛型方法,泛型類,泛型接口。Java 通過在編譯時類型擦除的方式來實現(xiàn)泛型。擦除時使用 Object 或者界定類型替代泛型,同時在要調(diào)用具體類型方法或者成員變量的時候插入強轉(zhuǎn)代碼,為了保證多態(tài)特性,Java 編譯器還會為泛型類的子類生成橋接方法。類型信息在編譯階段被擦除之后,程序在運行期間無法獲取類型參數(shù)所對應(yīng)的具體類型。

參考

https://docs.oracle.com/javase/tutorial/java/generics/index.html

https://stackoverflow.com/questions/25040837/generics-bridge-method-on-polymorphism

以上就是詳解Java 中泛型的實現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于Java 泛型實現(xiàn)原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot中Elasticsearch的連接配置原理與使用詳解

    SpringBoot中Elasticsearch的連接配置原理與使用詳解

    Elasticsearch是一種開源的分布式搜索和數(shù)據(jù)分析引擎,它可用于全文搜索、結(jié)構(gòu)化搜索、分析等應(yīng)用場景,本文主要介紹了SpringBoot中Elasticsearch的連接配置原理與使用詳解,感興趣的可以了解一下
    2023-09-09
  • java實現(xiàn)文件和base64相互轉(zhuǎn)換

    java實現(xiàn)文件和base64相互轉(zhuǎn)換

    這篇文章主要為大家詳細(xì)介紹了java如何實現(xiàn)文件和base64相互轉(zhuǎn)換,文中的示例代碼講解詳細(xì),具有一定的參考價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11
  • SpringCloud網(wǎng)關(guān)(Zuul)如何給多個微服務(wù)之間傳遞共享參數(shù)

    SpringCloud網(wǎng)關(guān)(Zuul)如何給多個微服務(wù)之間傳遞共享參數(shù)

    這篇文章主要介紹了SpringCloud網(wǎng)關(guān)(Zuul)如何給多個微服務(wù)之間傳遞共享參數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 基于spring boot 1.5.4 集成 jpa+hibernate+jdbcTemplate(詳解)

    基于spring boot 1.5.4 集成 jpa+hibernate+jdbcTemplate(詳解)

    下面小編就為大家?guī)硪黄趕pring boot 1.5.4 集成 jpa+hibernate+jdbcTemplate(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • JavaWeb入門教程之分頁查詢功能的簡單實現(xiàn)

    JavaWeb入門教程之分頁查詢功能的簡單實現(xiàn)

    這篇文章主要介紹了JavaWeb入門教程之分頁查詢功能的簡單實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • SpringBoot項目解決跨域的四種方案分享

    SpringBoot項目解決跨域的四種方案分享

    在用SpringBoot開發(fā)后端服務(wù)時,我們一般是提供接口給前端使用,但前端通過瀏覽器調(diào)我們接口時,瀏覽器會有個同源策略的限制,即協(xié)議,域名,端口任一不一樣時都會導(dǎo)致跨域,這篇文章主要介紹跨域的幾種常用解決方案,希望對大家有所幫助
    2023-05-05
  • 基于Tomcat7、Java、WebSocket的服務(wù)器推送聊天室實例

    基于Tomcat7、Java、WebSocket的服務(wù)器推送聊天室實例

    HTML5 WebSocket實現(xiàn)了服務(wù)器與瀏覽器的雙向通訊,本篇文章主要介紹了基于Tomcat7、Java、WebSocket的服務(wù)器推送聊天室實例,具有一定的參考價值,有興趣的可以了解一下。
    2016-12-12
  • MyBatis中ResultMap與多表查詢的處理方法

    MyBatis中ResultMap與多表查詢的處理方法

    這篇文章主要介紹了MyBatis中ResultMap與多表查詢的處理方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • idea啟動報錯:Command line is too long問題

    idea啟動報錯:Command line is too long問題

    在使用IDEA時,若遇到"Commandlineistoolong"錯誤,通常是因為命令行長度超限,這是因為IDEA通過命令行或文件將classpath傳遞至JVM,操作系統(tǒng)對命令行長度有限制,解決方法是切換至動態(tài)類路徑,通過修改項目的workspace.xml文件
    2024-09-09
  • java實現(xiàn)圖片分割指定大小

    java實現(xiàn)圖片分割指定大小

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)圖片分割指定大小,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論

梓潼县| 固原市| 荆门市| 特克斯县| 黑水县| 海南省| 陆丰市| 黎平县| 错那县| 祥云县| 丰都县| 吉水县| 苏尼特右旗| 新源县| 仁寿县| 岳阳市| 上饶县| 绥化市| 江孜县| 万全县| 鄂州市| 阿拉善左旗| 浪卡子县| 那坡县| 石家庄市| 洪雅县| 斗六市| 云梦县| 南华县| 江阴市| 桐柏县| 湄潭县| 镇宁| 新余市| 交口县| 利津县| 同仁县| 中山市| 岗巴县| 潼关县| 盐津县|