Using == Operator in Java to Compare Wrapper Objects

Using == operator in Java to compare wrapper objects

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.

Comparing wrapper class with primitive using equals() gives strange behavior

longWrapper.equals(0) returns false, because 0 is autoboxed to Integer, not to Long. Since the two types are different, .equals() returns false.

In the meantime, longWrapper == 0 is true, because the longwrapper value is unboxed to 0, and 0 == 0 without considering the actual primitive types.

Comparing two Integer Wrapper classes

Using the new keyword always creates two different instances. So the following is always true:

new Integer(10) != new Integer(10)

hence the first line printing "false".

Then:

i++;

hides the unboxing and boxing. It is equivalent to:

i = Integer.valueOf(i.intValue() + 1);

As described in the Javadoc of Integer.valueOf, values from -128 to 127 (at least) are cached: you are getting back the cached instance of Integer.valueOf(11) for both i++ and i1++, hence the second line printing "true".

operator == differet behaviour on wrapper class object

The == comparator checks for object equality!

Since Integer.valueOf maintains a cache of Integer Objects with the value -128 to 127 valueOf(String) returns the cached object, thus the == comparance results in true.

Integer a1 = new Integer("12");
Integer b1 = new Integer("12");
//a1 == b1 returns false because they point to two different Integer objects

Integer aa = Integer.valueOf("12");
Integer bb = Integer.valueOf("12");
//aa == bb returns true because they point to same cached object

For the comparance of object values always use the .equals method, for primitives like int, long etc. you can use the == comparator.

Why can I test inequality of Wrappers like primitives? Can I do it for classes I create?

First of all - a whole ratsnest of implications has been unveiled.

What is happening is that for the operators '>=', '<=', '<', and '>' the compiler already knows that they can only be executed on primitive types, so automatically an unboxing will happen (convert the Object type to a primitive type). That is why those operators can be executed on Integer instances.

However, when using '==' or '!=', the compiler knows it can compare instances directly, basically comparing wether or not two variables are referencing the same object or not. It is not a true integer comparison at all.

As a matter of fact, this will return false:

System.out.println("Test == :"+(new Integer(1000) == new Integer(1000)));
System.out.println("Test == :"+(new Integer(100) == new Integer(100)));

These most likely will return false:

System.out.println("Test == :"+((Integer)1000 == (Integer)1000));
System.out.println("Test == :"+(Integer.valueOf(1000) == Integer.valueOf(1000)));

Although these most likely will return true:

System.out.println("Test == :"+((Integer)100 == (Integer)100));
System.out.println("Test == :"+(Integer.valueOf(100) == Integer.valueOf(100)));

'Most likely' because it is going to be implementation specific, and even can be controlled by parameters.

due to the fact that integer objects with values in the range -127..128 are being interned when using the Integer.valueOf(int) static factory method. See a more elaborate explenation.

But please never assume that this will ever work, and always use the Comparable interface, .equals(...), or do the unboxing.

For reference, also review these articles:

  • Why aren't Integers cached in Java?
  • Using == operator in Java to compare wrapper objects

Comparing primitive to wrapper object with == behaviour unexplained

c and cy refer to different instances of the Character class (each time you invoke a constructor, you create a new instance), so comparing these references returns false.

On the other hand, when you compare either of them to the primitive cx, they are unboxed to char, and the char comparison returns true.

Had you used Character.valueOf('a') instead of new Character('a'), you would have gotten the same instance in both calls, and the reference comparison would have returned true (since valueOf returns a cached Character instance if the argument <= 127).

Why does '', ' ' work with wrapper classes while '==' doesn't ?

The <, >, <= and >= operators are only defined for primitive types. Therefore using them on wrapper types causes the compiler to unbox the objects into primitives.

This means

System.out.println(a>=b);

is equivalent to

System.out.println(a.intValue()>=b.intValue());

However, the == and != operators exist for both primitive types and reference types, so using them to compare two objects of primitive wrapper types compares the references instead of the primitive values they wrap.

As Holger commented, comparison of object references with == and != existed in the Java language before auto-boxing and auto-unboxing were introduced, but comparison with <, >, <= and >= was not supported for any reference types before auto-unboxing was introduced.

This means that in the early days of Java, the a>=b of your code snippet would not pass compilation (since a and b are not primitive numeric types). On the other hand your a==b snippet would still pass compilation and return false.

Changing the behavior of == and != for reference types that happen to be wrappers of numeric primitives would change the behavior of existing code, thus breaking backwards compatibility, which is probably the reason it wasn't done.

Primitive wrappers comparison

Does on the 1st line of code we make implicit boxing?

Yes

2) Why the 3rd and 6th lines of code give us different results?

Integer.valueOf(int) pools all values from -128 to 127.

The reason is that small Integer values are used frequently and there is no point in creating a new object for all such values everytime we need an object. Hence, these are created as "interned" objects and all the references to such integer values will point to the same memory address.

code snippet 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);
}

Instead, when you call new Integer(10);, it is making an entire new object hence two different objects with same integer values will point to different memory addresses



Related Topics



Leave a reply



Submit