Let say I have a class Car with fields color and model. I need to store cars in a collection in which I will have no duplicates (no 2 same cars). In the example below I am using a HashMap.
According to the Java documentation, if we have 2 Car objects car1 and car2 such that car1.equals(car2) == true
, then it must also hold that car1.hashCode() == car2.hashCode()
. So in this example, if I wanted to compare cars just by their color then I would use only the color field in equals()
and hashCode()
, as I did it in my code, and it works perfectly fine.
public class Car {
String color;
String model;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((color == null) ? 0 : color.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Car other = (Car) obj;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
return true;
}
public Car(String color, String model) {
super();
this.color = color;
this.model = model;
}
@Override
public String toString() {
return color + "\t" + model;
}
public static void main(String[] args) {
Map<Car, Car> cars = new HashMap<Car, Car>();
Car a = new Car("red", "audi");
Car b = new Car("red", "bmw");
Car c = new Car("blue", "audi");
cars.put(a, a);
cars.put(b, b);
cars.put(c, c);
for(Car car : cars.keySet()) {
System.out.println(cars.get(car));
}
}
}
The output is:
- red bmw
- blue audi
as expected.
So good so far. Now, I am experimenting with other ways for comparing 2 cars. I have provided a function to measure similarity between 2 cars. For the sake of the argument let say I have a method double similarity(Car car1, Car car2)
which returns a double value in the interval [0,1]. I consider 2 cars to be equal if their similarity function returns value greater than 0.5. Then, I override the equals method:
@Override
public boolean equals(Object obj) {
Car other = (Car) obj;
return similarity(this, other) > 0.5;
}
Now, I don't know how to override the hashCode() to be sure that always will hold the hashCode - equals contract, e.g. 2 equal objects to have always equal hashCodes.
I have been thinking of using TreeMap instead of HashMap, just to avoid overriding the hashCode because I have no idea how to do it properly. But, I don't need any sorting, so I find using TreeMap in this problem not appropriate, and I think it would be more expensive in terms of complexity.
It would be very helpful if you could suggest me: a way of overriding the hashCode
or an alternative of a different structure which would be more appropriate for my problem.
Thank you in advance!
Although sprinter has covered some of the issues with your strategy, there is a more contract-based issue with your method. According to the Javadoc,
[
equals
] is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true
However, x
can be similar to y
and y
can be similar to z
with x being too far from z
to be similar, so your equals
method doesn't work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With