I have a class where I have overridden both the hashCode method as well as the equals method. The equals method behaves as I would expect it to, however the hashCode method does not seem to behave as I would expect. I'm assuming therefor my expectation is incorrect, but not sure why. Below are the overridden methods:
public class Car extends SomeBaseClass implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private String carName;
private String carModel;
private String displayTextCar;
public boolean equals(Car car)
{
return (getCarName().equals(car.getCarName()) && getCarModel().equals(car.getCarModel()));
}
public int hashCode()
{
return (this.getCarName() + this.getCarModel()).hashCode();
}
Now I have a test class where create two car objects, and call the equals method and then put each instance of car into a HashMap. I set each instance to have the same car Name and Model and calling equals method in fact returns true. However even though each instance returns the same hashCode, when I add them to the HashMap, it keeps two objects int the Map, whereas I would expect the second put to replace the first object in the map ??? Below is the guts of the test class:
HashMap<Car,String> testMap;
Car testCar1 = new Car();
testCar1.setCarName("DaveCar");
testCar1.setCarModel("DaveModelTest");
System.out.println("Car Hash 1: " + testCar1.hashCode());
Car testCar2 = new Car();
testCar2.setCarName("DaveCar");
testCar2.setCarModel("DaveModelTest");
System.out.println("Car Hash 2: " + testCar2.hashCode());
//hashCodes prints identical numbers
System.out.println("Car 1 equal Car 2 ?? " + testCar1.equals(testCar2));
//returns true
testMap.put(testCar1, "3");
testMap.put(testCar2, "16");
System.out.println("Map size is " + testMap.size());
//I would expect the size to be 1 here, but it's in fact 2.
So this doesn't seem correct to me, I have naturally left some of the code out here, but this is the basic principal. Hoping someone can point out where I have gone wrong here. Note that I did use Eclipse to generate hashCode and equals methods and that worked correctly, however it's bugging me that my implementation of hashCode did not work as I expected, even though both objects seemingly returned the same value for the hashCode. Appreciate anyone's input.
The problem is that you have provided a wrong
equals
: it should beequals(Object)
, notequals(Car)
.Essentially, you have provided an overload instead of an override, so
HashMap
keeps calling theequals
from the base class.Fixing this problem is simple: add an override that does the cast, and calls the
equals
method that you wrote, like this:Note the use of
@Override
annotation. It helps Java help you spot issues like this automatically.Note: with this problem out of the way, consider implementing your
hashCode
method in a more "frugal" way. Rather than creating a throw-away(this.getCarName() + this.getCarModel())
string simply for the purpose of obtaining its hash code, consider rewriting the method as follows:or in Java 1.7+ you could write
The problem is not with
.hashCode()
; the problem is that you don't override.equals()
!Look at your prototype:
Now have a look at the documentation for
Object
...What you should override is:
Hence the error. You did implement hashCode correctly, however you use
Object
's.equals()
implementation.