编译后Java对象引用变量类型会发生什么?

Stu*_*ent 3 java variables bytecode compilation reference

我记得在Java字节码中没有看到任何引用变量类型的概念.我对类型擦除有点了解,但是这个术语似乎与泛型紧密相关,而我的问题一般是关于对象引用变量.Java对象引用变量类型是否在编译后存活?或者变量类型只是起到帮助编译器帮助开发人员检查代码是否有意义的作用?如果引用变量类型在编译中存活,它们在字节码中出现在哪里?

编辑:请允许我在此感谢您的宝贵贡献.为了更多地考虑我的想法,我想补充一个例子:

Object o = "foo";
Run Code Online (Sandbox Code Playgroud)

在字节码中,变量o及其类型(Object)是否可以在任何地方表示并在运行时读取?

Tom*_*icz 6

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

Object obj = "abc";
String s = (String)obj;
Run Code Online (Sandbox Code Playgroud)

被翻译成:

aload_1       
checkcast     #3                  // class java/lang/String
astore_2   
Run Code Online (Sandbox Code Playgroud)

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

Integer x = 1;
String s = "abc";
int len = s.length();
Run Code Online (Sandbox Code Playgroud)

被翻译成:

   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      
Run Code Online (Sandbox Code Playgroud)

注意8加载s局部变量的指令.使用十六进制编辑器替换aload_2aload_1,因此尝试调用String.length()一个Integer对象(x局部变量):

$ 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
Run Code Online (Sandbox Code Playgroud)

如果你好奇,如果你禁用了类验证,那么地狱就会松动:

$ 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)
Run Code Online (Sandbox Code Playgroud)

可能会更糟.


最后但并非最不重要的是,有很多专用于特定基元的操作码(浮点数,双精度数,整数等)