I have a Point class and a MinesweeperSquare class, the latter being a subclass of the former. If I override the equals method in the latter, like so:
if (!(obj instanceof MinesweeperSquare)) {
return false;
}
FindBugs reports that:
This class defines an equals method that overrides an equals method in a superclass. Both equals methods
methods use instanceof in the determination of whether two objects are equal. This is fraught with peril,
since it is important that the equals method is symmetrical (in other words, a.equals(b) == b.equals(a)).
If B is a subtype of A, and A's equals method checks that the argument is an instanceof A, and B's equals method
checks that the argument is an instanceof B, it is quite likely that the equivalence relation defined by these
methods is not symmetric.
In the Point class, I wrote:
if (!(obj instanceof Point)) {
return false;
}
How do I write an equals method in MinesweeperSquare such that the equals method is symmetric?
Update
FindBugs reports no errors if I write the following in MinesweeperSquare:
if (o == null || this.getClass() != o.getClass()) {
return false;
}
In your new method, MinesweeperSquare.equals(Point) will always return false, but Point.equals(MinesweeperSquare) could return true. Good on you for using FindBugs on this sort of thing. You might be able to use getClass() in both the definition of Point and MinesweeperSquare to check if the classes are exactly equal...although this, too, is tricky.
As you have already cited, if you use 'instanceof' operator in your equals() method implementation it become non-symetric. Get rid of 'instanceof' in your superclass as well as all subclasses and try to override equals() method based on the class properties and common sense. Most IDE's allows you to generate equals() method automatically which is a good starting point.
Using instanceof is fine if done correctly, which is quite hard without proper lecture. Using
this.getClass().equals(that.getClass())
is trivial, but not always does what you need. Look here for canEqual.
EDIT
This all applies only when you control both classes, which doesn't seem to be the case here. So stick with the easy way.
Related
I've a method that dissociate two object.
At the beginning of the method i retrieve from the DB(SpringData JPA/HIBERNATE) both the objects, that we well name object1 of type A and object2 of type B, then i compare object1.getB().equals(object2) and though the object1.getB is the same of object2 the result is false. Why? If i debug the method i can see that object2 and the property B of the object 2 have the same class that is B_$$_jvst1a4_5. Why have this strange name? shouldn't be only B? In the equals method infact when compare
if (getClass() != obj.getClass())
return false;
i obtain B != B_$$_jvst1a4_5 and so return false.
Someone can explain me this behaviour?
You use libraries that generate classes at runtime (proxy classes).
You should never rely on getClass() of these proxy classes to compare class of two instances as you don't have the hand and guarantee on how Hibernate (here) and Spring (as you use it) generate them.
As alternative in your equals() you should use the instanceof operator to determine whether an object is an instance of a class known at compile time :
if (myObject instanceof MyClass){
...
}
Whatever, instanceof should always be favored in equals() implementation to not break the method behavior for subclass instances.
First, I am not asking for the difference between them.
I have an idea in mind and I would like more brain to verify, which seems able to take (most of) the pros of using both approach.
In brief, equals() in Java usually looks like this.
public boolean equals(Object other) {
if (other == null) return false;
if (this == other) return true;
if (this and other is not of the same type) return false
// then actual equals checking
}
The problem lies in the "this and other is not of the same type" checking.
One stream of people prefer using if (! (other instanceof MyClass)), which have the shortcoming of
Easily lead to asymmetric result. If other is a subclass of MyClass and has overridden equals(), a.equals(b) and b.equals(a) will not be the same
To avoid this, we need to avoid child class from overriding equals(), by declaring it final
The other stream of people prefer using if (getClass() != other.getClass()), which has the shortcoming of
Violating Liskov substitution principle. A child class of MyClass should be able to use in place of MyClass.
Therefore a.equals(b) will be false if a is of MyClass while b is of a child class of MyClass, even the internal attributes are just the same.
I have an idea in mind I would want people to verify.
This approach should
If a child class overridden equals(), results should still be symmetric
A child class will still be able to be used as its parent type (in aspect of equals(), and equals is not overridden of course)
public class Parent {
#Override
public boolean equals(Object other) {
if (other == null) return false;
if (this == other) return true;
if (!(other instanceof Parent)) return false;
try {
if (other.getClass().getMethod("equals", Object.class).getDeclaringClass() != Parent.class) {
return other.equals(this);
}
} catch(Exception neverHappen){}
// do actual checking
}
}
The main idea is, if this encountered a Parent object, but that object's equals() is not declared in Parent (i.e. that object is a child class, with equals() overridden, I will delegate the equals invocation to the child class object (or may simply return false).
Is there any shortcoming of using this approach that I have overlooked? (I guess performance loss will be one concern, but I believe call of getClass().method("equals").getDeclaringClass() should be quite cheap?)
As stated in the comments, if the child class does super.equals(..), you would get a stackoverflow. To prevent this, you would end up rewriting the whole parents equals(..) in each children, which is even worst design.
Somehow, it depends on how/why you implemented inheritance in the first place. Should a child be comparable to a parent ? Does the comparaison makes sense ? (edited)
If you override equals, then you're not respecting LSP, by definition.
If a child has more parameters (which means it overides the equals method), then it shouldn't be equal to its parent, and this is why we can compare using getClass() != other.getClass() in the parent. If you want to use the parent class's equals() in your child (so you don't have to rewrite it all), you wouldn't end up stackoverflowing; equals() would just be false, because they weren't meant to be equal.
What if a child is comparable to its parent ? If you're respecting LSP, the child shouldn't have a different equals() than his parent (ie: equals shouldn't be overriden), I guess. So the asymetric case shouldn't exists.
If a child is comparable to its parent, but has more parameters ? This is now your design, not respecting LSP, so it's up to you to see what meaning it does have in your context and act accordingly.
EDIT:#Adrian yes, "does symmmetry makes sense" was poor wording, I should have said "does the comparaison makes sense ?".
For your example, if you compare two child class with getClass() and they use super with also getClass() it will return true (the test will be redondant, because this.getClass() and other.getClass() will always have the same values, in the child and in the parent). But as I said, if you compare a child and a parent, it will be false (and I think it's normal if they have different parameters).
Why use final only on equals with instance of ? You said it, because of possible assymetry, whereas it's not possible to be assymetric with inheritance using getClass(), so it's no use making it final in this case.
As a side note, if you use getClass(), then multiple child of the same parent won't be comparable ( always return false ). If you use instanceof, they can, but if they do, no child should override equals() for risking of breaking symmetry. (I think you got this, but I was wondering when choose insteanceof instead of getClass() if it's so problematic).
Is there any shortcoming of using this approach?
It wouldn't work. The method to call is determined at compile time. Polymorphism only apply to reference before . not after it.
other.equals(this); // always calls equals(Object); as `other` is an Object.
Also
other.getClass().getMethod("equals", /* method with no args */).getDeclaringClass();
I assume you wanted other.getClass().getMethod("equals", Parent.class) but you would have to catch NoSuchMethodException
I believe call of getClass().method("equals").getDeclaringClass() should be quite cheap?
Not in my option. It's quicker than reading something from disk, but you wouldn't want to do this very often.
Last but not least you should ensure that a.equals(b) ==> b.equals(a) and if a.equals(b) then a.hashCode() == b.hashCode() which is hard to do is a and b are different types.
If I implement equals() and hashCode() in both the parent and child classes, is it necessary to call super.equals() in equals() in the child class, e.g.
public boolean equals(Object obj) {
if (obj.getClass() != ChildClass.class) {
return false;
}
return super.equals() && this.var == ((ChildClass) obj).var;
}
I am assuming that the parent class is not Object and is giving the correct definition of equals and hashCode.
No, that's not necessary, and would probably be wrong. Indeed, part of the reason why you're overriding equal is because super.equals doesn't give the correct behaviour (right?).
Or put another way, if super.equals gives the correct behaviour, you probably don't need to go to the trouble of overriding it.
But if you are overriding equals, then yes, you need to override hashCode, too.
If your super class doesn't implement equals, then calling super.equals will get you the Object implementation which only compares references, so in any normal equals implementation where you want to compare a business key it would actually cause a lot of false negatives.
That said, your implementation above really isn't any different semantically than the default equals implementation in Object since you are just using == for comparison.
As for hashCode, if you override equals you really should override hashCode in order to keep the contract of the two. For instance, if you are using a business key for equals you should probably use the same business key for the hashcode so that two objects that are equal generate the same hashcode.
I am relatively new to java programming and have had a problem finding out where to use
equals and hashcode method overriding when I have a subclass inheriting from the superclass.
I want to check for equality for objects of the superclass and subclass and was wanting to know if either or both the superclass and subclass would need their equals and hashcode methods overriding?
My subclass has no instance variables and my superclass has 2 instance variables (integers)
My subclass constructor is calling the superclass constructor.
If I want to override the subclass equals and hashcode methods is that possible based on the fact the subclass has no instance variables but inherits the 2 instance variables from its superclass?
This actually brings up a difficult question. Let's say you have a class Foo, and two subclasses, FooA and FooB. Does it make sense, in your application/domain, for a FooA to ever be equals to a Foo or a FooB?
If so, you should implement equals in the superclass. And test for instanceof Foo. Basically, any extra fields that are added in FooA or FooB will get ignored. Often this is proper. Code looks like:
public boolean equals(Object o) { // perfectionists will make this final
if (this == o)
return true;
if (o instanceof Foo) { // note that Foo, FooA and FooB would all pass
Foo oFoo = (Foo)o;
// compare all the fields of Foo here
}
return false;
}
If not, you need to implement equals in the subclasses. And test for the classes be equals, not just instanceof. e.g.
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null) // this extra check is needed to avoid a NPE
return false;
if (o.getClass() == this.getClass()) { // must be an exact match
FooA oFoo = (FooA)o;
// compare all the fields here
}
return false;
}
In general, I think most people use the first approach. And it seems most appropriate to your problem. See Effective Java by Josh Bloch. You'll find a lot of posts on this, e.g. Any reason to prefer getClass() over instanceof when generating .equals()?
Since there are no new attributes added in the subclass, overriding equals() and hashcode() in the superclass will be fine. When you call these method on subclass objects, the superclasses methods will be called not those from class Object
However, if at a later date new attributes are added to the subclass, you will need to override those methods in the subclass also.
You need to override them for the class, Whose object would be under equals() check at runtime or whose Object would/can be under Hashing based Data Structure
If I want to override the subclass equals and hashcode methods is that
possible based on the fact the subclass has no instance variables but
inherits the 2 instance variables from its superclass?
It's certainly possible, but it rarely makes sense. Note that the contract of equals() requires it to be symmetric, i.e. a.equals(b) and b.equals(a) should always have the same result. When a and b are instances of a sub- and superclass that define equals() differently, this contract is probably not kept. That means if you put instances of the two classes into a collection, the collection may not work correctly.
Say I have a class where I would have to check for multiple different types of objects. Would it be feasible/possible to override equals() in the following manner?
public boolean equals(Object o){
if(o == null) return false;
if(o instanceof class1){
return this.class1.equals((class1) o);
if(o instanceof class2){
return this.class2.equals((class2) o);
...
}
Would this ever be useful? I assume here that I create a static overloaded equals() method in the respective classes (though maybe polymorphism would take care of that automatically as long as I cast?).
I very much doubt that because you can easily violate the transitivity of equals this way (x.equals(y) && x.equals(z) implies y.equals(z))
unless of course you do a very throughout setup involving all classes but that would be a pain to get right
It seems like you want a method to check whether a specified object is equal to at least one of various member variables in the receiver.
It is inappropriate to override java.lang.Object#equals for this purpose.
You should instead provide a different method, e.g.
public boolean hasEquals(Object o) { // your impl }
Semantically I don't think this is a good idea. Equals should not be based on class types but instance variables.
Apart from that, an Apple should never be equal to a Pear but only to other apples.
If you're sure that it won't lead to mutual recursion you can just return that.equals(this). However in general object equality implies either equality of classes, or at least a coherent inheritance relationship between them.