我在一本书中碰到了以下内容-
//Here, T is bound by Object by default.
class Gen<T> {
T ob; // here, T will be replaced by Object
Gen(T o) {
ob = o;
}
//Return ob.
T getob() {
return ob;
}
}
// Here, T is bound by String.
class GenStr<T extends String> {
T str; // here, T will be replaced by String
GenStr(T o) {
str = o;
}
T getstr() { return str; }
}
编译这两个类之后,T
中的Gen
将被Object
替换。中的T
GenStr
将替换为String
。您可以通过在编译后运行javap
来确认
类。结果显示在这里:
class Gen extends java.lang.Object{
java.lang.Object ob;
Gen(java.lang.Object);
java.lang.Object getob();
}
class GenStr extends java.lang.Object{
java.lang.String str;
GenStr(java.lang.String);
java.lang.String getstr();
}
但是,我看到了这个
public class GenStr<T extends java.lang.String> {
T str;
GenStr(T);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field str:Ljava/lang/String;
9: return
T getstr();
Code:
0: aload_0
1: getfield #2 // Field str:Ljava/lang/String;
4: areturn
}
class Gen<T> {
T ob;
Gen(T);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field ob:Ljava/lang/Object;
9: return
T getob();
Code:
0: aload_0
1: getfield #2 // Field ob:Ljava/lang/Object;
4: areturn
}
为什么.class
文件仍然显示Formal Type参数<T>
?
答案 0 :(得分:3)
.class文件为什么仍显示Formal Type参数?
简单:这样
类型擦除是指以下事实:未保留有关用于实例化泛型类的特定类型的信息。但是该类是通用的信息需要在类文件中。在编译器看不到Gen.java而是只看到Gen.class的情况下,编译器又如何知道Gen
是通用的呢?
答案 1 :(得分:1)
类型信息仍然保留。不是有关个体实例的类型信息。
因此,您知道Gen
有一个类级别的类型参数(名义上)称为T
。
在运行时,您不知道T
实例的Gen
。您甚至无法从getob
来确定它:仅给您类型的下限(例如,如果getob
返回String
,T
可能是{{ 1}},String
,CharSequence
或Serializable
)。如果返回Object
,则null
可以是任何东西。
您可以使用Java针对没有源的类(只有编译后的字节码)编写代码。编译器需要有关此类的泛型的信息,以便能够确保正确使用它们。