问题 为什么后期增量适用于包装类


我正在对一些代码进行审查,并遇到了一个有人在增加一个成员变量的实例,该成员变量是一个围绕Integer的包装类。我亲自尝试过,真的很惊讶它有效。

Integer x = 0; 
System.out.print(x++ + ", ");
System.out.print(x);

打印出来 0, 1不是 0, 0  正如我所料。我查看了语言规范,找不到任何有关此内容的内容。任何人都可以向我解释为什么这有效,如果它在多个平台上是安全的?我原本以为这会分解成

Integer x = 0;
int temp1 = x.intValue();
int temp2 = temp1 + 1;
System.out.println(temp1);
temp1 = temp2;
System.out.println(x.intValue());

但显然规范中有一些东西可以补充它 x = temp1; 在最后一行之前


8746
2017-11-07 23:32


起源

它不是围绕Integer的包装类,因为它是类Integer的一个实例,其中包含方法/运算符。其中一个是'++'运算符,它增加了它的值。 - hd1
@ hd1 - 这不正确。该 ++ 运算符仅适用于(基本)整数类型。在幕后, x 没有装箱, ++ 应用,然后将结果分配回 x (拳击转换后)。该 Integer上课没有 ++ 运营商。事实上, Integer 对象是不可变的。 - Ted Hopp
为什么你会期望输出 0, 0? - Ted Hopp
@ hd1:Java不支持运算符重载,除非在一个非常特殊的情况下(字符串中的+运算符)。 Integer类没有++运算符。 - Jherico
@Ted-熟悉C ++的人也可能期望Integer的行为与C ++'const'对象的行为方式相同。我不认为它特别直观,特别是因为预增量通常不涉及临时变量。它当然似乎没有被覆盖在任何地方 docs.oracle.com/javase/tutorial/java/data/numbers.html 要么 docs.oracle.com/javase/tutorial/java/data/autoboxing.html - Jherico


答案:


跨平台使用是完全安全的。行为在。中指定 Java语言规范的第15.4.2节 (重点补充):

后缀表达式的结果必须是可转换类型的变量(§5.1.8)数字类型,或发生编译时错误。

后缀增量表达式的类型是变量的类型。后缀增量表达式的结果不是变量,而是值。

在运行时,如果操作数表达式的评估突然完成,则后缀增量表达式出于同样的原因突然完成,并且不会发生增量。否则,将值1添加到变量的值 并将总和存回到变量中。在添加之前,二进制数字促销(§5.6.2)对值1和变量值执行。如有必要,通过缩小原始转换来缩小总和(§5.1.3)和/或进行拳击转换(§5.1.7)在存储变量之前的变量类型。后缀增量表达式的值是存储新值之前的变量值。

编辑 这里更准确地等同于您的示例代码中发生的事情:

Integer x = 0;
int temp = x.intValue();
x = temp + 1; // autoboxing!
System.out.println(temp + ", ");
System.out.println(x.intValue());

13
2017-11-07 23:34



+1“如果有必要,总和是...受到拳击转换” - Paul Bellora
只想添加Integers是不可变的,所以在此之后,x实际上是一个不同的Object。 - Scott Carlson


从Java 1.5开始,Java执行自动拆箱以转换“包装类型”,例如 Integer 到相应的原始类型 int 必要时。然后增量运算符可以处理结果 int


1
2017-11-07 23:34



我知道自动拆箱,这就是为什么我对x ++编译并不感到惊讶。我没有得到的是,java显然也会重新加载增量变量并将其重新填充到Integer中。 - Jherico


它是Java 5中的一个“新”特性 自动装箱  - 在需要时将整数转换为 - 反之亦然。同样适用于Float,Double,Boolean等。

虽然这是一个方便的功能,但如果您不小心,它可能会导致巨大的性能损失


0
2017-11-07 23:36