Why does Java require an explicit cast on a final variable if it was copied from an array?
从以下代码开始…
1 2 | byte foo = 1; byte fooFoo = foo + foo; |
当我尝试编译此代码时,会得到以下错误…
Error:(5, 27) java: incompatible types: possible lossy conversion from int to byte
…但如果
1 2 | final byte foo = 1; final byte fooFoo = foo + foo; |
文件将成功编译。
继续执行以下代码…
1 2 3 4 5 6 7 | final byte[] fooArray = new byte[1]; fooArray[0] = 1; final byte foo = fooArray[0]; fooArray[0] = 127; System.out.println("foo is:" + foo); |
…将打印
1 | foo is: 1 |
…这很好。该值将被复制到最终变量,并且不能再更改。使用数组中的值不会更改EDOCX1的值(如预期的那样…)。
为什么以下内容需要演员表?
1 2 3 4 | final byte[] fooArray = new byte[1]; fooArray[0] = 1; final byte foo = fooArray[0]; final byte fooFoo = foo + foo; |
这与这个问题中的第二个例子有什么不同?为什么编译器会给出以下错误?
Error:(5, 27) java: incompatible types: possible lossy conversion from int to byte
怎么会这样?
JLS(§5.2)对常量表达式的赋值转换有特殊的规则:
In addition, if the expression is a constant expression (§15.28) of type
byte ,short ,char , orint :
- A narrowing primitive conversion may be used if the type of the variable is
byte ,short , orchar , and the value of the constant expression is representable in the type of the variable.
如果我们遵循上面的链接,我们可以在常量表达式的定义中看到:
- Literals of primitive type and literals of type
String - The additive operators
+ and- - Simple names (§6.5.6.1) that refer to constant variables (§4.12.4).
如果我们遵循上面的第二个链接,我们会看到
A variable of primitive type or type
String , that isfinal and initialized with a compile-time constant expression (§15.28), is called a constant variable.
因此,如果
byte foo = 1; 没有定义常量变量,因为它不是final 变量。final byte foo = 1; 确实定义了一个常量变量,因为它是final 并用常量表达式(原始文本)初始化。final byte foo = fooArray[0]; 没有定义常量变量,因为它没有用常量表达式初始化。
注意,
值1非常适合一个字节;1+1也是如此;当变量是最终变量时,编译器可以进行常量折叠。(换句话说:编译器在执行+operation时不使用
但是当变量不是最终变量时,所有关于转换和升级的有趣规则都会出现(请参见这里;您想阅读第5.12节关于扩大原始转换的内容)。
第二部分:使一个数组成为最终数组仍然允许您更改它的任何字段;再次如此;不可能持续折叠;因此"加宽"操作再次开始。
这确实是编译器在与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | byte f = 1; // because compiler still use variable 'f', so `f + f` will // be promoted to int, so we need cast byte ff = (byte) (f + f); final byte s = 3; // here compiler will directly compute the result and it know // 3 + 3 = 6 is a byte, so no need cast byte ss = s + s; //---------------------- L0 LINENUMBER 12 L0 ICONST_1 // set variable to 1 ISTORE 1 // store variable 'f' L1 LINENUMBER 13 L1 ILOAD 1 // use variable 'f' ILOAD 1 IADD I2B ISTORE 2 // store 'ff' L2 LINENUMBER 14 L2 ICONST_3 // set variable to 3 ISTORE 3 // store 's' L3 LINENUMBER 15 L3 BIPUSH 6 // compiler just compute the result '6' and set directly ISTORE 4 // store 'ss' |
如果您将最后一个字节更改为127,它还会抱怨:
1 2 | final byte s = 127; byte ss = s + s; |
在这种情况下,编译器计算结果并知道它超出了限制,因此它仍然会抱怨它们不兼容。
更多:
还有一个关于用绳子不断折叠的问题: