首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如果final变量是从数组中复制过来的,为什么Java需要对它进行显式转换?

如果final变量是从数组中复制过来的,为什么Java需要对它进行显式转换?
EN

Stack Overflow用户
提问于 2017-03-26 15:32:43
回答 4查看 3.2K关注 0票数 60

从下面的代码开始...

代码语言:javascript
复制
byte foo = 1;
byte fooFoo = foo + foo;

当我尝试编译这段代码时,我会得到以下错误...

错误:(5,27) java:不兼容的类型:可能存在从整数到字节的有损转换

..。但是如果foo是最终的..。

代码语言:javascript
复制
final byte foo = 1;
final byte fooFoo = foo + foo;

文件将成功编译。

继续看下面的代码...

代码语言:javascript
复制
final byte[] fooArray = new byte[1];
fooArray[0] = 1;

final byte foo = fooArray[0];
fooArray[0] = 127;

System.out.println("foo is: " + foo);

..。将打印

代码语言:javascript
复制
foo is: 1

..。这很好。该值被复制到最终变量中,并且不能再更改。使用数组中的值不会更改foo的值(如预期的那样...)。

为什么下面的代码需要强制转换?

代码语言:javascript
复制
final byte[] fooArray = new byte[1];
fooArray[0] = 1;
final byte foo = fooArray[0];
final byte fooFoo = foo + foo;

这与这个问题中的第二个示例有什么不同?为什么编译器会给我下面的错误?

错误:(5,27) java:不兼容的类型:可能存在从整数到字节的有损转换

这怎么会发生呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-03-26 16:06:53

JLS (§5.2)具有使用常量表达式进行赋值转换的特殊规则

此外,如果表达式是类型为byteshortcharint的常量表达式(§15.28):

  • 如果变量的类型是byteshortchar,并且常量表达式的值可以在变量的类型中表示,则可以使用缩小基元转换。

如果我们沿着上面的链接,我们可以在常量表达式的定义中看到这些

原语类型的

String

  • The类型的加性运算符+和名称名称(§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并不重要。

票数 47
EN

Stack Overflow用户

发布于 2017-03-26 15:36:28

值1适合于一个字节;1+1也是如此;当变量是constant folding时,编译器可以执行最终操作。(换句话说:编译器在执行+操作时不使用foo;而是使用"raw“1值)

但是,当变量不是最终变量时,所有关于转换和提升的有趣规则都会生效(请参阅here;您想要阅读5.12节关于扩大原语转换的内容)。

对于第二部分:使一个数组为,仍然允许您更改它的任何字段;所以,再一次;不可能进行常量折叠;因此,“加宽”操作再次开始。

票数 18
EN

Stack Overflow用户

发布于 2017-03-26 20:23:40

这确实是编译器在与final一起使用时在常量折叠中所做的事情,正如我们可以从字节码中看到的:

代码语言:javascript
复制
    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,它也会报错:

代码语言:javascript
复制
    final byte s = 127;
    byte ss = s + s;

在这种情况下,编译器计算结果并知道它超出了限制,因此它仍然会抱怨它们是不兼容的。

更多信息:

here是关于字符串常量折叠的另一个问题:

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43026241

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档