Using == operator in Java to compare wrapper objects
Asked Answered
C

8

69

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'

Cryptogam answered 14/4, 2012 at 0:28 Comment(4)
I think this link can help you: #1515410Babbette
duplicate of #5278381Brushoff
And this: #5117632, #8427916Brushoff
Possible duplicate of Why does 128==128 return false but 127==127 return true in this code?Tachylyte
E
78

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.

Encephaloma answered 14/4, 2012 at 0:32 Comment(12)
Wow! I just saw that too. Why?? That's so confusing. What is the reasoning behind this?Cryptogam
note that only the object obtained from literals, autoboxing and Integer.valueOf() are interned objects while those constructed with new Integer are always distinct objectsGlean
I seem to remember that also goes for small Strings, but am not sure whether this is true and if so, what is considered a small String. Do you know anything about that?Malone
@G.Bach No, that has nothing to do with size. String constants are interned and you can call intern on your string variables for the same effect, that's all. And the why is simple: We need to store string constants somewhere anyhow and for small integers it's just a performance/memory optimizationEcumenicist
@Cryptogam One of the reasons behind interning integers is an attempt to save memory and to a certain extent - to save time as well. When Integer objects are used as keys in hash maps or as objects in hash sets, the percentage of small integers is disproportionally large. By interning them you can skip re-allocation of memory to hold identical copies of immutable objects that are equal to each other, and let the equality compare finish faster by checking reference equality first. Best of all, it hardly costs you anything in terms of CPU cycles, so it was an easy decision to make.Encephaloma
Java is not interning small numbers. Integer itself is doing the object pooling.Une
@SteveKuo You are right - I used the term loosely to mean both the language and its libraries, specifically java.lang.Integer. The two are more or less inseparable (e.g. Java compiler "knows" how to box int constants as Integers) so I think this usage is justified.Encephaloma
I've seen cases where this interning caused serious peformance degradation. I was creating a lot of Integers in a tight loop, and the instantiation cost was not trivial.Vins
@JamesScriven As any optimization technique, interning manually can go wrong. There is a cost difference between doing it manually to lots of integers in a tight loop, and doing it ahead of time to a small number of integers.Encephaloma
@JamesScriven java does not intern Integer dynamically, the interned Integer values are allocated at startup. It only does a range check (value < internedValues.length)when autoboxing int.Snowstorm
@Snowstorm If I recall it correctly, it also checks for it in the Integer.valueOf method.Encephaloma
@dasblinkenlight that is the range check I was referring to, after all autoboxing is performed using valueOf. with only I wanted to refer to the overhead being only a range check (not a native English speaker).Snowstorm
U
21

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.

Une answered 14/4, 2012 at 0:57 Comment(1)
Actually, the caching of Integer objects for int values in the range [-128, 127] is specified in the API docs, so that part of the range is, in fact, guaranteed.Elianaelianora
I
7

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.

Indolent answered 14/4, 2012 at 0:43 Comment(0)
S
3
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).

Snowstorm answered 16/4, 2012 at 19:22 Comment(0)
P
0

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.

Piddling answered 23/11, 2013 at 18:6 Comment(0)
P
0

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.

Posset answered 7/1, 2014 at 17:11 Comment(0)
T
0

"==" 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

Refer the link for some additional info

Tedford answered 1/8, 2016 at 17:12 Comment(0)
T
0

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

Talent answered 12/6, 2018 at 10:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.