Overriding the java equals() method - not working?

equals, java, overriding

Solution

In Java, the `equals()` method that is inherited from `Object` is:

public boolean equals(Object other);

In other words, the parameter must be of type `Object`. This is called overriding; your method `public boolean equals(Book other)` does what is called overloading to the `equals()` method.

The `ArrayList` uses overridden `equals()` methods to compare contents (e.g. for its `contains()` and `equals()` methods), not overloaded ones. In most of your code, calling the one that didn't properly override `Object`'s equals was fine, but not compatible with `ArrayList`.

So, not overriding the method correctly can cause problems.

I override equals the following everytime:

@Override
public boolean equals(Object other){
    if (other == null) return false;
    if (other == this) return true;
    if (!(other instanceof MyClass)) return false;
    MyClass otherMyClass = (MyClass)other;
    ...test other properties here...
}

The use of the `@Override` annotation can help a ton with silly mistakes.

Use it whenever you think you are overriding a super class' or interface's method. That way, if you do it the wrong way, you will get a compile error.

Problem

I ran into an interesting (and very frustrating) issue with the `equals()` method today which caused what I thought to be a well tested class to crash and cause a bug that took me a very long time to track down. Just for completeness, I wasn't using an IDE or debugger - just good old fashioned text editor and System.out's. Time was very limited and it was a school project. Anyhow - I was developing a basic shopping cart which could contain an `ArrayList` of `Book` objects. In order to implement the `addBook()`, `removeBook()`, and `hasBook()` methods of the Cart, I wanted to check if the `Book` already existed in the `Cart`. So off I go - ``` public boolean equals(Book b) { ... // More code here - null checks if (b.getID() == this.getID()) return true; else return false; } ``` All works fine in testing. I create 6 objects and fill them with data. Do many adds, removes, has() operations on the `Cart` and everything works fine. I read that you can either have `equals(TYPE var)` or `equals(Object o) { (CAST) var }` but assumed that since it was working, it didn't matter too much. Then I ran into a problem - I needed to create a `Book` object with only the `ID` in it from within the Book class. No other data would be entered into it. Basically the following: ``` public boolean hasBook(int i) { Book b = new Book(i); return hasBook(b); } public boolean hasBook(Book b) { // .. more code here return this.books.contains(b); } ``` All of a sudden, the `equals(Book b)` method no longer works. This took a VERY long time to track down without a good debugger and assuming the `Cart` class was properly tested and correct. After swaapping the `equals()` method to the following: ``` public boolean equals(Object o) { Book b = (Book) o; ... // The rest goes here } ``` Everything began to work again. Is there a reason the method decided not to take the Book parameter even though it clearly was a `Book` object? The only difference seemed to be it was instantiated from within the same class, and only filled with one data member. I'm very very confused. Please, shed some light?

Original source

Related problems