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?