日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

【Java 泛型】使用上下边界通配符解决泛型擦除问题

發(fā)布時間:2025/6/17 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Java 泛型】使用上下边界通配符解决泛型擦除问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 一、使用上邊界通配符示例
  • 二、分析字節(jié)碼的附加信息

前言

上一篇博客 【Java 泛型】泛型用法 ( 泛型編譯期擦除 | 上界通配符 <? extends T> | 下界通配符 <? super T> ) 一、泛型擦除 章節(jié)中 , 講到了泛型擦除問題 , 泛型只保留到了編譯階段 , 運(yùn)行時就沒有泛型的限制了 ;

本篇博客中介紹一種方法 , 使用上下邊界通配符解決泛型擦除問題 ;





一、使用上邊界通配符示例



接口類 :

public interface Data <T>{void set(T t);T get(); }

實(shí)現(xiàn)類 :

public class DataImpl<T extends Person> implements Data<T>{private T t;@Overridepublic void set(T t) {}@Overridepublic T get() {return null;} }

反編譯查看 實(shí)現(xiàn)類的 字節(jié)碼的信息 : 發(fā)現(xiàn)分別有 222 個 get 和 set 方法 ;

使用

javap -p DataImpl.class

命令 , 反編譯 DataImpl.class 字節(jié)碼文件 , 查看類中的主要方法 ;


D:\002_Project\004_Java_Learn\Main\out\production\Main>javap -p DataImpl.class Compiled from "DataImpl.java" public class DataImpl<T extends Person> implements Data<T> {private T t;public DataImpl();public void set(T);public T get();public java.lang.Object get();public void set(java.lang.Object); }

下面的 222 個方法 , 明顯不符合 Java 語法規(guī)范 , 方法名和參數(shù)一樣 ;

public T get();public java.lang.Object get();



二、分析字節(jié)碼的附加信息



下面分析字節(jié)碼詳細(xì)信息 ;

使用

javap -v DataImpl.class

命令 , 查看詳細(xì)的字節(jié)碼附加信息 ;

D:\002_Project\004_Java_Learn\Main\out\production\Main>javap -v DataImpl.class Classfile /D:/002_Project/004_Java_Learn/Main/out/production/Main/DataImpl.classLast modified 2021-9-7; size 907 bytesMD5 checksum 90421d2a83f40d38de81c4c7f3cf341bCompiled from "DataImpl.java" public class DataImpl<T extends Person> extends java.lang.Object implements Data<T>minor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER Constant pool:#1 = Methodref #6.#32 // java/lang/Object."<init>":()V#2 = Methodref #5.#33 // DataImpl.get:()LPerson;#3 = Class #34 // Person#4 = Methodref #5.#35 // DataImpl.set:(LPerson;)V#5 = Class #36 // DataImpl#6 = Class #37 // java/lang/Object#7 = Class #38 // Data#8 = Utf8 t#9 = Utf8 LPerson;#10 = Utf8 Signature#11 = Utf8 TT;#12 = Utf8 <init>#13 = Utf8 ()V#14 = Utf8 Code#15 = Utf8 LineNumberTable#16 = Utf8 LocalVariableTable#17 = Utf8 this#18 = Utf8 LDataImpl;#19 = Utf8 LocalVariableTypeTable#20 = Utf8 LDataImpl<TT;>;#21 = Utf8 set#22 = Utf8 (LPerson;)V#23 = Utf8 (TT;)V#24 = Utf8 get#25 = Utf8 ()LPerson;#26 = Utf8 ()TT;#27 = Utf8 ()Ljava/lang/Object;#28 = Utf8 (Ljava/lang/Object;)V#29 = Utf8 <T:LPerson;>Ljava/lang/Object;LData<TT;>;#30 = Utf8 SourceFile#31 = Utf8 DataImpl.java#32 = NameAndType #12:#13 // "<init>":()V#33 = NameAndType #24:#25 // get:()LPerson;#34 = Utf8 Person#35 = NameAndType #21:#22 // set:(LPerson;)V#36 = Utf8 DataImpl#37 = Utf8 java/lang/Object#38 = Utf8 Data {public DataImpl();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this LDataImpl;LocalVariableTypeTable:Start Length Slot Name Signature0 5 0 this LDataImpl<TT;>;public void set(T);descriptor: (LPerson;)Vflags: ACC_PUBLICCode:stack=0, locals=2, args_size=20: returnLineNumberTable:line 7: 0LocalVariableTable:Start Length Slot Name Signature0 1 0 this LDataImpl;0 1 1 t LPerson;LocalVariableTypeTable:Start Length Slot Name Signature0 1 0 this LDataImpl<TT;>;0 1 1 t TT;Signature: #23 // (TT;)Vpublic T get();descriptor: ()LPerson;flags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aconst_null1: areturnLineNumberTable:line 11: 0LocalVariableTable:Start Length Slot Name Signature0 2 0 this LDataImpl;LocalVariableTypeTable:Start Length Slot Name Signature0 2 0 this LDataImpl<TT;>;Signature: #26 // ()TT;public java.lang.Object get();descriptor: ()Ljava/lang/Object;flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETICCode:stack=1, locals=1, args_size=10: aload_01: invokevirtual #2 // Method get:()LPerson;4: areturnLineNumberTable:line 1: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this LDataImpl;LocalVariableTypeTable:Start Length Slot Name Signature0 5 0 this LDataImpl<TT;>;public void set(java.lang.Object);descriptor: (Ljava/lang/Object;)Vflags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETICCode:stack=2, locals=2, args_size=20: aload_01: aload_12: checkcast #3 // class Person5: invokevirtual #4 // Method set:(LPerson;)V8: returnLineNumberTable:line 1: 0LocalVariableTable:Start Length Slot Name Signature0 9 0 this LDataImpl;LocalVariableTypeTable:Start Length Slot Name Signature0 9 0 this LDataImpl<TT;>; } Signature: #29 // <T:LPerson;>Ljava/lang/Object;LData<TT;>; SourceFile: "DataImpl.java"

