It's to do with how boxing works. From the JLS section 5.1.7:
If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
Basically, a Java implementation must cache the boxed representations for suitably small values, and may cache more. The ==
operator is just comparing references, so it's specifically detecting whether the two variables refer to the same object. In the second code snippet they definitely won't, as new Integer(3)
definitely isn't the same reference as any previously created one... it always creates a new object.
Due to the rules above, this code must always give the same result:
Integer x = 127;
Integer y = 127;
System.out.println(x == y); // Guarantee to print true
Whereas this could go either way:
Integer x = 128;
Integer y = 128;
System.out.println(x == y); // Might print true, might print false