instanceof
or getClass()
An equals
method needs to check the type of its argument, and there’s two ways to do that: with an instanceof
check, or with a getClass()
check.
(Note, with instanceof
you don’t need an explicit null check, because instanceof
already does that for you.)
Both are valid, but unfortunately, EqualsVerifier needs to know which one you use and it can’t always tell the difference. EqualsVerifier prefers instanceof
, so if you use getClass()
and run into a problem, you can add usingGetClass()
:
Why the preference for instanceof
? Many IDEs generate equals
methods with getClass()
checks by default. Or maybe you just prefer getClass()
over instanceof
.
The reason is that Josh Bloch, in his Effective Java, recommends using instanceof
over getClass()
because instanceof
plays nicer with the Liskov substitution principle. EqualsVerifier follows this advice.
You might ask: why is this Liskov substitution principle important? Well, tools like Hibernate, and many mocking frameworks such as Mockito and EasyMock, use bytecode manipulation tricks to generate subclasses on the fly. That means that an object that you instantiate yourself could never be equal to an object that you fetch from the database, even if all the fields have the same values, simply because they’re not of the same type.
If you use getClass()
and you forget to add usingGetClass()
, you might get this error message:
Subclass: object is not equal to an instance of a trivial subclass with equal fields:
nl.jqno.equalsverifier.Foo@123456
Maybe you forgot to add usingGetClass(). Otherwise, consider making the class final or use EqualsVerifier.simple().
This is an example where the Liskov substitution principle and getClass()
clash. EqualsVerifier creates a subclass of Foo
, but adds nothing to it. Then it expects that equals
treats it the same as an actual Foo
. It doesn’t because getClass()
returns different values for Foo
and for the subclass.
In code, it looks like this:
Should this print true
or false
? SubFoo doesn’t change anything about Foo, so true
seems to make most sense. However, with getClass()
, it prints false
.
Making Foo
final is another way to avoid this problem.
Finally, if you think this is too strict, you can suppress Warning.STRICT_INHERITANCE
or use EqualsVerifier.simple()
instead.
If you want to know more about this, read Effective Java’s chapter on equals
.