Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does == actually work the same or different when comparing two primitives vs two Objects in Java?

Tags:

When searching for explanations of how logical equals == works in Java the answers are always something along the lines of:

  • For primitives it returns whether the primitives have the same value (this includes comparing a primitive to its WrapperObject as the WrapperObject gets automatically unboxed to a primitive).
  • For Objects it returns whether they represent the same Object on the Heap.

But these explanations all seem to imply that these are 2 different things, that == behaves differently depending whether you're comparing Objects vs primitives. It seems to me that they must actually be the exact same thing: Take two variables from the Stack and compare their values.

The thing that changes isn't the behavior of ==, it's what the values it's comparing represent. If the things you're comparing are primitives then the value on the Stack is the value of the primitive itself. If you're comparing Objects then the value on the Stack is the value of the reference (and thus the address of the Object on the Heap).

Have I mis-understood something, or does == actually behave the same in all situations? Bonus points if you can point me to documentation on how this really works under the covers.

like image 381
user7382368 Avatar asked Aug 18 '19 02:08

user7382368


People also ask

How is == operator different for objects and primitive types?

How is == operator different for objects and primitive types ? Ans. For objects or references, == operator check if the reference on left and right points to the same object. For primitive types or variables, == operator check if the variable on left and right holds the same value.

Can objects be compared with == in Java?

In Java, the == operator compares that two references are identical or not. Whereas the equals() method compares two objects. Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity.

What is the difference between == and equals in comparing Java String objects?

In java both == and equals() method is used to check the equality of two variables or objects. == is a relational operator which checks if the values of two operands are equal or not, if yes then condition becomes true. equals() is a method available in Object class and is used to compare objects for equality.

What does == mean in Java?

Both equals() method and the == operator are used to compare two objects in Java. == is an operator and equals() is method. But == operator compares reference or memory location of objects in a heap, whether they point to the same location or not.


1 Answers

As other answers / comments say, at the Java language level the == operator semantics are specified (in JLS 15.21) in an implementation independent way. Strictly speaking, you cannot infer the "under the hood" implementation details from the JLS text. All that you can say is that any conformant implementation of == must behave in a certain way.

I will assume that we are talking about conventional JVMs where the actual machine representation of a reference is a machine address. It is possible to implement references in other ways; e.g using some kind of indirect addressing mechanism such as a PIDLAM.

At the bytecode level, there are a number of different bytecode instructions that implement the logic of == depending on the type (int, long or reference). However, the semantic of the comparisons are similar. Once the bytecodes have been verified as type-safe, integers and addresses can be handled the same for the purposes of == comparison at the hardware level.

At the hardware (machine instruction) level == works the same for primitive integral types and non-primitive values. In both cases it will be executing a machine instruction that compares two "words" taken from a register or from memory (heap or stack).


The JLS specified semantics of == for float and double are a bit different because the special values (infinities and not-a-number values) need special treatment. For example: NaN == NaN is false. See also the IEEE 754 floating point standard.

There are different bytecodes for this, and at the hardware level the instructions used are different to those used in the integer and reference cases. (The treatment of special values is typically handled in the floating hardware.)


The JLS specified semantics of == for boolean, byte, short and char is to promote the values to another type (int, long, float or double) before comparing them. Promotion also occurs with other cases if the operands have different (unboxed) types.

In addition, unboxing occurs if one (but not both!) of the operands is boxed. If both operands are boxed, then == is a reference comparison.


Summarizing the above ...

Have I mis-understood something, or does == actually behave the same in all situations?

No it doesn't, if you include floating point types, and the considerations of primitive widening and unboxing.

Bonus points if you can point me to documentation on how this really works under the covers.

There is no official (Oracle) public documentation for this. The JLS and JVM spec do not prescribe implementation strategies.

like image 142
Stephen C Avatar answered Oct 07 '22 03:10

Stephen C