主要分析 下面 222 個方法的詳細(xì)字節(jié)碼數(shù)據(jù) ;

public void set(T); public void set(java.lang.Object);

public void set(T) 方法的字節(jié)碼詳細(xì)數(shù)據(jù)如下 :

public void set(T);descriptor: (LPerson;)Vflags: ACC_PUBLICCode:stack=0, locals=2, args_size=20: returnLineNumberTable:line 7: 0LocalVariableTable:Start Length Slot Name Signature0 1 0 this LDataImpl;0 1 1 t LPerson;LocalVariableTypeTable:Start Length Slot Name Signature0 1 0 this LDataImpl<TT;>;0 1 1 t TT;Signature: #23 // (TT;)V

public void set(java.lang.Object) 的字節(jié)碼詳細(xì)數(shù)據(jù)如下 : 該方法是橋接方法 ;

public void set(java.lang.Object);descriptor: (Ljava/lang/Object;)Vflags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETICCode:stack=2, locals=2, args_size=20: aload_01: aload_12: checkcast #3 // class Person5: invokevirtual #4 // Method set:(LPerson;)V8: returnLineNumberTable:line 1: 0LocalVariableTable:Start Length Slot Name Signature0 9 0 this LDataImpl;LocalVariableTypeTable:Start Length Slot Name Signature0 9 0 this LDataImpl<TT;>;

分析 public void set(java.lang.Object) 方法 :

該方法傳入 Object 類型 , 所有的類都是 Object 子類 ;

descriptor: (Ljava/lang/Object;)V 說明該方法的參數(shù)是 Ljava/lang/Object; 類型 , 返回值是 void 類型 ;

ACC_BRIDGE 標(biāo)識 標(biāo)明 該該方法是一個橋接方法 ;

0: aload_0 從局部變量 0 裝載引用類型值到操作數(shù)棧 ;

1: aload_1 從局部變量 1 裝載引用類型值到操作數(shù)棧 ;

2: checkcast #3 檢查該值是否是常量值 #3 的引用 , 也就是檢查參數(shù)中傳入的 Object 參數(shù)是否是 Person 類型 ;

Constant pool:#3 = Class #34 // Person

5: invokevirtual #4 如果上一步檢查 , 傳入的參數(shù)是 Person 類型 , 就調(diào)用常量池中的 #4 常量對應(yīng)的方法 , 也就是實(shí)際的 public void set(T) 方法 ;

Constant pool:#4 = Methodref #5.#35 // DataImpl.set:(LPerson;)V

通過 上下邊界 通配符 解決 泛型擦除問題 ;

總結(jié)

以上是生活随笔為你收集整理的【Java 泛型】使用上下边界通配符解决泛型擦除问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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