In a nutshell the difference is simple:
- the default implementation of
equals()
and hashCode()
for java.lang.Object
will never consider two objects as equal
unless they are the same object (i.e. it's "object identity", i.e. x == y
).
- the default implementation of
equals()
and hashCode()
for records will consider all components (or fields) and compare them for equality (or consider them for the hash code). If they all match then .equals()
will return true
and hashCode
will return the same values.
The details documented for java.lang.Object.hashCode()
are:
As far as is reasonably practical, the hashCode method defined by class Object returns distinct integers for distinct objects.
In practice this means that any object which doesn't override hashCode
anywhere in its type hierarchy will return what is called the "identity hash code" which is effectively an arbitrary but constant number.
As for java.lang.Record.hashCode()
, it says:
The implicitly provided implementation returns a hash code value derived by combining appropriate hashes from each component. The precise algorithm used in the implicitly provided implementation is unspecified and is subject to change within the above limits. The resulting integer need not remain consistent from one execution of an application to another execution of the same application, even if the hashes of the component values were to remain consistent in this way. Also, a component of primitive type may contribute its bits to the hash code differently than the hashCode of its primitive wrapper class.
And for equals()
methods;
java.lang.Object.equals(Object obj)
:
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). In other words, under the reference equality equivalence relation, each equivalence class only has a single element.
java.lang.Record.equals(Object obj)
:
The implicitly provided implementation returns true if and only if the argument is an instance of the same record class as this record, and each component of this record is equal to the corresponding component of the argument; otherwise, false is returned. Equality of a component c is determined as follows:
If the component is of a reference type, the component is considered equal if and only if Objects.equals(this.c, r.c would return true.
If the component is of a primitive type, using the corresponding primitive wrapper class PW (the corresponding wrapper class for int is java.lang.Integer, and so on), the component is considered equal if and only if PW.compare(this.c, r.c) would return 0.
Apart from the semantics described above, the precise algorithm used in the implicitly provided implementation is unspecified and is subject to change. The implementation may or may not use calls to the particular methods listed, and may or may not perform comparisons in the order of component declaration.
For more discussion, see JEP 395: Records.