从下面的代码开始...
byte foo = 1;
byte fooFoo = foo + foo;
当我尝试编译这段代码时,我会得到以下错误...
错误:(5,27) java:不兼容的类型:可能存在从整数到字节的有损转换
..。但是如果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:不兼容的类型:可能存在从整数到字节的有损转换
这怎么会发生呢?
发布于 2017-03-26 16:06:53
JLS (§5.2)具有使用常量表达式进行赋值转换的特殊规则
此外,如果表达式是类型为
byte
、short
、char
或int
的常量表达式(§15.28):
byte
、short
或char
,并且常量表达式的值可以在变量的类型中表示,则可以使用缩小基元转换。如果我们沿着上面的链接,我们可以在常量表达式的定义中看到这些
原语类型的
的String
+
和名称名称(§6.5.6.1)的文本如果我们遵循上面的第二个链接,我们可以看到
原语类型或类型为
String
的变量称为常量变量,即final
,并使用编译时常量表达式(§15.28)进行初始化。
由此可以得出,只有当foo
是常量变量时,才能将foo + foo
赋值给fooFoo
。要将其应用到您的案例中:
因为常量变量不是final
.,所以
byte foo = 1;
不定义常量变量final byte foo = 1;
确实定义了一个常量变量,因为它是final
的,并且是用常量表达式(原始文字)初始化的。final byte foo = fooArray[0];
不定义常量变量,因为它不是用常量表达式初始化的。请注意,fooFoo
本身是否为final
并不重要。
发布于 2017-03-26 15:36:28
值1适合于一个字节;1+1也是如此;当变量是constant folding时,编译器可以执行最终操作。(换句话说:编译器在执行+操作时不使用foo
;而是使用"raw“1值)
但是,当变量不是最终变量时,所有关于转换和提升的有趣规则都会生效(请参阅here;您想要阅读5.12节关于扩大原语转换的内容)。
对于第二部分:使一个数组为,仍然允许您更改它的任何字段;所以,再一次;不可能进行常量折叠;因此,“加宽”操作再次开始。
发布于 2017-03-26 20:23:40
这确实是编译器在与final
一起使用时在常量折叠中所做的事情,正如我们可以从字节码中看到的:
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,它也会报错:
final byte s = 127;
byte ss = s + s;
在这种情况下,编译器计算结果并知道它超出了限制,因此它仍然会抱怨它们是不兼容的。
更多信息:
here是关于字符串常量折叠的另一个问题:
https://stackoverflow.com/questions/43026241
复制相似问题