23

In the below class I have tried to compare the wrapper class with the primitive but the results are different.

I have checked the following links links:

The more interesting question is why new Object(); should be required to create a unique instance every time? i. e. why is new Object(); not allowed to cache? The answer is the wait(...) and notify(...) calls. Caching new Object()s would incorrectly cause threads to synchronize with each other when they shouldn't.

If there is a new object then how are a and c equal?

If b is equal to c and c is equal to a, then a should be equal to b. But in following case I got a != c.

Please explain.

class WrapperCompare {

    public static void main (String args[]) {
        Integer a = new Integer(10);    
        Integer b = 10; 
        int c=10;
        System.out.println(b==c);       //true
        System.out.println(a==b);       //false
        System.out.println(a==c);       //true
    }
}

Update: By referring to this link Integer caching.

Basically, the Integer class keeps a cache of Integer instances in the range of -128 to 127, and all autoboxing, literals and uses of Integer.valueOf() will return instances from that cache for the range it covers.

So in this case all statements should be true.

Boann
  • 48,794
  • 16
  • 117
  • 146
User12345
  • 486
  • 1
  • 3
  • 18

1 Answers1

27

Explanation

When you compare Integer vs int with ==, it needs to convert the Integer to an int. This is called unboxing.

See JLS§5.1.8:

If r is a reference of type Integer, then unboxing conversion converts r into r.intValue()

At that point, you are comparing int vs int. And primitives have no notion of instances, they all refer to the same value. As such, the result is true.

So the actual code you have is

a.intValue() == c

leading to a comparison of 10 == 10, both int values, no Integer instances anymore.

You can see that new Integer(...) indeed creates new instances, when you compare Integer vs Integer. You did that in a == b.


Note

The constructor new Integer(...) is deprecated. You should instead use Integer#valueOf, it is potentially faster and also uses an internal cache. From the documentation:

Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

The caching is important to note here, since it yields to == being true again (for cached values):

Integer first = Integer.valueOf(10);
Integer second = Integer.valueOf(10);
System.out.println(first == second); // true

The caching is guaranteed for values between -128 and +127, but may also be used for others.

Also note that your b actually comes out of the cache, since

Integer b = 10;
// same as
Integer b = Integer.valueOf(10);
// and not
Integer b = new Integer(10);

So boxing goes through Integers cache (see JLS§5.1.7).

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • 2
    “it is much faster” is a too strong claim. As the documentation says, “this method is *likely* to yield significantly better space and time performance”, in other words, it enables potential optimizations, whether they exist, is implementation dependent. – Holger May 07 '19 at 10:36