日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

深入理解 Java 泛型擦除机制

發(fā)布時間:2024/9/30 java 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解 Java 泛型擦除机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

我們都知道 Java 中的泛型可以在編譯期對類型檢查,避免類型強(qiáng)制轉(zhuǎn)化帶來的問題,保證代碼的健壯性。不同語言對泛型的支持也不一樣,Java 中的泛型類型在編譯期會擦除,下面一個例子可以證明這一點:

public static void main(String[] args) throws Exception {List<String> list = new ArrayList<>();list.add("abc");Class<? extends List> listClass = list.getClass();Method addMethod = listClass.getMethod("add", Object.class);addMethod.invoke(list, 10);System.out.println(list.size());}

上面這個例子中定義了一個 String 類型的集合,通過反射獲取 add 方法并調(diào)用該方法添加了一個 int 類型的元素,代碼執(zhí)行過程中并不會出現(xiàn)異常,而且能正常輸出 size = 2。

因為泛型會被擦除,所以很多人都認(rèn)為在代碼運行期間是無法得知泛型參數(shù)類型的。最近重溫 Java 基礎(chǔ)語法的時候,Java Reflection - Generics 在文章開頭認(rèn)為這種結(jié)論不是很準(zhǔn)確,因為通過反射可以獲取到泛型的具體類型,就像下面這樣:

public class GenericsSamples {public static List<String> getStringList() {return new ArrayList<>();}public static void main(String[] args) throws NoSuchMethodException {Method method = GenericsSamples.class.getMethod("getStringList", null);Type returnType = method.getGenericReturnType();if (returnType instanceof ParameterizedType) {ParameterizedType type = (ParameterizedType) returnType;Type[] typeArguments = type.getActualTypeArguments();for (Type typeArgument : typeArguments) {Class<?> typeArgClass = (Class<?>) typeArgument;System.out.println("typeArgClass = " + typeArgClass);}}} }

typeArgClass 輸出的類型為 class java.lang.String,為什么編譯期間被擦除的泛型,在代碼運行期間能獲取到呢?原因是為了讓虛擬機(jī)解析泛型類型,在虛擬機(jī)規(guī)范里引入了 LocalVariableTypeTable 屬性,我們可以通過 javap -v class 反編譯方式查看。

public class GenericsDemo {public static void main(String[] args) {List<String> stringList = new ArrayList<>();List<Integer> integerList = new ArrayList<>();System.out.println(stringList.getClass().equals(integerList.getClass()));} }

反編譯上面 GenericsDemo 的 class 文件,main 方法編譯信息如下:

從上面的編譯信息可以看出屬性 LocalVariableTypeTable 的 Signature 中保存了泛型的類型信息,因此我們可以通過反射在運行階段獲取到它。到這里可能會有人有個疑問:泛型不是被擦除了嗎,為啥還能保存到 Signature 中,原因是它和我們所說的泛型擦除是兩碼事,下面再來看一個例子:

public class GenericSamples<T> {private T param;public T getParam() { return param; }public void setParam(T param) { this.param = param; }public static void main(String[] args) {GenericSamples<Integer> integerGenericSamples = new GenericSamples<>();integerGenericSamples.setParam(10);System.out.println(integerGenericSamples.getParam());} }

下面是 get 與 set 方法反編譯的結(jié)果:


set 與 get 方法通過反編譯后并不會保留類型信息,統(tǒng)一處理成了 Object,這個才是我們通常所說的泛型擦除,由于被編譯器當(dāng)作 Object 類型處理,那么我們就可以通過反射 set 任意類型的參數(shù)。

和 LocalVariableTypeTable 類似的還有一個 LocalVariableTable,不同的地方在于前者的 Signature 相較于后者的 descriptor 保存了泛型信息,關(guān)于這兩個屬性更多的介紹可以查看官方的介紹:4.7.13. The LocalVariableTable Attribute。

參考:

Java Reflection - Generics
深入探索Java泛型的本質(zhì) | 泛型

總結(jié)

以上是生活随笔為你收集整理的深入理解 Java 泛型擦除机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。