Any reason to prefer getClass() over instanceof when generating .equals()?
If you use instanceof
, making your equals
implementation final
will preserve the symmetry contract of the method: x.equals(y) == y.equals(x)
. If final
seems restrictive, carefully examine your notion of object equivalence to make sure that your overriding implementations fully maintain the contract established by the Object
class.
What I'm trying to get at here is that if you believe getClass()
is the only reliable way to preserve symmetry, you are probably using equals()
the wrong way.
Sure, it's easy to use getClass()
to preserve the symmetry required of equals()
, but only because x.equals(y)
and y.equals(x)
are always false. Liskov substitutability would encourage you to find a symmetry-preserving implementation that can yield true
when it makes sense. If a subclass has a radically different notion of equality, is it really a subclass?
instanceof Vs getClass( )
The reason that the performance of instanceof
and getClass() == ...
is different is that they are doing different things.
instanceof
tests whether the object reference on the left-hand side (LHS) is an instance of the type on the right-hand side (RHS) or some subtype.getClass() == ...
tests whether the types are identical.
So the recommendation is to ignore the performance issue and use the alternative that gives you the answer that you need.
Is using the
instanceOf
operator bad practice ?
Not necessarily. Overuse of either instanceOf
or getClass()
may be "design smell". If you are not careful, you end up with a design where the addition of new subclasses results in a significant amount of code reworking. In most situations, the preferred approach is to use polymorphism.
However, there are cases where these are NOT "design smell". For example, in equals(Object)
you need to test the actual type of the argument, and return false
if it doesn't match. This is best done using getClass()
.
Terms like "best practice", "bad practice", "design smell", "antipattern" and so on should be used sparingly and treated with suspicion. They encourage black-or-white thinking. It is better to make your judgements in context, rather than based purely on dogma; e.g. something that someone said is "best practice". I recommend that everyone read No Best Practices if they haven't already done so.
Java .equals() instanceof subclass? Why not call superclass equals instead of making it final?
A lot of the examples use instanceof
for two reasons: a) it folds the null check and type check into one or b) the example is for Hibernate or some other code-rewriting framework.
The "correct" (as per the JavaDoc) solution is to use this.getClass() == obj.getClass()
. This works for Java because classes are singletons and the VM guarantees this. If you're paranoid, you can use this.getClass().equals(obj.getClass())
but the two are really equivalent.
This works most of the time. But sometimes, Java frameworks need to do "clever" things with the byte code. This usually means they create a subtype automatically. Since the subtype should be considered equal to the original type, equals()
must be implemented in the "wrong" way but this doesn't matter since at runtime, the subtypes will all follow certain patterns. For example, they will do additional stuff before a setter is being called. This has no effect on the "equalness".
As you noticed, things start to get ugly when you have both cases: You really extend the base types and you mix that with automatic subtype generation. If you do that, you must make sure that you never use non-leaf types.
Why does the equals() implementation generated by Eclipse check for null before type checking (instanceof)?
It is unnecessary because instanceof has a built in null check.
But instanceof is a lot more than a simple foo == null. It is a full instruction preparing a class check doing unnecessary work before the null check is done. (see for more details http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.instanceof)
So a separate null check could be a performance improvement.
Did a quick measurement and no surprise foo==null is faster than a nullcheck with instanceof.
But usually you do not have a ton of nulls in an equals() leaving you with a duplicate unnecessary nullcheck most of the times... which will likely eat up any improvement made during null comparisons.
My conclusion: It is unnecessary.
Code used for testing for completeness (remember to use -Djava.compiler=NONE else you will only measure the power of java):
public class InstanceOfTest {
public static void main(String[] args) {
Object nullObject = null;
long start = System.nanoTime();
for(int i = Integer.MAX_VALUE; i > 0; i--) {
if (nullObject instanceof InstanceOfTest) {}
}
long timeused = System.nanoTime() - start;
long start2 = System.nanoTime();
for(int i = Integer.MAX_VALUE; i > 0; i--) {
if (nullObject == null) {}
}
long timeused2 = System.nanoTime() - start2;
System.out.println("instanceof");
System.out.println(timeused);
System.out.println("nullcheck");
System.out.println(timeused2);
}
}
Java @Override equals(): When this.getClass() != o.getClass() fails but shouldn't
happy songs correctly stated in his response:
myObject2 is an instance of a proxy class, generated at runtime by Hibernate using Byte Buddy. The generated proxy intercepts all method invocations, that's why getClass() returns different results.
I really didn't want to use instanceof because that is considered bad practice so I started poking around and stumbled onto a post having a similar issue. Their solution was to add the final keyword to their class declaration. I thought this insignificant but gave it try - AND IT WORKED! Adding the final keyword caused
if ( o == null || this.getClass() != o.getClass() )
and
if ( o == null || !this.getClass().equals( o.getClass() ) )
to work properly. My class code is now:
@Entity( name = "MyClass" )
@Table( name = "my_class" )
final public class MyClass extends MySuperClass
{
...
@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || !this.getClass().equals( o.getClass() ) )
{
return false;
}
if ( !super.equals( o ) )
{
return false;
}
MyClass that = ( MyClass ) o;
return this.var1.equals( that.var1 ) && this.var2.equals( that.var2 );
}
...
}
Thank you all for your assistance! And a big thank you to happy songs for pointing me in the proper direction!
What should be the result of overridden Object#equals(Object) when instance is upcasted?
It turns out, the problem is a bit deeper than I originally thought for one main reason: Liskov Subsitution Principle.
My PurchaseOrder#equals(Object)
method violates LSP. Because InternationalPurchaseOrder
extends PurchaseOrder
, it is correct to say that an international purchase IS-A purchase order. Therefore, to comply with LSP, I should be able to replace one instance for the other without any ill effects. Because of this, the line if (getClass() != obj.getClass()) return false;
completely violates this principle.
Even when my focus was around upcasting (which by now I am pretty much convinced that it is a code smell), almost the same issue applies: Should I be able to compare instances of PurchaseOrder
and InternationalPurchaseOrder
and return true
if they contain the same data internally? According to Joshua Bloch book Effective Java, Item 10 (Obey the general contract when overriding equals), the answer should be yes, but it is indeed no; but not for the reasons I initially thought (they are not the same type). The problem is this, and I quote:
There is no way to extend an instantiable class and add value component while preserving the
equals
contract, unless you're willing to forgo the benefits of object-oriented abstraction.
He continues to get in more details about this. The conclusion is simple: Do it this way and loose the benefits of abstraction, and violate LSP in the process. Or... simply follow a very important programming principle (especially in Java): favor composition over inheritance and inject the attributes you need to make a PurchaseOrder
domestic or international in this example. In my case, this solution will look like this (irrelevant details of class omitted):
public class InternationalPurchaseOrder {
private PurchaseOrder po;
private String country;
public (PurchaseOrder po, String country) {
this.po = po;
this.country = country;
}
public PurchaseOrder asPurchaseOrder() {
return po;
}
@Override
public boolean equals (Object obj) {
if (!(obj instanceof InternationalPurchaseOrder)) {
return false;
}
InternationalPurchaseOrder ipo = (InternationalPurchaseOrder)obj;
return ipo.po.equals(po) && cp.country.equals(country);
}
}
This way, an InternationalPurchaseOrder
can continue to be compared to other instances of the same class AND if needed to be compared to objects of PurchaseOrder
type, all that is needed is to call the asPurchaseOrder
to return an object of the compatible type.
How to implement equals with hibernate without risking losing the symmetric property?
After rading up some more i summarize this question with:
- Use instanceof and you can never add significant members to subclasses.(
There is no way to extend an instantiable class and add a value component while preserving the equals contract (Bloch) - Use getClass and you violate the Liskov substitution principle
Langers says http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.html
- The instanceof test is correct only for final classes or if at least method equals() is final in a superclass. The latter essentially
implies that no subclass must extend the superclass's state, but can
only add functionality or fields that are irrelevant for the object's
state and behavior, such as transient or static fields.
Implementations using the getClass() test on the other hand always
comply to the equals() contract; they are correct and robust. They
are, however, semantically very different from implementations that
use the instanceof test. Implementations using getClass() do not allow
comparison of sub- with superclass objects, not even when the subclass
does not add any fields and would not even want to override equals() .
Such a "trivial" class extension would for instance be the addition of
a debug-print method in a subclass defined for exactly this "trivial"
purpose. If the superclass prohibits mixed-type comparison via the
getClass() check, then the trivial extension would not be comparable
to its superclass. Whether or not this is a problem fully depends on
the semantics of the class and the purpose of the extension.
Summary - use instanceof with final for equals avoids breaking symmetry, and avoids the hibernate "proxy" problem.
Links
- Liskov and hibernate
- GetClass vs instanceof in equals
Related Topics
How to Rotate an Image Gradually in Swing
How to Directly Initialize a Hashmap (In a Literal Way)
Under What Conditions Is a Jsessionid Created
Differencebetween Up-Casting and Down-Casting with Respect to Class Variable
Using Setdate in Preparedstatement
Can't Add Value to the Java Collection with Wildcard Generic Type
Centering a Jlabel on a JPAnel
Removing an Element from an Array (Java)
How to Upload File Using Selenium Webdriver in Java
Why Does Runtime.Exec(String) Work for Some But Not All Commands
How to Turn Off the Eclipse Code Formatter for Certain Sections of Java Code
Why Do We Usually Use || Over |? What Is the Difference
Conditionally Ignoring Tests in Junit 4
How to Get the Current Date/Time in Java
How to Implement Constants in Java
Differencebetween & and && in Java
Custom Method for Update Query With Spring Data Mongorepository