2

Simple question. I have an object:

class User {

    int id;
    String username;

    public User() {
    }

    public User(int id, String username) {
        this.id = id;
        this.username = username;
    }

    @Override
    public String toString() {
        return id + " - " + username;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + this.id;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final User other = (User) obj;
        return this.id == other.id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public int getId() {
        return id;
    }
}

Whose equality is determined based on int id (it is a database id).

Netbeans auto-generated this hashCode() method:

@Override
public int hashCode() {
    int hash = 7;
    hash = 31 * hash + this.id;
    return hash;
}

The question is: is there any advantage to this over just returning the (already) unique int id ?

@Override
public int hashCode() {
    return id;
}

Collisions are impossible either way.

Right?

ryvantage
  • 13,064
  • 15
  • 63
  • 112
  • 1
    The goal of hashCode() is not to avoid collisions. – peter.petrov Mar 31 '14 at 21:30
  • In a way it depends on how you implement `equals`. What if you want to add a clone of a data value? – Rogue Mar 31 '14 at 21:31
  • [Joshua Block: Effective Java](http://uet.vnu.edu.vn/~chauttm/e-books/java/Effective.Java.2nd.Edition.May.2008.3000th.Release.pdf), Item 9. – Boris the Spider Mar 31 '14 at 21:32
  • As explained in SCJP Book by Kathy Siera : The Idea of hashCode is like buckets, more unique hashcodes more buckets your objects will go into, once the hashcode matches, then it will use equals operator to check for equality – Javaboy Mar 31 '14 at 21:36

3 Answers3

1

1) You can do:

@Override
public int hashCode() {
    return 1; // or any int constant here
}

2) If you have say 1,000,000 such objects in
the DB, you could maybe do something like:

@Override
public int hashCode() {
    return id % 10000;
}

This way you'll have 10000 buckets for 1,000,000 objects.

3) You may turn id into an Integer and just do this:

@Override
public int hashCode() {
    return id.hashCode();
}

or which is equivalent do:

@Override
public int hashCode() {
    return id;
}

1) and 3) are boundary cases for a hashCode implementation.
Approach 2) is somewhere in the middle.

peter.petrov
  • 38,363
  • 16
  • 94
  • 159
  • 1
    This is confusing - why would you voluntarily increase the risk of collision in (i) or use the Integer's hashcode, which returns the int value itself in (ii)? – assylias Mar 31 '14 at 21:36
  • @assylias Just want to demonstrate that both are valid hash functions in the OP's case. These are two boundary cases in a way. Actually the real boundary case is not `return id % 10000;` but `return 1;`. – peter.petrov Mar 31 '14 at 21:37
1

The Object.hashCode() javadoc tells you everything you need to know to answer your question.

The general contract of hashCode is:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

Community
  • 1
  • 1
Mike B
  • 5,390
  • 2
  • 23
  • 45
0

There is a bijection between id and 31 * 7 + id so returning id instead is equivalent. I would therefore simply return id; and remove unnecessary calculation/complication.

But would that constitute a compliant hashcode method? Let's go back to the javadoc:

The general contract of hashCode is:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

Does it work in your case?

  • (i) is hopefully satisfied: you won't change the id arbitrarily on a given object, right?
  • (ii) if two users are equal they have the same hashcode: yes because your equals is based on the id too
  • (iii) is satisfied
Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783