从以下代码开始......
byte foo = 1;
byte fooFoo = foo + foo;
当我尝试编译此代码时,我将收到以下错误...
错误:(5,27)java:不兼容的类型:从int到byte的可能有损转换
......但如果 foo
是最终的......
final byte foo = 1;
final byte fooFoo = foo + foo;
该文件将成功编译 .
转到以下代码......
final byte[] fooArray = new byte[1];
fooArray[0] = 1;
final byte foo = fooArray[0];
fooArray[0] = 127;
System.out.println("foo is: " + foo);
......会打印出来
foo is: 1
......很好 . 该值将复制到最终变量,不能再更改 . 使用数组中的值不会更改 foo
的值(如预期的那样...) .
为什么以下需要演员?
final byte[] fooArray = new byte[1];
fooArray[0] = 1;
final byte foo = fooArray[0];
final byte fooFoo = foo + foo;
这与这个问题中的第二个例子有什么不同?为什么编译器会给我以下错误?
错误:(5,27)java:不兼容的类型:从int到byte的可能有损转换
怎么会发生这种情况?
3 回答
JLS(§5.2)具有使用常量表达式进行赋值转换的特殊规则:
如果我们按照上面的链接,我们在常量表达式的定义中看到这些:
如果我们按照上面的第二个链接,我们就会看到
因此,如果
foo
是常量变量,则foo + foo
只能分配给fooFoo
. 要将其应用于您的案例:byte foo = 1;
does not 定义一个常量变量,因为它不是final
.final byte foo = 1;
does 定义一个常量变量,因为它是final
并用常量表达式(原始文字)初始化 .final byte foo = fooArray[0];
does not 定义一个常量变量,因为它没有用常量表达式初始化 .请注意,
fooFoo
本身是否final
无关紧要 .值1非常适合一个字节; 1 1也是如此;当变量为final时,编译器可以执行constant folding . (换句话说:编译器在执行该操作时不使用
foo
;但是"raw" 1值)但是当变量不是最终变量时,关于转换和促销的所有有趣规则都会出现(参见here;您希望阅读有关扩大原始转换的第5.12节) .
对于第二部分:使数组最终仍然允许你 change 任何字段;再一次;没有恒定的折叠可能;这样"widening"操作又开始了 .
当与
final
一起使用时,它确实是编译器在常量折叠中所做的事情,正如我们从字节代码中看到的那样:如果你将最后一个字节改为127,它也会抱怨:
在这种情况下,编译器计算结果并知道它超出限制,因此它仍然会抱怨它们不兼容 .
更多:
here是关于使用字符串进行常量折叠的另一个问题: