0

I am writing an app that has an "Achievements" system, similar to Stack Overflow's badges. I am also using SugarORM to store the progress of the achievements. This is the Achievement class:

public class Achievement extends SugarRecord<Achievement>{
    @StringRes
    public int shortNameId;
    @StringRes
    public int descriptionId;
    public int progressNow;
    public int fullProgress; 
    //I am afraid that Sugar ORM will ignore private fields 
    //so I made them public. Please tell me if Sugar ORM does
    //not ignore those.
}

Now I want to override equals. And that is easy enough.

@Override
public boolean equals (Object other) {
    if (other == null) return false;
    if (!(other instanceof Achievement)) return false;
    Achievement a = (Achievement)other;
    return a.shortNameId == shortNameId &&
            a.descriptionId == descriptionId &&
            a.fullProgress == fullProgress;
}

Then I remembered that I should always override hashCode if I override equals. According to Effective Java by Joshua Bloch, I wrote the hashCode method like this:

@Override
public int hashCode () {
    int result = 17;
    result = result * 31 + shortNameId;
    result = result * 31 + descriptionId;
    result = result * 31 + fullProgress;
    return result;
}

Then I though that I should change the implementation of equals to

@Override
public boolean equals (Object other) {
    if (other == null) return false;
    if (!(other instanceof Achievement)) return false;
    Achievement a = (Achievement)other;
    return a.hashCode() == hashCode ();
}

After that, I thought that if I overrode hashCode wrongly, equals would not work either. However, The above implementation seems "right" to me, because I think hash codes are what makes objects equal.

P.S. Don't tell me it's personal preference. I think there must be a standard for this, right? And also I am very willing to follow standards.

Sweeper
  • 213,210
  • 22
  • 193
  • 313

1 Answers1

3

In general a.hashCode()==b.hashCode() doesn't mean that a.equals(b) must be true. Therefore you shouldn't rely on hashCode to determine equality.

The other direction, however, is true. If a.equals(b) then a.hashCode() must be equal to b.hashCode().

Eran
  • 387,369
  • 54
  • 702
  • 768
  • So... my first implementation is fine? – Sweeper Nov 01 '15 at 08:30
  • Ok Thanks for your answer! I will accept it in 8 minutes! :) – Sweeper Nov 01 '15 at 08:32
  • I was happy to give the last undel vote to this pretty good question. If you still have high quality undeletion candidates (hint: "is:a deleted:1"), put them into your profil, as usual. – peterh Dec 18 '21 at 19:02
  • I disagree the answer in general. The essence of the hash codes are that no practical way should exist to find multiple objects with the same hash. If there is, then it is a serious sec hole (or bug). However, in this specific question, the hash function is very simple and even a random, unintentional collision is quite possible, saving this answer. – peterh Dec 19 '21 at 19:27