亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

詳解Java 中泛型的實現原理

瀏覽:28日期:2022-08-15 17:25:24

泛型是 Java 開發中常用的技術,了解泛型的幾種形式和實現泛型的基本原理,有助于寫出更優質的代碼。本文總結了 Java 泛型的三種形式以及泛型實現原理。

泛型

泛型的本質是對類型進行參數化,在代碼邏輯不關注具體的數據類型時使用。例如:實現一個通用的排序算法,此時關注的是算法本身,而非排序的對象的類型。

泛型方法

如下定義了一個泛型方法, 聲明了一個類型變量,它可以應用于參數,返回值,和方法內的代碼邏輯。

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

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

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

class GenericClass<ID, T>{ }class SubGenericClass<T> extends GenericClass<Integer, T>{ }泛型接口

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

interface GenericInterface<T> { T append(T seg);}泛型的基本原理

泛型本質是將數據類型參數化,它通過擦除的方式來實現。聲明了泛型的 .java 源代碼,在編譯生成 .class 文件之后,泛型相關的信息就消失了。可以認為,源代碼中泛型相關的信息,就是提供給編譯器用的。泛型信息對 Java 編譯器可以見,對 Java 虛擬機不可見。

Java 編譯器通過如下方式實現擦除:

用 Object 或者界定類型替代泛型,產生的字節碼中只包含了原始的類,接口和方法; 在恰當的位置插入強制轉換代碼來確保類型安全; 在繼承了泛型類或接口的類中插入橋接方法來保留多態性。

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 代碼內容反映的即為 .class 文件中的信息。

如下源代碼,定義 User 類,實現了 Comparable 接口,類型參數填入 User,實現 compareTo 方法。

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

JDK 中 Comparable 接口源碼內容如下:

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

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

$ jad Comparable.class

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

// 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.javapackage java.lang;// Referenced classes of package java.lang:// Objectpublic interface Comparable{ public abstract int compareTo(Object obj);}

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

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

$ javac User.java$ jad User.class

User.jad 文件內容如下:

// 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.javaclass 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,容易發現:類型參數沒有了,多了一個無參構造方法,多了一個 compareTo(Object obj) 方法,這個就是橋接方法,還可以發現參數 obj 被強轉成 User 再傳入 compareTo(User user) 方法。通過這些內容可以看到擦除規則 2 和規則 3 的實現方式。

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

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

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

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

Comparable<User> user = new User();

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

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

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

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

類型擦除之后變成了:

class Dog{ Dog() { } void eat(Object aobj[]) { }}小結

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

參考

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

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

以上就是詳解Java 中泛型的實現原理的詳細內容,更多關于Java 泛型實現原理的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 精品五夜婷香蕉国产线看观看 | 日韩精品一区二区在线观看 | 97视频在线观看视频在线精品 | 欧美黄色第一页 | 一区精品麻豆入口 | 夜色www国产精品资源站 | 香蕉视频三级 | 久久这里只有精品国产 | 黑人狂躁日本妞 | 成人一级黄色大片 | 国产1024精品视频专区免费 | 成人网免费观看 | 免费国产黄 | 中文字幕亚洲第一 | 久久99国产精品久久99 | 国产激情在线 | 又刺激又黄的一级毛片 | 中文字幕第一页在线 | 欧美三级短视频 | 欧美一级淫片a免费播放口aaa | 在线播放高清国语自产拍免费 | 国产日韩不卡免费精品视频 | 色婷婷影院 | 国产亚洲精品美女 | 欧美第二区 | 超级97碰碰碰碰久久久久最新 | 三级国产精品 | 91麻豆精品国产自产在线 | 久久婷婷综合中文字幕 | 色综合亚洲天天综合网站 | 国产精品一区二区综合 | 91视频第一页 | 国产一区二区在免费观看 | 亚洲国产精品乱码在线观看97 | 久久精品视 | 99久久免费看精品国产一区 | 最新黄色地址 | 永久国产 | 调教套上奶牛榨乳器喷奶水 | 最新黄色网址在线观看 | 黄色网久久|