3

我不记得曾经在 Java 字节码中看到过任何引用变量类型的概念。我对类型擦除有所了解,但这个术语似乎与泛型密切相关,而我的问题一般是关于对象引用变量。Java 对象引用变量类型能否在编译后继续存在?或者变量类型只是起到帮助编译器帮助开发人员检查代码是否有意义的作用?如果引用变量类型在编译后仍然存在,它们会出现在字节码中的什么位置?

编辑:请允许我在这里感谢您的所有宝贵贡献。为了进一步缩小我的想法,我想添加一个示例:

Object o = "foo";

在字节码中,变量 o 及其类型(对象)会在任何地方表示并在运行时读取吗?

4

3 回答 3

6

是的,字节码也是类型安全的。首先,每次向下转换时都会使用一个字节码指令:checkcast

Object obj = "abc";
String s = (String)obj;

被翻译成:

aload_1       
checkcast     #3                  // class java/lang/String
astore_2   

其次invokevirtual,其他人期望给定类型的对象。如果您传递了错误的类型,JVM 将拒绝加载此类。我不认为用 Java 语言可以实现,所以我做了一些黑客攻击。以下代码:

Integer x = 1;
String s = "abc";
int len = s.length();

被翻译成:

   0: iconst_1      
   1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   4: astore_1      
   5: ldc           #3                  // String abc
   7: astore_2      
   8: aload_2       
   9: invokevirtual #4                  // Method java/lang/String.length:()I
  12: istore_3      

8注意加载s局部变量的指令。使用十六进制编辑器替换aload_2aload_1,从而尝试调用String.length()对象Integerx局部变量):

$ java Test

Exception in thread "main" java.lang.VerifyError: 
  Bad type on operand stack in method Test.main([Ljava/lang/String;)V at offset 9

只是如果你好奇,如果你禁用类验证,地狱就会崩溃:

$ java -Xverify:none Test
Exception in thread "main" java.lang.NullPointerException
  at java.lang.String.length(String.java:623)
  at Test.main(Test.java:6)

本来可以更糟的。


最后但同样重要的是,有大量专用于特定原语(浮点数、双精度数、整数等)的操作码。

于 2013-02-02T20:27:39.653 回答
2

JVM 加载的所有字节码都经过静态类型检查以确保其安全。如果没有类型检查,恶意字节码可能只会将 int 视为指针并破解 VM。

然而,仅仅因为字节码是类型安全的并不意味着它具有显式类型。相反,每个值都有一个由类型推断确定的隐式类型。(从 Java 7 开始,还必须在每个基本块的开头包含指定所有内容类型的元数据,从而使类型推断任务更加容易)。

请注意,虽然所有内容都经过类型检查,但规则比 Java 中的更为宽松。例如,在字节码中,没有布尔、字节、字符或短局部变量之类的东西。它们都被编译成整数。因此,例如,您可以拥有一个不等于 true 或 false 的布尔值。此外,在您调用接口的方法之前不会检查接口,因此接口变量实际上可以保存任何任意对象。最后,Hotspot VM 允许您自由混合 byte[] 和 boolean[]s。

于 2013-02-02T20:58:15.663 回答
1

字段类型在字段描述符中编码。

局部变量的类型可以编码到LocalVariableTable 属性(或通用类型的LocalVariableFieldTypeTable 属性)中,并且在面向 Java 6 的类文件中,必须在StackMapTable 属性中编码。对于较旧的类文件,JVM 将使用类型推断验证字节码的类型正确性。

因此,虽然字段和变量的类型没有用字节码表示是正确的,但它们在类文件中(至少对于面向 Java 6 或更高版本的类文件)。

于 2013-02-02T20:54:23.383 回答