导致这种"可能的精度损失"错误的原因是什么?

Hel*_*rld 24 java final

我的最终变量有问题.任何帮助将不胜感激.

这是我的第一个工作正常的代码

final int i = 90; 
byte b = i ; 
System.out.println(i);
Run Code Online (Sandbox Code Playgroud)

这是我的第二个代码,它表示可能会损失精度.这有什么不对?

final int i; 
i = 90;
byte b = i ; 
System.out.println(i);
Run Code Online (Sandbox Code Playgroud)

Roh*_*ain 25

我在JLS中找不到这个的确切原因,所以我仔细检查了字节码,发现原因是编译器无法i在第二种情况下内联,但能够在第一种情况下完成案件.

这是代码:

final int x = 90;
System.out.println(x);

final int i;
i = 90;
System.out.println(i);
Run Code Online (Sandbox Code Playgroud)

编译后的字节代码如下:

 0: getstatic     #2        // Field java/lang/System.out:Ljava/io/PrintStream;
 3: bipush        90
 5: invokevirtual #3        // Method java/io/PrintStream.println:(I)V
 8: bipush        90
10: istore_2
11: getstatic     #2        // Field java/lang/System.out:Ljava/io/PrintStream;
14: iload_2
15: invokevirtual #3        // Method java/io/PrintStream.println:(I)V
18: return
Run Code Online (Sandbox Code Playgroud)

所以在第一种情况下(3到5),它直接使用90打印值,而在第二种情况下(8到15),它必须将值存储到变量中,然后将其加载回堆栈.然后该print方法将选择堆栈的最高值.

因此,如果转让:

byte x = i;
Run Code Online (Sandbox Code Playgroud)

i将在运行时从堆栈中获取,而不是由编译器内联.所以编译器不知道i可能包含什么值.

当然,这是我的全部猜测.不同JVM上的字节代码可能不同.但我强烈的直觉认为这可能是原因.

此外,JLS§4.12.4可能与此相关:

原始类型或类型String的变量是final,并使用编译时常量表达式(第15.28节)初始化,称为常量变量.

由于在第二种情况下,变量不是由常量表达式初始化,而是稍后赋值,因此它不再是常量变量.