3

Possible Duplicate:
In Java, why must equals() and hashCode() be consistent?

I read that one should always hascode() when overriding equals().

Can anyone give a practical example of why it might be wrong otherwise? i.e. Problems that might arise when overriding equals() but not hashCode().

Is it necessary to write a robust hasCode() function whenever we override equals()? Or a trivial implementation is enough?

For example,

A poor implementation such as the below is good enough to satisfy the contract between equals() & hashCode()?

public int hashCode() {
   return 91;
}
Community
  • 1
  • 1
  • http://stackoverflow.com/questions/27581/overriding-equals-and-hashcode-in-java – Aviram Segal Dec 10 '12 at 16:04
  • @Blam Yes, I see that all the values are going to be in a single hash bucket. If we exclude the performance, is there any other problem with that? Or more precisely, is it going to break the program functionality-wise under any conditions? – user1885220 Dec 10 '12 at 16:09
  • It will not break anything to my knowledge. I trust you are not going to use this in a collection. – paparazzo Dec 10 '12 at 16:18

5 Answers5

4

Both equals and hashcode are based on the principle of object's unicity. If equals returns true the hashcode of both objects must be the same, otherwise hash based structures and algorithms could have undefined results.

Think of a hash based structure such as a HashMap. hashcode will be invoked as a base to get the key's reference, not equals, making it impossible in most cases to find the key. Also, a poor implementation of hashcode will create collisions (multiple objects with the same hashcode, which one is the "correct" one?) that affect performance.

IMHO, overriding equals OR hashcode (instead of overriding both) should be considered a code smell or, at least, a potential bugs source. That is, unless you're 100% sure it won't affect your code sooner or later (when are we so sure anyway?).

Note: There are various libraries that provide support for this by having equals and hashcode builders, like Apache Commons with HashcodeBuilder and EqualsBuilder.

Fritz
  • 9,987
  • 4
  • 30
  • 49
  • In Java 7, there's the [`Objects`](http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html) class with its hashing methods as well. – Brian Dec 10 '12 at 16:14
  • @Brian Indeed! I'm so used to Apache Commons that I forgot that one ;) – Fritz Dec 10 '12 at 16:15
2

equals() and hashCode() are used conjunctively in certain collections, such as HashSet and HashMap, so you have to make sure that if you use these collections, you override hashCode according to the contract.

If you don't override hashCode at all, then you'll have problems with HashSet and HashMap. In particular, two objects that are "equal" may be put in different hash buckets even though they should be equal.

If you do override hashCode, but do so poorly, then you'll have performance issues. All your entries for HashSet and HashMap will be put into the same bucket, and you'll lose the O(1) performance and have O(n) instead. This is because the data structure essentially becomes a linearly-checked linked list.

As for breaking programs outside of these conditions, it's not likely, but you never know when an API (especially in 3rd-party libraries) is going to depend on this contract. The contract is upheld for objects that don't implement either of them, so it's conceivable that a library may depend on this somewhere without using hash buckets.

In any case, implementing a good hashCode is easy, especially if you're using an IDE. Eclipse and Netbeans both have the ability to generate equals and hashCode for you in a way that all contracts are followed, including the inverse rules of equals (the assertion that a.equals(b) == b.equals(a)). All you need to do is select the fields you want to be included and go.

Brian
  • 17,079
  • 6
  • 43
  • 66
  • Thank you for the answer. I think, you have given a fair explanation when it might be a problem with a poor implementation. – user1885220 Dec 10 '12 at 16:28
2

Here's some code that illustrates a bug you can introduce by not implementing hashCode(): Set.contains() will first check the hashCode() of an object, and then check .equals(). So, if you don't implement both, .contains() will not behave in an intuitive way:

public class ContainsProblem {

// define a class that implements equals, without implementing hashcode
class Car {
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Car)) return false;
        Car car = (Car) o;
        if (name != null ? !name.equals(car.name) : car.name != null) return false;
        return true;
    }

    public String getName() {return name;}

    public Car(String name) { this.name = name;}
}

public static void main(String[] args) {
    ContainsProblem oc = new ContainsProblem();

    ContainsProblem.Car ford = oc.new Car("ford");
    ContainsProblem.Car chevy = oc.new Car("chevy");
    ContainsProblem.Car anotherFord = oc.new Car("ford");
    Set cars = Sets.newHashSet(ford,chevy);

    // if the set of cars contains a ford, a ford is equal to another ford, shouldn't
    // the set return the same thing for both fords? without hashCode(), it won't:
    if (cars.contains(ford) && ford.equals(anotherFord) && !cars.contains(anotherFord)) {
        System.out.println("oh noes, why don't we have a ford? isn't this a bug?");
    }
}
}
Paul Sanwald
  • 10,899
  • 6
  • 44
  • 59
1

Your trivial implementation is correct, but would kill the performance of hash-based collections.

The default implementation (provided by Object) would break the contract if two different instances of your class compared equal.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
0

I suggest reading Joshua Bloch's "Effective Java" Chapter 3 "Methods Common to All Objects". Nobody can explaing better than him. He He led the design and implementation of numerous Java platform features.

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275