Calling super.equals and super.hashCode in child class? - java

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.

Related

Java Type Check in equals(): instanceof vs getClass()

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.

Why can equals not be inferred in HashSets where the type is specified?

I don't understand something silly in Java and was hoping you could clear it up for me.
I have defined Hashset<Point> myHashSet = new HashSet<Point>();
Then, I create two equal Point points, Point p1 and Point p2, and put them in different variables/memory locations. Then I override the .equals() method for public boolean equals(Point other) and added my first point, p1, to the HashSet.
Then I call System.out.println(myHashSet.contains(p2)); // prints false
Why can the compiler not infer "Oh, this hashset is of type Point" from the when it is being created and say "I should check to see if Point has overridden the default equals method...yup, let's call that one!".
Instead, I believe it calls the generic equals method for objects, thus comparing memory location, I believe ?
Is the reasoning for this simply that the HashSet could contain a subclass of Point which uses a different Equals method ? This is the only reason I can see for the current behaviour, though I am sure I am overlooking something :). Thanks a lot.
Collections use Object.equals(Object) which you have to override. If you create another method like equals(Point) it won't call it.
Instead, I believe it calls the generic equals method for objects, thus comparing memory location, I believe ?
Yes, as the only method which HashSet can generically call is equals(Object)
Is the reasoning for this simply that the HashSet could contain a subclass of Point which uses a different Equals method ?
The HashSet has no way of know that you want to use this method instead at runtime.
You should override both equals() and hashCode() according to this doc http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode%28%29, since HashSet use both of these methods to check if objects are equal
Your problem lies in public boolean equals(Point other), because that is NOT the default equals method defined in the Object class.
You must override public boolean equals(Object other) (notice Object instead of Point) if you wish the HashMap to use your implementation. See the the documentation for Object and note also that if you override equals you SHOULD also override the hashCode() method.
Try adding #Override annotation. You must have misspelled equals method and its signature.
#Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}

contains method ignores equals override

Having Node abstract class which Cell extends him .
In Cell I implemented public boolean equals(Node cmpCell) . I created Set<Node> closeList = new HashSet<Node>(); and when I execute closeList.contains((Cell) node) I debugged it and detect that it utterly ignores Cell equals I implemented . What I did wrong ?
Edit :
I changed in Cell to
#Override
public boolean equals(Object cmpCell)
and still closeList.contains((Cell) node) doesn't using the above override .
2nd Edit :
In Cell class there is 2 members -
int colIndex ;
int rowIndex ;
the equals override just compare them to that both members of the 2nd class , I think it would be better I use HashMap<K, V> but still I would be glade to know how the hashCode should be looks like in such case ?
public boolean equals(Node cmpCell)
This is not a valid override. The syntax of equals method of Object class is: -
public boolean equals(Object)
And yes, as pointed out by #JonSkeet in comment, whenever you are overriding equals method, also remember to override hashCode method to follow the contract of equals and hashCode. Because if you don't do that, then even if your equals method shows evaluates your instances as equal, the default hashCode implementation in Object class will generate different hashCodes for them, and hence they won't be equal.
Also, ensure that, while calculating hashcode, you consider only those attributes, that you used to compare your instances in equals method. Else, again you will get incorrect result.
In addition to that, if you are using any IDE like Eclipse, it generates a very nicely overridden and compatible equals and hashCode method for you. You should be better using them.
You need to right-click on your class, go to source and select Generate equals and hashCode method.
You probably didn't override the hashCode method.
An object in a hashset is found using the hashcode first. You must always override both or none of the two equals and hashCode methods.
Well there are three potential issues:
You overrode the wrong signature. Should be public boolean equals(Object)
If you override equals you must implement hashCode
Is your equals method symmetric (x.equals(y) implies y.equals(x)) and does it play correctly with polymorphism, ie can you have a Node.equals(Cell) but the reverse be false?
As already stated, hashCode and equals must be implemented accordingly.
But the question asked here is "Why isn't the custom equals() called?". So, the answer is, that Java doesn't support multiple dispatch.
Simple example
If you declare Object myCell = new Cell(), then myCell2.equals(myCell) can only determine the declared type of myCell, which is Object.
Your case
The signature of the called methods is: HashSet.contains(Object o), with the same consequences as stated above.
You can do something like that, although it isn't a nice solution:
public class Cell {
#Override
public boolean equals(Object o) {
if(o instanceof Cell) {
// your code
}
super.equals(o);
}
}

Overriding equals() in subclass of class that contains an overridden equals()

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.

How default .equals and .hashCode will work for my classes?

Say I have my own class
public class MyObj { /* ... */ }
It has some attributes and methods. It DOES NOT implement equals, DOES NOT implement hashCode.
Once we call equals and hashCode, what are the default implementations? From Object class? And what are they? How the default equals will work? How the default hashCode will work and what will return? == will just check if they reference to the same object, so it's easy, but what about equals() and hashCode() methods?
Yes, the default implementation is Object's (generally speaking; if you inherit from a class that redefined equals and/or hashCode, then you'll use that implementation instead).
From the documentation:
equals
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).
hashCode
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
From Object in one of the JVM implementations:
public boolean equals(Object object) {
return this == object;
}
public int hashCode() {
return VMMemoryManager.getIdentityHashCode(this);
}
In both cases it's just comparing the memory addresses of the objects in question.
There are default implementations of equals() and hashCode() in Object. If you don't provide your own implementation, those will be used. For equals(), this means an == comparison: the objects will only be equal if they are exactly the same object. For hashCode(), the Javadoc has a good explanation.
For more information, see Effective Java, Chapter 3 (pdf), item 8.
Yes, from Object class since your class extends Object implicitly. equals simply returns this == obj. hashCode implementation is native. Just a guess - it returns the pointer to the object.
If you do not provide your own implementation, one derived from Object would be used. It is OK, unless you plan to put your class instances into i.e. HashSet (any collection that actually use hashCode() ), or something that need to check object's equality (i.e. HashSet's contains() method). Otherwise it will work incorrectly, if that's what you are asking for.
It is quite easy to provide your own implementation of these methods thanks to HashCodeBuilder and EqualsBuilder from Apache Commons Lang.
IBM's developerworks says:
Under this default implementation, two
references are equal only if they
refer to the exact same object.
Similarly, the default implementation
of hashCode() provided by Object is
derived by mapping the memory address
of the object to an integer value.
However, to be sure of the exact implementation details for a particular vendor's Java version it's probably best to look as the source (if it's available)

Categories

Resources