为什么编译器不为这个加法操作提供一个错误?

这个问题在这里已经有了答案:

  • 为什么Java的+ =, - =,* =,/ =复合赋值操作符需要转换? 11个答案

  • 答案由JLS 15.26.2提供:

    例如,以下代码是正确的:

    short x = 3;

    x += 4.6;

    并导致x的值为7,因为它相当于:

    short x = 3;

    x = (short)(x + 4.6);

    所以,正如你所看到的,最新的情况实际上是有效的,因为添加赋值(和任何其他操作符赋值一样)对左手类型执行隐式转换(在你的情况中a是一个byte )。 扩展,它相当于byte e = (byte)(a + b); ,它会愉快地编译。


    反编译你的代码将解释Java正在做什么,它的原因通常可以在语言规范中找到。 但在我们进入之前,我们必须确定几个重要的概念:

  • 一个字面数字总是用int

    如果后缀为ASCII字母L或l(ell),则整数常量的类型为long; 否则它是int类型的(§4.2.1)。

  • 一个byte只能包含-128和127之间的整数值。

  • 尝试分配大于可容纳它的类型的文字将导致编译错误。 这是你遇到的第一个场景。

  • 所以我们回到这种情况:为什么添加两个字节明显比字节可以处理的字节更多而不会产生编译错误?

    它不会因溢出而引发运行时异常。

    这是两个数字加在一起突然产生一个非常小的数字的情况。 由于byte范围较小,所以很容易溢出; 例如,加1到127就可以了,结果是-128。

    它将要包装的主要原因是Java处理原始值转换的方式; 在这种情况下,我们正在谈论缩小转换。 也就是说,即使生成的总和大于byte ,缩小转换将导致丢弃信息以允许数据适合byte ,因为此转换永远不会导致运行时异常。

    逐步打破您的方案:

  • Java将a = 127b = 5加起来产生132。
  • Java知道abbyte类型,所以结果也必须是byte类型。
  • 这个整数结果仍然是132,但是在这一点上,Java将执行一次强制转换以将结果缩小到一个字节内 - 有效地为您提供(byte)(a += b)
  • 现在,由于环绕, az都包含结果-124。

  • 我得出的结论是,涉及变量的表达式的结果不能得到保证。 结果值可能在字节范围之内或之外,因此编译器会抛出错误。

    不,这不是原因。 静态类型语言的编译器以这种方式工作:任何变量都必须声明和输入,所以即使它的值在编译时不知道,它的类型也是已知的。 隐式常量也是如此。 基于这个事实,计算尺度的规则基本上是这样的:

  • 任何变量必须具有与其右侧表达式相同或更高的比例。
  • 任何表达式都具有与其有关的最大期限的相同比例。
  • 一个明确的施展力量,即科斯的右边表达的尺度。
  • (这些实际上是一个简化的视图;实际上可能会更复杂一点)。

    将其应用于您的案例:

    byte d = 1 + b
    

    实际的比例是:

    byte = int + byte
    

    ...(因为1被认为是一个隐式的int常量)。 因此,应用第一条规则,变量必须至少具有int尺度。

    在这种情况下:

    byte z = (a+=b);
    

    实际的比例是:

    byte = byte += byte
    

    ......这是可以的。

    更新

    那么,为什么byte e = a + b产生编译时错误?

    正如我所说的,java中的实际类型规则更为复杂:尽管一般规则适用于所有类型,但基元byteshort类型受到更多限制:编译器假定添加/减去两个或更多字节/短路可能导致原因一个溢出(如@Makoto所述),所以它需要被存储为下一个被认为“更安全”的比例类型: int

    链接地址: http://www.djcxy.com/p/12781.html

    上一篇: Why does the compiler not give an error for this addition operation?

    下一篇: Does Java support default parameter values?