Java 这是什么原因造成的;可能的精度损失”;错误?

Java 这是什么原因造成的;可能的精度损失”;错误?,java,final,Java,Final,我的最终变量有问题。任何帮助都将不胜感激 这是我的第一个代码,运行良好 final int i = 90; byte b = i ; System.out.println(i); 这是我的第二个代码,它说可能会丢失精度。这里怎么了 final int i; i = 90; byte b = i ; System.out.println(i); 我在JLS中找不到这方面的确切原因,所以我检查了字节码,发现原因是编译器在第二种情况下不能内联I的值,但在第一种情况下能够这样做 代码如下:

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

这是我的第一个代码,运行良好

final int i = 90; 
byte b = i ; 
System.out.println(i);
这是我的第二个代码,它说可能会丢失精度。这里怎么了

final int i; 
i = 90;
byte b = i ; 
System.out.println(i);

我在JLS中找不到这方面的确切原因,所以我检查了字节码,发现原因是编译器在第二种情况下不能内联I的值,但在第一种情况下能够这样做

代码如下:

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

final int i;
i = 90;
System.out.println(i);
编译后的字节码如下所示:

 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
因此,在第一种情况下(3到5),它直接使用值
90
进行打印,而在第二种情况下(8到15),它必须将值存储到变量中,然后将其加载回堆栈。然后,
print
方法将拾取堆栈的顶部值

因此,在转让的情况下:

byte x = i;
i
的值将在运行时从堆栈中提取,而不是由编译器内联。因此编译器不知道
i
可能包含什么值

当然,这只是我的猜测。不同JVM上的字节码可能不同。但我有强烈的直觉,这可能就是原因

此外,可能与此相关:

原语类型或字符串类型的变量称为常量变量,它是最终变量,并用编译时常量表达式(§15.28)初始化


因为在第二种情况下,变量不是由常量表达式初始化的,而是后来被赋值的,它不再是一个常量变量。

在编译时,如果在创建时赋值,编译器可以确定最终变量的值,但在第二个代码中,您在创建后赋值,编译器不会捕获该值

如果您在第一个代码中使用超过127个变量(对于变量i),它也不会起作用

规范说“如果一个原语类型或字符串被定义为一个常量,并且该值在编译时是已知的,编译器会用它的值替换代码中任何地方的常量名。这称为编译时常量”

编译时常量为:

宣布最终

原语或字符串

在声明中初始化


用常量表达式初始化很简单,第一种方式编译器“知道”90可以放入字节变量,但第二种方式,它无法检测“i”的值,也不知道它可能包含什么值,因此不确定它是否可以放入字节变量。

@Manuel Selva:但第一个版本正在工作。如何?@Pshemo,为什么要编辑?@Mr.Pandey第一段代码编译吗?您应该提供一个涵盖代码主题的标题。可能有数百个问题的标题是“为什么我的代码不工作?”@sankrish:是的,它工作。这可能是真的,尽管你可以辩称编译器仍然有错;即使在第二个代码中,i的值是并且只能是90,因此它可以知道真相。但也许从编译器设计的角度来看,这实际上是一个很难解决的问题。@Gimby:不,事实上,编译器检查这个问题很简单。即使是基本编译器通常也有一个简单的常量传播。然而,好吧,java编译器几乎不执行任何优化,因为它依赖于JVM在运行时执行优化。我知道有一些优化是在执行的,但实际上大部分是在运行时执行的。虽然依我看,这不是一个优化,这是关于代码正确性的。编译器是否应用优化与语言规范所说的无关。了解语言行为从来都不需要看IL。只有这个答案的最后一部分是相关的。@usr我确实先去了JLS。我找到了那句话,但没有找到确切的意思。因此,只需转到
javap
进行确认。我知道字节码并不总是给出规则的答案,但这是为了检查。