根据https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html
编译器应将每个无边界类型替换为Object
。
我有一堂课:
public class Test<E> {
void setE(E e) {
return;
}
}
在Idea中反编译后,结果是:
public class Test<E> {
public Test() {
}
void setE(E e) {
}
}
为什么
E
不替换为Object
? 最佳答案
该教程在这里有些误导。它试图提出关于类型擦除的观点,但是这样做并不十分优雅。
您生成的类的字节码如下。显然,此信息不会被丢弃。
Last modified 2 Mar 2020; size 332 bytes
MD5 checksum e3b7faf33fd5666eae578bd516d0f903
Compiled from "Test.java"
public class Test<E extends java.lang.Object> extends java.lang.Object
minor version: 0
major version: 53
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #2 // Test
super_class: #3 // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 2
Constant pool:
#1 = Methodref #3.#15 // java/lang/Object."<init>":()V
#2 = Class #16 // Test
#3 = Class #17 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 setE
#9 = Utf8 (Ljava/lang/Object;)V
#10 = Utf8 Signature
#11 = Utf8 (TE;)V
#12 = Utf8 <E:Ljava/lang/Object;>Ljava/lang/Object;
#13 = Utf8 SourceFile
#14 = Utf8 Test.java
#15 = NameAndType #4:#5 // "<init>":()V
#16 = Utf8 Test
#17 = Utf8 java/lang/Object
{
public Test();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
void setE(E);
descriptor: (Ljava/lang/Object;)V
flags: (0x0000)
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 3: 0
Signature: #11 // (TE;)V
}
Signature: #12 // <E:Ljava/lang/Object;>Ljava/lang/Object;
SourceFile: "Test.java"
之所以无法将这些信息丢弃在字节码中,是因为该类是库的一部分;另一个项目取决于它。在第二个项目的编译时,他们的编译器需要能够断言泛型类型参数是否在范围之内。如果它被完全扔掉了,他们必须写
Test test = new Test();
而在我的源项目中,我可以写
Test<String> test = new Test<>():
关于java - 为什么泛型类型信息在类文件中可见?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60494990/