Consider the following snippet:
int i = 99999999;
byte b = 99;
short s = 9999;
Integer ii = Integer.valueOf(9); // should be within cache
System.out.println(new Integer(i) == i); // "true"
System.out.println(new Integer(b) == b); // "true"
System.out.println(new Integer(s) == s); // "true"
System.out.println(new Integer(ii) == ii); // "false"
It’s obvious why the last line will ALWAYS prints "false": we’re using == reference identity comparison, and a new object will NEVER be == to an already existing object.
The question is about the first 3 lines: are those comparisons guaranteed to be on the primitive int, with the Integer auto-unboxed? Are there cases where the primitive would be auto-boxed instead, and reference identity comparisons are performed? (which would all then be false!)
Yes. JLS §5.6.2 specifies the rules for binary numeric promotion. In part:
Binary numeric promotion applies for several numeric operators, including "the numerical equality operators == and !=."
JLS §15.21.1 (Numerical Equality Operators == and !=) specifies:
In contrast, JLS §15.21.3 (Reference Equality Operators == and !=) provides:
This fits the common understanding of boxing and unboxing, that’s it only done when there’s a mismatch.