Using == operator in Java to compare wrapper objects

JavaIntegerWrapperEqualsOperator Keyword

Java Problem Overview


I'm reading SCJP Java 6 by Kathy Sierra and Bert Bates and this book is confusing me so much. On page 245 they state that the following code below.

Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2)
System.out.println("different objects");

//Prints output
different objects

Then on the very next page they have the following code

Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
System.out.println("same objects");

//Prints output
same objects

I'm so confused! When I try this out on my own it seems that you cannot use the == to compare the same way you would use equals() method. Using the == always gives me 'false' even if the Integer variables are set to the same value (i.e. 10). Am I correct? Using the == to compare the same Integer object (with same values) will always result in 'false'

Java Solutions


Solution 1 - Java

The key to the answer is called object interning. Java interns small numbers (less than 128), so all instances of Integer(n) with n in the interned range are the same. Numbers greater than or equal to 128 are not interned, hence Integer(1000) objects are not equal to each other.

Solution 2 - Java

If you look at the source code for Integer you'll see that Integer.valueOf(int) pools all values -128 to 127. The reason is that small Integer values are used frequently and are thus worthy of being pooled/cached.

Taken straight from Integer.java:

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

Note that this pooling is implementation specific and there's no guarantee of the pooled range.

The answers about interning are correct in concept, but incorrect with terminology. Interning in Java normally implies that the Java runtime is performing the pooling (such as String's intern). In Integer's case it's the class itself that is doing the pooling. There's no JVM magic involved.

Solution 3 - Java

The above answer about Interning is right on. Something to consider though if you do:

Integer i3 = new Integer(10);
Integer i4 = new Integer(10);

You will not have the new objects since you have created new objects explictly. If you write the code as follows it will be interned:

Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);

They will now be the same object again. If you take a look at the valueOf Method inside of the Integer.java class in the src.zip file you can see where it checks to see if the value of the int is outside of -128 to 127 it calls the new Integer class otherwise it loads it from the cache.

Solution 4 - Java

Integer i1 = 1000;
Integer i2 = 1000;

The compiler 'boxes' the int 1000 as Integer object. To do this it converts the source to the following:

Integer i1 = Integer.valueOf(1000);
Integer i2 = Integer.valueOf(1000);

Now valueOf could be a simple call to new Integer(1000) however creating a new Integer object every time an int is boxed would cost both time and space. To avoid this the Integer class keeps an array of Integer objects for a limited range of int values.

if(value> maxRange || value< minRange){
     //not in pool return new Integer
     return new Integer(value);
}else{
     //return pooled Integer object
     //for the value, pool contains all Integer
     //values from minRange to maxRange
     return integerPool[value-minRange];
}

The speed gained vs. the memory lost to this can be adjusted by setting the range with a jvm argument at program start (afaik it defaults to -127 to 128).

Solution 5 - Java

When the Java == operator is used to compare anything other than primitive types, it checks for referential equality; this applies even when the things being compared are wrapped primitives. Further, the valueOf method and compiler-generated autoboxing statement are generally free to arbitrarily return a new object which will not be reference-equal to any other previously-existing reference, or to return a reference to an existing object (which would, of course, be reference-equal to any pre-existing reference identifying the same object). Implementations are required to maintain a "pool" of Integer instances for values -128 to 127, such that all calls to Integer.valueOf on any particular number within that range will return references to the same object, but other than that an implementation would be free to do something like

static Integer [] intPool = new Integer[256];

public Integer valueOf(int n)
{
  int hash = (n*0x18675309) >>> 24;
  Integer instance = intPool[n];
  if (instance == null && instance.value != n)
  {
    instance = new Integer(n);
    intPool[hash] = instance ;
  }
  return instance;
}

I don't particularly expect Java implementations to do something like that, since in many cases the "cache hit" ratio could be near 0% and the extra time spent looking for instances in the cache would be wasted. Nonetheless, there is never any guarantee that a reference returned by instanceOf won't match some previous reference returned by that method (even if it doesn't match the last reference returned by that method, some caching algorithms might possibly cause it to return an earlier reference, especially if the pool is shared by multiple threads without locking. The lack of locking will never cause the code to return anything other than a reference to an integer with the correct value, but could cause unpredictable variations in which returned references compare equal). Only reference to Integer objects created directly using the constructor new Integer(n) are guaranteed to be unique; code which expects any reference returned by valueOf to not match any reference returned by valueOf, without having actually observed that it does not match, should be considered broken.

Solution 6 - Java

String comparison and integer comparison using == and != gives boolean results not as we expect.So be careful and make sure the possible unknown outcomes do not hinder the performance , reliability and accuracy of your software.

Solution 7 - Java

"==" always compare the memory location or object references of the values. equals method always compare the values.but equals also indirectly uses the "==" operator to compare the values. Integer uses Integer cache to store the values from -128 to +127.If == operator is used to check for any values between -128 to 127 then it returns true. if any value between -128 to 127 as

Integer i1 = -128; 
Integer i2 = -128; 
System.out.println(i1 == i2); // returns true

other than the above range then it returns false

Integer i1 = 1000;
Integer i2 = 1000;
System.out.println(i1 == i2); // returns false

https://vijayanbu001.blogspot.com/2016/07/identity-vs-equality-comparison-of.html">Refer the link for some additional info

Solution 8 - Java

According to jls-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.

So, any number between -128 and 127 is cached by Interger class.
Remember, when comparing two objects always use equals method.

The caching code is written in IntegerCache class which is member of Integer class.

Here is the code snippet:

 /**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

###References

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondidoView Question on Stackoverflow
Solution 1 - JavaSergey KalinichenkoView Answer on Stackoverflow
Solution 2 - JavaSteve KuoView Answer on Stackoverflow
Solution 3 - JavahaskovecView Answer on Stackoverflow
Solution 4 - JavajosefxView Answer on Stackoverflow
Solution 5 - JavasupercatView Answer on Stackoverflow
Solution 6 - JavaAntony Thomas RamanattuView Answer on Stackoverflow
Solution 7 - JavavijayView Answer on Stackoverflow
Solution 8 - JavaAniket KulkarniView Answer on Stackoverflow