Why does post-increment work on wrapper classes
Asked Answered
P

5

14

I was doing a review of some code and came across an instance of someone post-incrementing a member variable that was a wrapper class around Integer. I tried it myself and was genuinely surprised that it works.

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

This prints out 0, 1, not 0, 0 as I would have expected. I've looked through the language specification and can't find anything covering this. Can anyone explain to me why this works and if it's safe across multiple platforms? I would have thought that this would decompose into

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

But apparently there's something in the specification that make it add x = temp1; before the last line

Pineal answered 7/11, 2012 at 23:32 Comment(9)
It's not so much a wrapper class around Integer, as it is that x is an instance of class Integer, with the methods/operators that go along with that. One of which is the '++' operator, which increments its value.Polymerization
@Polymerization - That's not correct. The ++ operator applies only to (primitive) integer types. Behind the scenes, x is unboxed, the ++ is applied, and the result is then assigned back to x (after a boxing conversion). The Integer class does not have a ++ operator. In fact, Integer objects are immutable.Junie
Why would you have expected the output to be 0, 0?Junie
@hd1: Java doesn't support operator overloading except in one very specific case (the + operator in Strings). The Integer class does not have a ++ operator.Pineal
@Ted: it's not self-evident that after unboxing, Java will know to rebox the primitive and put it back into the original variable.Pineal
@Pineal - It is self-evident once you read the spec. (See my answer.) It was designed that way because everyone familiar with the C/C++ family of languages (to which Java is related) expects ++ to change the value of the variable to which it is applied, and having wrapper classes should not conflict with that expectation.Junie
@Ted - people familiar with C++ might also expect Integer to behave the way a C++ 'const' object would. I don't think it's particularly intuitive, especially since pre-increment doesn't normally involve a temporary variable. It certainly doesn't seem to be covered anywhere in docs.oracle.com/javase/tutorial/java/data/numbers.html or docs.oracle.com/javase/tutorial/java/data/autoboxing.htmlPineal
The analogy with a C++ const seems flawed. You can't use ++ with a const int in C++. So you should expect either to not be able to apply ++ to a Java Integer at all, or for it to behave just like an int, not a const int. (Java tries to make Integer behave as much like int as possible.)Junie
let us continue this discussion in chatPineal
J
16

It's perfectly safe to use across platforms. The behavior is specified in §15.4.2 of the Java Language Specification (emphasis added):

The result of the postfix expression must be a variable of a type that is convertible (§5.1.8) to a numeric type, or a compile-time error occurs.

The type of the postfix increment expression is the type of the variable. The result of the postfix increment expression is not a variable, but a value.

At run-time, if evaluation of the operand expression completes abruptly, then the postfix increment expression completes abruptly for the same reason and no incrementation occurs. Otherwise, the value 1 is added to the value of the variable and the sum is stored back into the variable. Before the addition, binary numeric promotion (§5.6.2) is performed on the value 1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the postfix increment expression is the value of the variable before the new value is stored.

EDIT Here's a more accurate equivalent of what's going on in your example code:

Integer x = 0;
int temp = x.intValue();
x = temp + 1; // autoboxing!
System.out.println(temp + ", ");
System.out.println(x.intValue());
Junie answered 7/11, 2012 at 23:34 Comment(2)
+1 "If necessary, the sum is... subjected to boxing conversion"Howland
Just wanted to add that Integers are immutable, so after this is over x is actually a different Object.Tagmeme
S
3

Answer by Sir Tedd Hopp is at a very complex level for programmers who are programming only for few or couple of years.

Let me clear your doubt in simple way suppose

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

output will be 11

Because ++ either post or pre increment is doing Addition by 1 only internally

ie x+1 is what it has to perform and put back the result in the same variable.

ie x=x+1;

now we all know that + operator can only take primitives but x is object , then we have auto-unboxing and auto-boxing concept. so the expression becomes

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

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

Hence output comes as 11 after another step of auto-unboxing inside the println statement.

Schmidt answered 16/5, 2019 at 19:57 Comment(0)
W
2

As of Java 1.5, Java performs auto-unboxing to convert "wrapper types" such as Integer to the corresponding primitive type int when necessary. Then the increment operator can work on the resulting int.

Walter answered 7/11, 2012 at 23:34 Comment(1)
I know about auto-unboxing, which is why I'm not surprised that x++ compiles. What I didn't get is that java apparently will also re-box the incremented variable and stuff it back in the Integer.Pineal
S
0

It is a "new" feature in Java 5 called autoboxing - Integer is transformed to in when needed - and vice-versa. Same applies to Float, Double, Boolean etc.

While it is a convenient feature, it can lead to a HUGE performance hit if you are not careful

Salyer answered 7/11, 2012 at 23:36 Comment(0)
Z
0

Note that the output would be as expected if the increment operation were moved to a method:

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

That's because Java passed a copy of the reference so you're now working with a new reference object, x1 instead of x. The original Integer object that x was pointing to stays unchanged and x still points to it.

This can easily bite you when doing calculations in a method if you forget about it.

Zachery answered 25/11, 2018 at 8:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.