前言
经常会看到 “泛型会在编译期擦除,但是运行时可以获取到”,自己也有过这样的疑惑。此处做一下笔记,记录一下认识和理解。
一、泛型概述
可以参照本文 Java 泛型,你了解类型擦除吗?
二、获取泛型类型
3.1、demo
参照本文Java通过反射获取泛型实际类型总结(什么可获取,什么不可获取)
文章中列出了几种可以通过反射在 runtime 获取泛型类型的情况:
package bean;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestCache extends LocalCache {
private Map map = new HashMap<>();
public TestCache(Map map) {
}
public void set(List list) {
}
public List get() {
return null;
}
public static void main(String[] args) throws Exception {
System.out.println("获取属性上的泛型: ");
getFieldType();
System.out.println("获取方法参数中的泛型类型: ");
getMethodParamsType();
System.out.println("获取方法返回值中的泛型类型: ");
getMethodReturnType();
System.out.println("获取构造方法中参数的泛型类型: ");
getConstructorParamsType();
System.out.println("获取当前类的直接父类上设置的泛型类型: ");
getClassType();
}
/**
* 获取属性的泛型类型
*
* @throws Exception
*/
private static void getFieldType() throws Exception {
Field field = TestCache.class.getDeclaredField("map");
field.setAccessible(true);
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Type[] typeList = parameterizedType.getActualTypeArguments();
for (Type type : typeList) {
System.out.println(type.getTypeName());
}
}
}
/**
* 获取方法参数中的泛型类型
*
* @throws Exception
*/
public static void getMethodParamsType() throws Exception {
Method method = TestCache.class.getDeclaredMethod("set", List.class);
Type[] types = method.getGenericParameterTypes();
if (types[0] instanceof ParameterizedType) {
System.out.println(((ParameterizedType) (types[0])).getActualTypeArguments()[0]);
}
}
/**
* 获取方法返回值中的泛型类型
*
* @throws Exception
*/
public static void getMethodReturnType() throws Exception {
Method method = TestCache.class.getDeclaredMethod("get");
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
System.out.println(((ParameterizedType) (genericReturnType)).getActualTypeArguments()[0]);
}
}
/**
* 获取构造方法中参数的泛型类型
*
* @throws Exception
*/
public static void getConstructorParamsType() throws Exception {
Constructor constructor = TestCache.class.getConstructor(Map.class);
Type[] genericParameterTypes = constructor.getGenericParameterTypes();
Type[] typeList = ((ParameterizedType) (genericParameterTypes[0])).getActualTypeArguments();
for (Type type : typeList) {
System.out.println(type.getTypeName());
}
}
/**
* 获取当前类的直接父类上设置的泛型类型
*/
public static void getClassType() {
Type genType = TestCache.class.getGenericSuperclass();
Type type = ((ParameterizedType) genType).getActualTypeArguments()[0];
System.out.println(type);
}
}
我个人理解:
能从 class 文件中找到的泛型,都可以在 runtime 通过反射获取到,下面看一下 class 文件中哪些地方记录了泛型的类型。
3.2、class 文件一览
3.2.1、class 文件内容
~/Documents/projects/java-go/target/classes/bean javap -v TestCache.class
Classfile /Users/dongbaowen/Documents/projects/java-go/target/classes/bean/TestCache.class
Last modified 2021年2月11日; size 3721 bytes
SHA-256 checksum 4d46ed7b93a4e7d51f9e3aa7e65832b01b342f11622a3ab0d52b64a5ccebbbb7
Compiled from "TestCache.java"
public class bean.TestCache extends bean.LocalCache
minor version: 0
major version: 52
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #6 // bean/TestCache
super_class: #35 // bean/LocalCache
interfaces: 0, fields: 1, methods: 9, attributes: 2
Constant pool:
#1 = Methodref #35.#97 // bean/LocalCache."":()V
#2 = Class #98 // java/util/HashMap
#3 = Methodref #2.#97 // java/util/HashMap."":()V
#4 = Fieldref #6.#99 // bean/TestCache.map:Ljava/util/Map;
#5 = Methodref #6.#100 // bean/TestCache.getConstructorParamsType:()V
#6 = Class #101 // bean/TestCache
#7 = String #36 // map
#8 = Methodref #16.#102 // java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;
#9 = Methodref #103.#104 // java/lang/reflect/Field.setAccessible:(Z)V
#10 = Methodref #103.#105 // java/lang/reflect/Field.getGenericType:()Ljava/lang/reflect/Type;
#11 = Class #106 // java/lang/reflect/ParameterizedType
#12 = Fieldref #107.#108 // java/lang/System.out:Ljava/io/PrintStream;
#13 = InterfaceMethodref #11.#109 // java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
#14 = Methodref #110.#111 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#15 = String #50 // set
#16 = Class #112 // java/lang/Class
#17 = Class #113 // java/util/List
#18 = Methodref #16.#114 // java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
#19 = Methodref #115.#116 // java/lang/reflect/Method.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
#20 = Class #117 // java/lang/StringBuilder
#21 = Methodref #20.#97 // java/lang/StringBuilder."":()V
#22 = String #118 // genericParameterTypes=
#23 = Methodref #20.#119 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#24 = Methodref #20.#120 // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
#25 = Methodref #20.#121 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#26 = Methodref #110.#122 // java/io/PrintStream.println:(Ljava/lang/String;)V
#27 = String #56 // get
#28 = Methodref #115.#123 // java/lang/reflect/Method.getGenericReturnType:()Ljava/lang/reflect/Type;
#29 = String #124 // genericReturnType=
#30 = Class #125 // java/util/Map
#31 = Methodref #16.#126 // java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
#32 = Methodref #127.#116 // java/lang/reflect/Constructor.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
#33 = Methodref #16.#128 // java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
#34 = String #129 // params=
#35 = Class #130 // bean/LocalCache
#36 = Utf8 map
#37 = Utf8 Ljava/util/Map;
#38 = Utf8 Signature
#39 = Utf8 Ljava/util/Map;
#40 = Utf8
#41 = Utf8 (Ljava/util/Map;)V
#42 = Utf8 Code
#43 = Utf8 LineNumberTable
#44 = Utf8 LocalVariableTable
#45 = Utf8 this
#46 = Utf8 Lbean/TestCache;
#47 = Utf8 LocalVariableTypeTable
#48 = Utf8 Ljava/util/Map;
#49 = Utf8 (Ljava/util/Map;)V
#50 = Utf8 set
#51 = Utf8 (Ljava/util/List;)V
#52 = Utf8 list
#53 = Utf8 Ljava/util/List;
#54 = Utf8 Ljava/util/List;
#55 = Utf8 (Ljava/util/List;)V
#56 = Utf8 get
#57 = Utf8 ()Ljava/util/List;
#58 = Utf8 ()Ljava/util/List;
#59 = Utf8 main
#60 = Utf8 ([Ljava/lang/String;)V
#61 = Utf8 args
#62 = Utf8 [Ljava/lang/String;
#63 = Utf8 Exceptions
#64 = Class #131 // java/lang/Exception
#65 = Utf8 getFieldType
#66 = Utf8 ()V
#67 = Utf8 parameterizedType
#68 = Utf8 Ljava/lang/reflect/ParameterizedType;
#69 = Utf8 field
#70 = Utf8 Ljava/lang/reflect/Field;
#71 = Utf8 genericType
#72 = Utf8 Ljava/lang/reflect/Type;
#73 = Utf8 StackMapTable
#74 = Class #132 // java/lang/reflect/Field
#75 = Class #133 // java/lang/reflect/Type
#76 = Utf8 getMethodParamsType
#77 = Utf8 method
#78 = Utf8 Ljava/lang/reflect/Method;
#79 = Utf8 types
#80 = Utf8 [Ljava/lang/reflect/Type;
#81 = Class #134 // java/lang/reflect/Method
#82 = Class #80 // "[Ljava/lang/reflect/Type;"
#83 = Utf8 getMethodReturnType
#84 = Utf8 genericReturnType
#85 = Utf8 getConstructorParamsType
#86 = Utf8 constructor
#87 = Utf8 Ljava/lang/reflect/Constructor;
#88 = Utf8 genericParameterTypes
#89 = Utf8 type
#90 = Utf8 Ljava/lang/reflect/Constructor;
#91 = Utf8 getClassType
#92 = Utf8 genType
#93 = Utf8 params
#94 = Utf8 Lbean/LocalCache;
#95 = Utf8 SourceFile
#96 = Utf8 TestCache.java
#97 = NameAndType #40:#66 // "":()V
#98 = Utf8 java/util/HashMap
#99 = NameAndType #36:#37 // map:Ljava/util/Map;
#100 = NameAndType #85:#66 // getConstructorParamsType:()V
#101 = Utf8 bean/TestCache
#102 = NameAndType #135:#136 // getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;
#103 = Class #132 // java/lang/reflect/Field
#104 = NameAndType #137:#138 // setAccessible:(Z)V
#105 = NameAndType #139:#140 // getGenericType:()Ljava/lang/reflect/Type;
#106 = Utf8 java/lang/reflect/ParameterizedType
#107 = Class #141 // java/lang/System
#108 = NameAndType #142:#143 // out:Ljava/io/PrintStream;
#109 = NameAndType #144:#145 // getActualTypeArguments:()[Ljava/lang/reflect/Type;
#110 = Class #146 // java/io/PrintStream
#111 = NameAndType #147:#148 // println:(Ljava/lang/Object;)V
#112 = Utf8 java/lang/Class
#113 = Utf8 java/util/List
#114 = NameAndType #149:#150 // getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
#115 = Class #134 // java/lang/reflect/Method
#116 = NameAndType #151:#145 // getGenericParameterTypes:()[Ljava/lang/reflect/Type;
#117 = Utf8 java/lang/StringBuilder
#118 = Utf8 genericParameterTypes=
#119 = NameAndType #152:#153 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#120 = NameAndType #152:#154 // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
#121 = NameAndType #155:#156 // toString:()Ljava/lang/String;
#122 = NameAndType #147:#157 // println:(Ljava/lang/String;)V
#123 = NameAndType #158:#140 // getGenericReturnType:()Ljava/lang/reflect/Type;
#124 = Utf8 genericReturnType=
#125 = Utf8 java/util/Map
#126 = NameAndType #159:#160 // getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
#127 = Class #161 // java/lang/reflect/Constructor
#128 = NameAndType #162:#140 // getGenericSuperclass:()Ljava/lang/reflect/Type;
#129 = Utf8 params=
#130 = Utf8 bean/LocalCache
#131 = Utf8 java/lang/Exception
#132 = Utf8 java/lang/reflect/Field
#133 = Utf8 java/lang/reflect/Type
#134 = Utf8 java/lang/reflect/Method
#135 = Utf8 getDeclaredField
#136 = Utf8 (Ljava/lang/String;)Ljava/lang/reflect/Field;
#137 = Utf8 setAccessible
#138 = Utf8 (Z)V
#139 = Utf8 getGenericType
#140 = Utf8 ()Ljava/lang/reflect/Type;
#141 = Utf8 java/lang/System
#142 = Utf8 out
#143 = Utf8 Ljava/io/PrintStream;
#144 = Utf8 getActualTypeArguments
#145 = Utf8 ()[Ljava/lang/reflect/Type;
#146 = Utf8 java/io/PrintStream
#147 = Utf8 println
#148 = Utf8 (Ljava/lang/Object;)V
#149 = Utf8 getDeclaredMethod
#150 = Utf8 (Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
#151 = Utf8 getGenericParameterTypes
#152 = Utf8 append
#153 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#154 = Utf8 (Ljava/lang/Object;)Ljava/lang/StringBuilder;
#155 = Utf8 toString
#156 = Utf8 ()Ljava/lang/String;
#157 = Utf8 (Ljava/lang/String;)V
#158 = Utf8 getGenericReturnType
#159 = Utf8 getConstructor
#160 = Utf8 ([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
#161 = Utf8 java/lang/reflect/Constructor
#162 = Utf8 getGenericSuperclass
{
public bean.TestCache(java.util.Map);
descriptor: (Ljava/util/Map;)V
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method bean/LocalCache."":()V
4: aload_0
5: new #2 // class java/util/HashMap
8: dup
9: invokespecial #3 // Method java/util/HashMap."":()V
12: putfield #4 // Field map:Ljava/util/Map;
15: return
LineNumberTable:
line 20: 0
line 18: 4
line 21: 15
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lbean/TestCache;
0 16 1 map Ljava/util/Map;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 16 1 map Ljava/util/Map;
Signature: #49 // (Ljava/util/Map;)V
public void set(java.util.List);
descriptor: (Ljava/util/List;)V
flags: (0x0001) ACC_PUBLIC
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 25: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this Lbean/TestCache;
0 1 1 list Ljava/util/List;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 1 1 list Ljava/util/List;
Signature: #55 // (Ljava/util/List;)V
public java.util.List get();
descriptor: ()Ljava/util/List;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aconst_null
1: areturn
LineNumberTable:
line 28: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this Lbean/TestCache;
Signature: #58 // ()Ljava/util/List;
public static void main(java.lang.String[]) throws java.lang.Exception;
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: invokestatic #5 // Method getConstructorParamsType:()V
3: return
LineNumberTable:
line 32: 0
line 33: 3
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 args [Ljava/lang/String;
Exceptions:
throws java.lang.Exception
public static void getMethodParamsType() throws java.lang.Exception;
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=6, locals=2, args_size=0
0: ldc #6 // class bean/TestCache
2: ldc #15 // String set
4: iconst_1
5: anewarray #16 // class java/lang/Class
8: dup
9: iconst_0
10: ldc #17 // class java/util/List
12: aastore
13: invokevirtual #18 // Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
16: astore_0
17: aload_0
18: invokevirtual #19 // Method java/lang/reflect/Method.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
21: astore_1
22: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
25: new #20 // class java/lang/StringBuilder
28: dup
29: invokespecial #21 // Method java/lang/StringBuilder."":()V
32: ldc #22 // String genericParameterTypes=
34: invokevirtual #23 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
37: aload_1
38: invokevirtual #24 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
41: invokevirtual #25 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
47: aload_1
48: iconst_0
49: aaload
50: instanceof #11 // class java/lang/reflect/ParameterizedType
53: ifeq 78
56: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
59: aload_1
60: iconst_0
61: aaload
62: checkcast #11 // class java/lang/reflect/ParameterizedType
65: checkcast #11 // class java/lang/reflect/ParameterizedType
68: invokeinterface #13, 1 // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
73: iconst_0
74: aaload
75: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
78: return
LineNumberTable:
line 56: 0
line 57: 17
line 58: 22
line 59: 47
line 60: 56
line 62: 78
LocalVariableTable:
Start Length Slot Name Signature
17 62 0 method Ljava/lang/reflect/Method;
22 57 1 types [Ljava/lang/reflect/Type;
StackMapTable: number_of_entries = 1
frame_type = 253 /* append */
offset_delta = 78
locals = [ class java/lang/reflect/Method, class "[Ljava/lang/reflect/Type;" ]
Exceptions:
throws java.lang.Exception
public static void getMethodReturnType() throws java.lang.Exception;
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=6, locals=2, args_size=0
0: ldc #6 // class bean/TestCache
2: ldc #27 // String get
4: iconst_1
5: anewarray #16 // class java/lang/Class
8: dup
9: iconst_0
10: ldc #17 // class java/util/List
12: aastore
13: invokevirtual #18 // Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
16: astore_0
17: aload_0
18: invokevirtual #28 // Method java/lang/reflect/Method.getGenericReturnType:()Ljava/lang/reflect/Type;
21: astore_1
22: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
25: new #20 // class java/lang/StringBuilder
28: dup
29: invokespecial #21 // Method java/lang/StringBuilder."":()V
32: ldc #29 // String genericReturnType=
34: invokevirtual #23 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
37: aload_1
38: invokevirtual #24 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
41: invokevirtual #25 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
47: aload_1
48: instanceof #11 // class java/lang/reflect/ParameterizedType
51: ifeq 74
54: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
57: aload_1
58: checkcast #11 // class java/lang/reflect/ParameterizedType
61: checkcast #11 // class java/lang/reflect/ParameterizedType
64: invokeinterface #13, 1 // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
69: iconst_0
70: aaload
71: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
74: return
LineNumberTable:
line 70: 0
line 71: 17
line 72: 22
line 73: 47
line 74: 54
line 76: 74
LocalVariableTable:
Start Length Slot Name Signature
17 58 0 method Ljava/lang/reflect/Method;
22 53 1 genericReturnType Ljava/lang/reflect/Type;
StackMapTable: number_of_entries = 1
frame_type = 253 /* append */
offset_delta = 74
locals = [ class java/lang/reflect/Method, class java/lang/reflect/Type ]
Exceptions:
throws java.lang.Exception
public static void getConstructorParamsType() throws java.lang.Exception;
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=5, locals=3, args_size=0
0: ldc #6 // class bean/TestCache
2: iconst_1
3: anewarray #16 // class java/lang/Class
6: dup
7: iconst_0
8: ldc #30 // class java/util/Map
10: aastore
11: invokevirtual #31 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
14: astore_0
15: aload_0
16: invokevirtual #32 // Method java/lang/reflect/Constructor.getGenericParameterTypes:()[Ljava/lang/reflect/Type;
19: astore_1
20: aload_1
21: iconst_0
22: aaload
23: checkcast #11 // class java/lang/reflect/ParameterizedType
26: checkcast #11 // class java/lang/reflect/ParameterizedType
29: invokeinterface #13, 1 // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
34: iconst_0
35: aaload
36: astore_2
37: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
40: aload_2
41: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
44: return
LineNumberTable:
line 84: 0
line 85: 15
line 86: 20
line 87: 37
line 88: 44
LocalVariableTable:
Start Length Slot Name Signature
15 30 0 constructor Ljava/lang/reflect/Constructor;
20 25 1 genericParameterTypes [Ljava/lang/reflect/Type;
37 8 2 type Ljava/lang/reflect/Type;
LocalVariableTypeTable:
Start Length Slot Name Signature
15 30 0 constructor Ljava/lang/reflect/Constructor;
Exceptions:
throws java.lang.Exception
public static void getClassType() throws java.lang.Exception;
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=0
0: ldc #6 // class bean/TestCache
2: invokevirtual #33 // Method java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
5: astore_0
6: aload_0
7: checkcast #11 // class java/lang/reflect/ParameterizedType
10: invokeinterface #13, 1 // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
15: iconst_0
16: aaload
17: astore_1
18: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
21: new #20 // class java/lang/StringBuilder
24: dup
25: invokespecial #21 // Method java/lang/StringBuilder."":()V
28: ldc #34 // String params=
30: invokevirtual #23 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
33: aload_1
34: invokevirtual #24 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
37: invokevirtual #25 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
40: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
43: return
LineNumberTable:
line 96: 0
line 97: 6
line 98: 18
line 99: 43
LocalVariableTable:
Start Length Slot Name Signature
6 38 0 genType Ljava/lang/reflect/Type;
18 26 1 params Ljava/lang/reflect/Type;
Exceptions:
throws java.lang.Exception
}
Signature: #94 // Lbean/LocalCache;
SourceFile: "TestCache.java"
查看 class 文件内容,发现 LocalVariableTypeTable 中的 Signature 包含了方法中存在的泛型,类似于:
LocalVariableTypeTable:
Start Length Slot Name Signature
0 16 1 map Ljava/util/Map;
Signature: #49 // (Ljava/util/Map;)V
下方的 Signature 的#后面的编号对应着 Constant pool 中保存的信息。每个方法中都可以通过 LocalVariableTypeTable 的 Signature 获取到代码中写的泛型实际类型。
至于成员属性,只有在 Constant pool 中保存着。
#39 = Utf8 Ljava/util/Map;
LocalVariableTypeTable 以及 Signature 的解释:
深入探索Java泛型的本质 | 泛型