在类型擦除过程中,如果类型参数是有界的,Java编译器将擦除所有类型参数,并将每个参数替换为其第一个边界;如果类型参数是无边界的,则将每个参数替换为Object。
但是,当我们在编译类中引用方法时,编译器会确保在编译时进行类型检查。
为。例如,如果我在A类上使用泛型,编译它,然后通过B类引用它,在编译期间,它将确保类型检查。
如果java在编译时擦除类型,那么编译后的类文件如何确保类型检查呢?
发布于 2013-07-11 03:04:03
在运行时没有类型检查,除了擦除的上界。Java泛型是关于编译器检查的。
另一方面,也许您的问题只是关于如果类型参数信息从字节码中消失,编译器如何进行检查。答案是它并没有从整个类文件中消失:它是作为元数据附加的,可供编译器(以及反射API)使用,但与执行代码无关。
发布于 2013-07-11 06:38:57
我不同意在运行时没有检查的说法--但是所有的类型检查都是在编译时完成的。
查看生成的实际字节码总是很有趣的。让我们来看看这段代码
import java.util.*;
class Types{
public static void main(String [] args){
List<String> list = new ArrayList<String>();
list.add("hello");
System.out.println(list.get(0));
}
}
编译它,然后使用javap -c
反汇编它,我们得到
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: ldc #4 // String hello
11: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
16: pop
17: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
20: aload_1
21: iconst_0
22: invokeinterface #7, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
27: checkcast #8 // class java/lang/String
30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: return
}
我们注意到两件事
checkcast
来确保从列表中检索到的对象实际上是一个String
。这是由编译器插入的运行时检查。在泛型之前手动引入的东西。https://stackoverflow.com/questions/17578827
复制相似问题