java why should equals method input parameter be O

2020-01-29 06:41发布

问题:

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?

回答1:

@Override
public boolean equals(Object obj)
{
     if(obj == null) return false;
     else if (!(obj instanceof Vertex)) return false;
     else return // blah blah
}


回答2:

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.



回答3:

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.



回答4:

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>;


回答5:

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).



回答6:

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