1

Saw this in a book:

Given:

class SortOf {
  String name;
  int bal;
  String code;
  short rate;
  public int hashCode() {
    return (code.length() * bal);
  }
}

does the following:

public boolean equals(Object o) {
  return ((SortOf)o).code.length() * ((SortOf)o).bal * ((SortOf)o).rate == this.code.length() * this.bal * this.rate;
}

satisfy the equals contract?

Tom Tresansky
  • 17,860
  • 16
  • 81
  • 122

5 Answers5

4

Suppose SortOf A has code = "AA"; bal=2; rate=2 and SortOf B has code = "A"; bal=4; rate=2; Then for A, code.length = 2, bal = 2, rate = 2 and B has code.length = 1, bal = 4, rate=2. Then A.equals(B) but A.hashCode() != B.hashCode()

Apart from your other issues with the code, I believe this violates the contract.

Edited to add: Actually, it may be that this definition of equals() technically satisfies the contract for Object.equals(), which makes no demand on consistency with hashCode(). It's the contract for Object.hashCode() whose contract demands consistency with equals(). What's that about small minds and foolish consistency...? <andersoj leaves to apply to law school>

This equals() is reflexive, symmetric, transitive, consistent. I guess it violates the contract because .equals(null) throws an exception rather than returning false as required. All the equals() spec says about hashCode() is:

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

andersoj
  • 20,778
  • 6
  • 59
  • 72
  • I think your edit here is the answer. Technically, the question was only asking whether the EQUALS contract was valid. Even if it did break the HASHCODE contract by existing. What an awful question... – Tom Tresansky Oct 19 '10 at 16:20
  • 2
    The part about not returning `false` on a null parameter is enough to break the `equals()` contract. The implementation is not compliant, which should be your conclusion I suppose, completely ignoring hashCode in any capacity. – Mark Peters Oct 19 '10 at 16:34
3

No.

For starters, you'll get a ClassCastException at runtime (rather than just returning false) if o is not a SortOf.

There also a general contract (see link below):

Use the same set of fields that you use to compute equals() to compute hashCode().

The methods in your question do not do this.


Excellent Q&A on this topic: What issues should be considered when overriding equals and hashCode in Java?

Community
  • 1
  • 1
Matt Ball
  • 332,322
  • 92
  • 617
  • 683
  • And **no** because of: `((SortOf)o).code.length()`. Comparing the *length* of a string to test equality is not going to be reliable. – Kirk Woll Oct 19 '10 at 01:57
  • 2
    @Kirk Woll:Reliable != satisfies the contract. The method sucks, but my book says it did satisfy the contract and I was scratching my head... – Tom Tresansky Oct 19 '10 at 02:13
3

Joshua Bloch tells you precisely how to write and test equals and hashCode such that they conform to the contract.

Better yet, get an IDE that generates both perfectly for you. IntelliJ does a brilliant job at this and many other things.

duffymo
  • 293,097
  • 41
  • 348
  • 541
  • I'm really doing neither here, I'm analyzing an existing implementation. – Tom Tresansky Oct 19 '10 at 16:18
  • 1
    Given the feedback on the method you posted, I think you'll be writing and testing a new one soon. Bloch tells you how to assess those methods without asking here. Read the link - you'll learn something. – duffymo Oct 19 '10 at 17:28
  • I don't think you read the question...its not an implementation of mine, it's a question from a review book. I have read Effective Java, and reading this review book, I thought there WAS something wrong with the question and answer it provided. – Tom Tresansky Oct 20 '10 at 12:21
  • 1
    I did read the question, and I believe I understood it. The equals you posted is not the way Joshua Bloch would recommend that you write it, so my answer is no just like everyone else. I went one better and provided you with a positive example. You can choose whether or not you will follow it. – duffymo Oct 20 '10 at 12:36
1

No.

If the objects are equal, they must have the same hashcode.

However

 100 * 10 * 10  =  200 * 10 * 5    (equals)

but

 100 * 10  != 200 * 10    (hashCode)

In general, though, I think you develop the other way around: You have a natural idea what should make objects equal (which yours does not seem to fit), and then think about how to make a hash code to match that.

Thilo
  • 241,635
  • 91
  • 474
  • 626
1

Everyone else has piped up "No", but just to add, as a general rule, many IDE environments (IE Eclipse) offer equals()/hashCode() implementation generation. Generally speaking, you'll want to do that instead. Caveat though, if you're using something like Hibernate, it's very important not to construct it in a way that goes and invokes fetching of lazy-init'd large Collections.

jcalvert
  • 3,342
  • 2
  • 16
  • 13