在Java中,a += 10和a = a + 10之间的区别是什么?

32
< p> a += 10 a = a + 10 是完全相同的吗?还是它们之间存在差异?我在学习Java作业时遇到了这个问题。


这个问题的重复问题是在这个问题之后发布的,所以它应该是这个问题的重复问题,而不是相反。 - Kröw
1
@Kröw 不,那并不重要。例如,请参见https://meta.stackoverflow.com/q/251938/2891664。 - Radiodef
5个回答

37

现在你提到了类型转换... 在这种情况下有所不同:

byte a = 5;
a += 10; // Valid
a = a + 10; // Invalid, as the expression "a + 10" is of type int

从Java语言规范第15.26.2节

形如E1 op= E2的复合赋值表达式相当于E1 = (T)((E1) op (E2)),其中TE1的类型,除了E1仅被计算一次。

有趣的是,规范中给出的例子:

short x = 3;
x += 4.6;

在Java中是有效的,但在C#中不是...基本上在C#中编译器会对+=和-=进行特殊处理,以确保表达式要么是目标类型,要么是目标类型范围内的字面量。

1
请原谅我的无知,但是为什么'a+10'的类型是int,当a已经被定义为byte? - Raúl
1
@Raúl:由于二进制数字提升,实际上不存在 byte +(byte, byte) 运算符。请参阅 http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.2。 - Jon Skeet

18

没有区别,两者是缩写。甚至编译器会为它们生成相同的指令。

编辑:正如我刚发现的那样,编译器并不会为两者生成相同的代码。查看下面的内容:

dan$ cat Test.java
public class Test {
    public static void main(String[] args) {
        int a = 0;
        a = a + 10;
        a += 20;
    }
}

dan$ javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   bipush  10
   5:   iadd
   6:   istore_1
   7:   iinc    1, 20
   10:  return

}
所以,对于Java初学者或不担心在最小级别上进行优化的任何人来说,简短答案是它们可以互换使用。长答案取决于我阅读iadd与iinc的区别。编辑2:指令规范大致如下:iadd-将堆栈上的两个int相加;iinc-将局部变量增加一个常数。正如我们上面所看到的,只要右侧有一个常数,我们可以使用iinc节省几个指令。但是如果我们有a + = a呢?那么代码看起来像这样:
   7:   iload_1
   8:   iload_1
   9:   iadd
   10:  istore_1

如果我们有 a = a + a,那么它与我们得到的相同。


我知道这个。但是我读到有关于类型转换的一些不同之处。我不理解,所以在这里问了解更多相关信息。 - GuruKulki
1
你应该在主题开头就明确表达清楚。 - BalusC
@danben:很高兴看到编辑(因为编译器不会生成相同的代码)。但是一旦启用JIT的JVM(如HotSpot)接管它,我的怀疑是,如果表达式没有其他影响,即使使用更长的形式也将被优化为增量操作。 - T.J. Crowder
嘿,你在哪里编译了 Test.java? :) - Pascal Thivent
@Pascal Thivent:我为了简洁起见省略了那部分。 - danben
显示剩余3条评论

5
这在Java语言规范, 15.25.2节中有定义。其要点是:

形如 E1 op= E2 的复合赋值表达式等同于 E1 = (T)((E1) op (E2)),其中 T 是 E1 的类型,除了 E1 只被计算一次。

换句话说,在你的情况下,区别在于隐式类型转换:
byte a = 100;
a += 1000;    // compiles
a = a + 1000; // doesn't compile, because an int cannot be assigned to a byte.

byte a = 100; a += 1000; 这段代码会给 a 赋什么值? - Jerry Jeremiah
1100的二进制表示中的8个最低有效位,就像将int强制转换为byte一样。 - meriton

4

在你展示的表达式中,它们是等价的,在像下面这样的表达式中:

array[getIndex(context)][some / complex + expression] += offset;

在一些情况下,使用+=(以及其他赋值运算符)能够帮助你更好地实现想法。如果表达式比较复杂,使用+=运算符可以避免错误并提高可读性和可维护性。


1
在软件领域有一些术语,我可以向您解释,
在“a=a+1”赋值中,“a”的测量是在两个步骤之后进行的
1.系统计算a的值(这里创建了一个新的孤立副本) 2.系统将10添加到孤立变量“a”,然后将孤立“a”的值分配给左侧的“a”
但在第二种情况下,
系统知道“a”的值,并直接将10添加到“a”(这里没有创建孤立副本)。
希望这对您有所帮助,还有一件事,我们通常使用的方法是“a += 10;”,因为它减少了操作成本,根据其他方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接