views:

244

answers:

7

Consider this code:

class test {
   public static void main(String[] args) {
      test inst_test = new test();
      int i1 = 2000;
      int i2 = 2000;
      int i3 = 2;
      int i4 = 2;
      Integer Ithree = new Integer(2); // 1
      Integer Ifour = new Integer(2); // 2
      System.out.println( Ithree == Ifour );
      inst_test.method( i3 , i4 );
      inst_test.method( i1 , i2 );
   }
   public void method( Integer i , Integer eye ) {
      System.out.println(i == eye );
   }
}

It prints:

false
true
false

I understand the first false, the == operator only checks if two references are working on the same object, which in this case aren't.

The following true and false have me scratching my head. Why would Java consider i3 and i4 equal but i1 and i2 different? Both have been wrapped to Integer, shouldn't both evaluate to false? Is there a practical reason for this inconsistency?

+2  A: 

This is because boxing makes integers below a certain value (128, I think) refer to some preconstructed object, and higher values to new objects.

Jorn
+7  A: 

When autoboxing, Integers between -128 and 127 are cached, and the same wrapper object is returned. The same with boolean values and char values between \u0000 and \u007F

This is what you get most of the time, however it depends on JVM implementation.

amorfis
I used to think it was JVM-dependent too, but it's actually in the spec.
Jon Skeet
(Or rather, it's specified for those values, but not for others.)
Jon Skeet
A: 

I would guess that the wrapping tries to minimize the number of Integer Objects and creates only one Object representing 2 too save memory.

Just remember to never use == on Objects you never know what happens.

Janusz
yes, as several have said, do not use == unless specific effects are sought that are backed by "knows what happens" and in general use:Boolean booLean = Boolean.valueOf(i.intValue() == eye.intValue());System.out.println(booLean.toString());
Nicholas Jordan
+13  A: 

Autoboxing of primitives into objects (as used in your calls to method uses a cache of small values. From the Java Language Specification section 5.1.7:

If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

The discussion part of the spec immediately following that is interesting too. Notably a JVM can cache more values if it wants to - you can't be sure of the results of doing:

Integer i1 = 129;
Integer i2 = 129;
boolean b = (i1 == i2);
Jon Skeet
That is some seriously wicked logic - I guess it's done for performance reasons?
Michael Stum
Does this really have a benefit? I think it's an obfuscating design decision.
omgzor
6u14 (and various previous p-variants) has an option to increase the interned range. It's important for certain benchmarks and programming styles.
Tom Hawtin - tackline
The moral of the story should be when comparing objects, equals() is always the right thing to do, even for wrappers for primitive types.
sjlee
A: 

Integer class contain a cache of some frequently used instances. The range of values generally varies from JVM to JVM (sometimes is also configurable) but in general the relevant code is something like :

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

(code from sun JDK 1.6)

this is like string interning, since it both saves memory and allows test equality using a reference (e.g. == in place of equals)

dfa
+1  A: 

Autoboxing uses Integer.valueOf(i), not new Integer(i), to construct an object of class Integer.

As the others have said, valueOf() uses a cache, mostly for space efficiency.

Don't use == on reference types, it is almost always a mistake.

starblue
A: 

Autoboxing use some caching mechanism. Usually you should never rely on ==, always use equals to check equality.

fastcodejava