可能重复:
如何查看 Java 的字节码?
我想知道类型擦除后是否可以在类文件中看到java编译器所做的代码更改。
我尝试过 javap,但它使用参数化类型重建原始源文件。
本教程 ( http://docs.oracle.com/javase/tutorial/java/generics/genTypes.html ) 讨论了在类型擦除后用有界类型或对象替换参数化类型。我想看看编译器做了哪些更改,这些更改在 javap 或任何反编译器中都不可见。
问候,萨维克
可能重复:
如何查看 Java 的字节码?
我想知道类型擦除后是否可以在类文件中看到java编译器所做的代码更改。
我尝试过 javap,但它使用参数化类型重建原始源文件。
本教程 ( http://docs.oracle.com/javase/tutorial/java/generics/genTypes.html ) 讨论了在类型擦除后用有界类型或对象替换参数化类型。我想看看编译器做了哪些更改,这些更改在 javap 或任何反编译器中都不可见。
问候,萨维克
类型擦除字面意思是从生成的字节码中删除泛型类型。值得注意的是它的缺席。因此,您可以看到它在字节码中不存在。
当您使用 时javap
,您会看到一些泛型类型信息可用于类、方法和字段签名。这包括在内,因此编译器可以使用这些类完成其编译代码的工作。它们在运行时不做任何事情,尽管它们可以通过反射获得,因此您可以编写一个使用此信息的库。
我遇到的一个案例是Collections.max()
他们希望类型擦除在哪里,Object
但仍然强制它是一个Comparable
. 你可以看到这样的签名:
vlad@vld /tmp $ javap java.util.Collections | grep max
public static java.lang.Object max(java.util.Collection);
public static java.lang.Object max(java.util.Collection, java.util.Comparator);
另一种方法是使用javap -c
并查看编译器进行的检查。例子:
对于这个程序:
public class Test{
public static void main(String[]args){
java.util.Vector<String> a = new java.util.Vector<String>();
a.add("Hello world");
System.out.println(a.get(0).length());
}
}
您会得到以下结果:
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class java/util/Vector
3: dup
4: invokespecial #3; //Method java/util/Vector."<init>":()V
7: astore_1
8: aload_1
9: ldc #4; //String Hello world
11: invokevirtual #5; //Method java/util/Vector.add:(Ljava/lang/Object;)Z
14: pop
15: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
18: aload_1
19: iconst_0
20: invokevirtual #7; //Method java/util/Vector.get:(I)Ljava/lang/Object;
23: checkcast #8; //class java/lang/String
26: invokevirtual #9; //Method java/lang/String.length:()I
29: invokevirtual #10; //Method java/io/PrintStream.println:(I)V
32: return
}
注意checkcast
.