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

时间:2012-11-07 23:32:17

标签: java immutability post-increment

我正在对一些代码进行审查,并遇到了一个有人在增加一个成员变量的实例,该成员变量是一个围绕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;

5 个答案:

答案 0 :(得分:15)

跨平台使用非常安全。行为在§15.4.2 of the Java Language Specification中指定(强调添加):

  

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

     

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

     

在运行时,如果操作数表达式的评估突然完成,则后缀增量表达式突然完成,原因相同,并且不会发生增量。否则,将值1添加到变量的值中,并将总和存储回变量。在添加之前,对值1和变量的值执行二进制数字提升(§5.6.2)。如果必要,在存储之前,通过缩小的基元转换(§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());

答案 1 :(得分:1)

从Java 1.5开始,Java会执行自动拆箱,以便在必要时将Integer等“包装类型”转换为相应的基元类型int。然后,增量运算符可以处理生成的int

答案 2 :(得分:0)

这是Java 5中的一个名为autoboxing的“新”功能 - 在需要时将整数转换为 - 反之亦然。同样适用于Float,Double,Boolean等。

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

答案 3 :(得分:0)

请注意,如果将增量操作移至方法,则输出将与预期的一样:

public void printIncrement(Integer x1) {
    System.out.print(x1++ + ", ");
}

那是因为Java传递了引用的副本,所以您现在正在使用新的引用对象x1而不是x。 x指向的原始Integer对象保持不变,并且x仍指向它。

如果您忘记了使用方法进行计算时,这很容易咬住您。

答案 4 :(得分:0)

Tedd Hopp爵士的回答对于只进行几年或几年编程的程序员来说是一个非常复杂的水平。

让我以简单的方式消除您的疑问 假设

    Integer x=10;
    x++;
    System.out.println(x) ;

输出将为11

由于++的发布或预增仅在内部进行加1运算

即x + 1是它必须执行的操作,并将结果放回相同的变量中。

ie x=x+1;

现在我们都知道+运算符只能采用基元,而x是object, 那么我们就有了自动拆箱和自动装箱的概念。 因此表达式变为

x.intValue()+1;//step 1 auto-unboxing

x=Integer.valueOf(x.intValue()+1);//step 2 auto-boxing

因此,在println语句中的自动拆箱步骤之后,输出为11。

相关问题