Writing hashCode
A hashCode for Seat
A class gets hash codes of its own the same way it gets its own equals: by writing the method. The header must be exactly public int hashCode(), with no parameters and an int back. A method with any other name, even hashcode with a small c, is just a new method, and no hash map ever calls it.
What should it return? The rule says that equal seats must get equal hash codes, and two seats are equal when their rows and numbers are. So work the hash code out from those two values, and from nothing else:
public int hashCode() {
return 31 * this.row.hashCode() + this.number;
}
- The row is a String, and equal Strings have equal hash codes. The number is an
int, used as it is. So two equal seats give the same result, and the rule holds. - Why times 31?
this.row.hashCode() + this.numberwould follow the rule too, but many different seats would share a hash code. A one-letter String's hash code is the letter's code, so B7 would be 66 + 7 = 73, and so would C6 (67 + 6) and D5 (68 + 5). With the 31, B7 is 66 * 31 + 7 = 2053, and C6 is 67 * 31 + 6 = 2083. String's ownhashCodeuses the same trick. - Use only the values that
equalscompares. A value thatequalsignores could give two equal seats different hash codes, and that breaks the rule. (The last challenge of this step shows what happens then.) - If the calculation grows past the largest
intand wraps around, that's fine: anyintwill do as a hash code.
Here's step 1's hash map program again. Only Seat has changed: it has both methods now.
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<Seat, String> holders = new HashMap<>();
Seat seat = new Seat("B", 7);
holders.put(seat, "Ada");
System.out.println(holders.get(seat));
System.out.println(holders.get(new Seat("B", 7)));
System.out.println(holders.containsKey(new Seat("B", 7)));
holders.put(new Seat("B", 7), "Ben");
System.out.println(holders.size());
}
}public class Seat {
private String row;
private int number;
public Seat(String row, int number) {
this.row = row;
this.number = number;
}
public boolean equals(Object compared) {
if (this == compared) {
return true;
}
if (!(compared instanceof Seat)) {
return false;
}
Seat other = (Seat) compared;
return this.row.equals(other.row) && this.number == other.number;
}
public int hashCode() {
return 31 * this.row.hashCode() + this.number;
}
public String toString() {
return this.row + this.number;
}
}Ada
Ada
true
1- A new B7 seat now has the same hash code as the key in the map, so
getandcontainsKeylook in the right bucket, andequalsconfirms the match. putwith an equal key replaces the value, as it does with String keys: the map has one B7 seat, and Ben holds it now.- Seat's own hash code is worked out from its values, so it's the same on every run:
new Seat("B", 7).hashCode()is always 2053, and it's fine to print. Only the default one, of a class without ahashCodeof its own, is never printed in this course.
Objects.hash
With more values, combining them by hand gets long. The class Objects, in java.util, has a method for it: Objects.hash(...) takes any number of values, and combines their hash codes with 31, much as String's hashCode combines its characters. Seat's hashCode could be:
public int hashCode() {
return Objects.hash(this.row, this.number);
}
Seat.javathen needs the lineimport java.util.Objects;at the top, just as a class that usesArrayListneeds its import.- Give it the same values that
equalscompares. It takes numbers as well as objects. - It doesn't give the same number as the hand-written version (for B7 it's 3014), and it doesn't need to: any
hashCodethat follows the rule works. - A value that's
nullcounts as 0, wherethis.row.hashCode()would crash with a NullPointerException.
Letting the editor write them
Writing equals and hashCode is routine enough that most Java editors, such as IntelliJ IDEA, Eclipse and NetBeans, can generate both from the instance variables you pick, each with a line @Override above it, which module 34 explains. However they're written, write them together: Java's documentation of equals says that a class with its own equals generally needs its own hashCode too.