I'm going through a book on data structures. Currently I'm on graphs, and the below code is for the vertex part of the graph.
class Vertex<E>{
//bunch of methods
public boolean equals(Object o){
//some code
}
}
When I try to implement this equals method my compiler complains about not checking the type of the parameter and just allowing any object to be sent it. It also does seem a bit strange to me why that parameter shouldn't be a Vertex instead of an Object. Is there a reason why the author does this or is this some mistake or antiquated example?
@Override
public boolean equals(Object obj)
{
if(obj == null) return false;
else if (!(obj instanceof Vertex)) return false;
else return // blah blah
}
equals(Object) is the method defined in the root - Object. If you don't match the signature exactly, Object's version will be called when someone checks if two objects are equal. Not what you want.
You've probably seen other methods (like Comparator) where you can use the exact time. That's because those APIs were generic-ified with Java 5. Equals can't be because it is valid to call equals with two separate types. It should return false, but it is valid.
equals is a method inherited from Object, is defined to be flexible enough so that you can take any object and test if it is equal to any other object (as it rightfully should be able to do), so how could it be any other way?
Edit 1
Comment from jhlu87:
so is it not good form to write an equals method that has an input parameter of vertex?
You are welcome to create your own overload to any method, including equals, but doing so without changing the name could risk confusing many who would assume that your equals is the one that inherits from Object. If it were my code and I wanted a more specific equals method, I'd name it slightly different from just "equals" just to avoid confusion.
It's because this method existed before generics, so for backward compatabitity it has to stay this way.
The standard workaround to impose type is:
return obj instanceof MyClass && <some condition>;
If your method doesn't take an argument of type Object, it isn't overriding the default version of equals
but rather overloading it. When this happens, both versions exist and Java decides which one to use based on the variable type (not the actual object type) of the argument. Thus, this program:
public class Thing {
private int x;
public Thing(int x) {
this.x = x;
}
public boolean equals(Thing that) {
return this.x == that.x;
}
public static void main(String[] args) {
Thing a = new Thing(1);
Thing b = new Thing(1);
Object c = new Thing(1);
System.out.println(a.equals(b));
System.out.println(a.equals(c));
}
}
confusingly prints true for the first comparison (because b
is of type Thing) and false for the second (because c
is of type Object, even though it happens to contain a Thing).
It is because the author is overriding equals. Equals is specified in java.lang.Object and is something that all classes inherrits from.
See the javadoc for java.lang.Object