{"id":"equals-hashcode-writing-hashcode","slug":"writing-hashcode","title":"Writing hashCode","text":"### A hashCode for Seat\n\nA 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.\n\nWhat 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:\n\n```java\npublic int hashCode() {\n    return 31 * this.row.hashCode() + this.number;\n}\n```\n\n- 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.\n- Why times 31? `this.row.hashCode() + this.number` would 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 own `hashCode` uses the same trick.\n- Use only the values that `equals` compares. A value that `equals` ignores could give two equal seats different hash codes, and that breaks the rule. (The last challenge of this step shows what happens then.)\n- If the calculation grows past the largest `int` and wraps around, that's fine: any `int` will do as a hash code.\n\nHere's step 1's hash map program again. Only Seat has changed: it has both methods now.\n\n```java\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Seat, String> holders = new HashMap<>();\n        Seat seat = new Seat(\"B\", 7);\n        holders.put(seat, \"Ada\");\n        System.out.println(holders.get(seat));\n        System.out.println(holders.get(new Seat(\"B\", 7)));\n        System.out.println(holders.containsKey(new Seat(\"B\", 7)));\n\n        holders.put(new Seat(\"B\", 7), \"Ben\");\n        System.out.println(holders.size());\n    }\n}\n// ==== Seat.java ====\npublic class Seat {\n    private String row;\n    private int number;\n\n    public Seat(String row, int number) {\n        this.row = row;\n        this.number = number;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Seat)) {\n            return false;\n        }\n        Seat other = (Seat) compared;\n        return this.row.equals(other.row) && this.number == other.number;\n    }\n\n    public int hashCode() {\n        return 31 * this.row.hashCode() + this.number;\n    }\n\n    public String toString() {\n        return this.row + this.number;\n    }\n}\n```\n\n```output\nAda\nAda\ntrue\n1\n```\n\n- A new B7 seat now has the same hash code as the key in the map, so `get` and `containsKey` look in the right bucket, and `equals` confirms the match.\n- `put` with an equal key replaces the value, as it does with String keys: the map has one B7 seat, and Ben holds it now.\n- 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 a `hashCode` of its own, is never printed in this course.\n\n### Objects.hash\n\nWith 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:\n\n```java\npublic int hashCode() {\n    return Objects.hash(this.row, this.number);\n}\n```\n\n- `Seat.java` then needs the line `import java.util.Objects;` at the top, just as a class that uses `ArrayList` needs its import.\n- Give it the same values that `equals` compares. It takes numbers as well as objects.\n- It doesn't give the same number as the hand-written version (for B7 it's 3014), and it doesn't need to: any `hashCode` that follows the rule works.\n- A value that's `null` counts as 0, where `this.row.hashCode()` would crash with a NullPointerException.\n\n### Letting the editor write them\n\nWriting `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.\n","task":"The board game's squares get hash codes of their own. In `Square.java`, write `hashCode`: 31 times the hash code of the column, plus the row. The check lets players claim squares, and looks them up with new squares:\n\n```java\nHashMap<Square, String> owners = new HashMap<>();\nowners.put(new Square(\"A\", 1), \"Ada\");\nowners.put(new Square(\"E\", 1), \"Ben\");\nowners.put(new Square(\"A\", 1), \"Cy\");\nSystem.out.println(owners.get(new Square(\"A\", 1)));\nSystem.out.println(owners.containsKey(new Square(\"E\", 2)));\nSystem.out.println(owners.size());\nSystem.out.println(new Square(\"E\", 1).hashCode());\n```\n\nand expects:\n\n```\nCy\nfalse\n2\n2140\n```\n","kind":"code","seed":"// ==== Square.java ====\npublic class Square {\n    private String column;\n    private int row;\n\n    public Square(String column, int row) {\n        this.column = column;\n        this.row = row;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Square)) {\n            return false;\n        }\n        Square other = (Square) compared;\n        return this.column.equals(other.column) && this.row == other.row;\n    }\n\n    // Write the hashCode method here.\n\n    public String toString() {\n        return this.column + this.row;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Square, String> owners = new HashMap<>();\n        owners.put(new Square(\"A\", 1), \"Ada\");\n        owners.put(new Square(\"E\", 1), \"Ben\");\n        owners.put(new Square(\"A\", 1), \"Cy\");\n        System.out.println(owners.get(new Square(\"A\", 1)));\n        System.out.println(owners.containsKey(new Square(\"E\", 2)));\n        System.out.println(owners.size());\n        System.out.println(new Square(\"E\", 1).hashCode());\n    }\n}\n","solution":"// ==== Square.java ====\npublic class Square {\n    private String column;\n    private int row;\n\n    public Square(String column, int row) {\n        this.column = column;\n        this.row = row;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Square)) {\n            return false;\n        }\n        Square other = (Square) compared;\n        return this.column.equals(other.column) && this.row == other.row;\n    }\n\n    public int hashCode() {\n        return 31 * this.column.hashCode() + this.row;\n    }\n\n    public String toString() {\n        return this.column + this.row;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Square, String> owners = new HashMap<>();\n        owners.put(new Square(\"A\", 1), \"Ada\");\n        owners.put(new Square(\"E\", 1), \"Ben\");\n        owners.put(new Square(\"A\", 1), \"Cy\");\n        System.out.println(owners.get(new Square(\"A\", 1)));\n        System.out.println(owners.containsKey(new Square(\"E\", 2)));\n        System.out.println(owners.size());\n        System.out.println(new Square(\"E\", 1).hashCode());\n    }\n}\n","hints":["The header is `public int hashCode() {`. The column is a String, so its hash code is `this.column.hashCode()`.","`return 31 * this.column.hashCode() + this.row;`: the two values that `equals` compares, and nothing else."],"tests":[{"name":"Test 1","stdin":"","call":"HashMap<Square, String> owners = new HashMap<>();\nowners.put(new Square(\"A\", 1), \"Ada\");\nowners.put(new Square(\"E\", 1), \"Ben\");\nowners.put(new Square(\"A\", 1), \"Cy\");\nSystem.out.println(owners.get(new Square(\"A\", 1)));\nSystem.out.println(owners.containsKey(new Square(\"E\", 2)));\nSystem.out.println(owners.size());\nSystem.out.println(new Square(\"E\", 1).hashCode());\n","expect":"Cy\nfalse\n2\n2140","hidden":false},{"name":"Test 2","stdin":"","call":"HashMap<Square, String> owners = new HashMap<>();\nowners.put(new Square(\"F\", 6), \"Ada\");\nString letter = \"F\";\nSystem.out.println(owners.get(new Square(letter, 6)) + \" \" + owners.get(new Square(\"F\", 5)) + \" \" + owners.get(new Square(\"E\", 6)));\nSystem.out.println(new Square(\"A\", 1).hashCode() + \" \" + new Square(\"B\", 2).hashCode());\n","expect":"Ada null null\n2016 2048","hidden":true},{"name":"Test 3","stdin":"","call":"HashMap<Square, Integer> visits = new HashMap<>();\nfor (int row = 1; row <= 6; row++) {\n    visits.put(new Square(\"C\", row), row * 10);\n}\nvisits.put(new Square(\"C\", 3), 99);\nSystem.out.println(visits.size() + \" \" + visits.get(new Square(\"C\", 3)) + \" \" + visits.get(new Square(\"C\", 6)));\n","expect":"6 99 60","hidden":true}],"require":[{"pattern":"\\bpublic\\s+int\\s+hashCode\\s*\\(\\s*\\)","message":"Write the header exactly as `public int hashCode()`, so that the map uses your method."}],"forbid":[],"more":[{"task":"The coin collector from step 1 now counts coins in a `HashMap<Coin, Integer>`. `Coin.java` has its `equals`. Give it a `hashCode` too, with `Objects.hash` and the same three values that `equals` compares. Then, in `Main.java`, write the method `countCoins(ArrayList<Coin> coins)`, which returns a `HashMap<Coin, Integer>` from each different coin to how many times it's in the list. The check runs:\n\n```java\nArrayList<Coin> box = new ArrayList<>();\nbox.add(new Coin(\"Italy\", 2002, 50));\nbox.add(new Coin(\"Kenya\", 2005, 10));\nbox.add(new Coin(\"Italy\", 2002, 50));\nbox.add(new Coin(\"Italy\", 2002, 20));\nHashMap<Coin, Integer> counts = countCoins(box);\nSystem.out.println(counts.get(new Coin(\"Italy\", 2002, 50)));\nSystem.out.println(counts.get(new Coin(\"Kenya\", 2005, 10)));\nSystem.out.println(counts.size());\n```\n\nand expects:\n\n```\n2\n1\n3\n```\n","kind":"code","seed":"// ==== Coin.java ====\npublic class Coin {\n    private String country;\n    private int year;\n    private int cents;\n\n    public Coin(String country, int year, int cents) {\n        this.country = country;\n        this.year = year;\n        this.cents = cents;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Coin)) {\n            return false;\n        }\n        Coin other = (Coin) compared;\n        return this.country.equals(other.country) && this.year == other.year && this.cents == other.cents;\n    }\n\n    // Write the hashCode method here.\n\n    public String toString() {\n        return this.country + \" \" + this.year + \" \" + this.cents + \"c\";\n    }\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Coin> box = new ArrayList<>();\n        box.add(new Coin(\"Italy\", 2002, 50));\n        box.add(new Coin(\"Kenya\", 2005, 10));\n        box.add(new Coin(\"Italy\", 2002, 50));\n        box.add(new Coin(\"Italy\", 2002, 20));\n        HashMap<Coin, Integer> counts = countCoins(box);\n        System.out.println(counts.get(new Coin(\"Italy\", 2002, 50)));\n        System.out.println(counts.get(new Coin(\"Kenya\", 2005, 10)));\n        System.out.println(counts.size());\n    }\n\n    // Write the method countCoins here.\n}\n","solution":"// ==== Coin.java ====\nimport java.util.Objects;\n\npublic class Coin {\n    private String country;\n    private int year;\n    private int cents;\n\n    public Coin(String country, int year, int cents) {\n        this.country = country;\n        this.year = year;\n        this.cents = cents;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Coin)) {\n            return false;\n        }\n        Coin other = (Coin) compared;\n        return this.country.equals(other.country) && this.year == other.year && this.cents == other.cents;\n    }\n\n    public int hashCode() {\n        return Objects.hash(this.country, this.year, this.cents);\n    }\n\n    public String toString() {\n        return this.country + \" \" + this.year + \" \" + this.cents + \"c\";\n    }\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Coin> box = new ArrayList<>();\n        box.add(new Coin(\"Italy\", 2002, 50));\n        box.add(new Coin(\"Kenya\", 2005, 10));\n        box.add(new Coin(\"Italy\", 2002, 50));\n        box.add(new Coin(\"Italy\", 2002, 20));\n        HashMap<Coin, Integer> counts = countCoins(box);\n        System.out.println(counts.get(new Coin(\"Italy\", 2002, 50)));\n        System.out.println(counts.get(new Coin(\"Kenya\", 2005, 10)));\n        System.out.println(counts.size());\n    }\n\n    public static HashMap<Coin, Integer> countCoins(ArrayList<Coin> coins) {\n        HashMap<Coin, Integer> counts = new HashMap<>();\n        for (Coin coin : coins) {\n            counts.put(coin, counts.getOrDefault(coin, 0) + 1);\n        }\n        return counts;\n    }\n}\n","hints":["`hashCode` gives `Objects.hash` the three values that `equals` compares, and `Coin.java` needs `import java.util.Objects;` at the top. `countCoins` makes a new `HashMap<Coin, Integer>`, goes through the coins, adds one to each coin's count, and returns the map.","The method is `public int hashCode() { return Objects.hash(this.country, this.year, this.cents); }`. In the loop of `countCoins`, count as module 31 did: `counts.put(coin, counts.getOrDefault(coin, 0) + 1);`."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Coin> box = new ArrayList<>();\nbox.add(new Coin(\"Italy\", 2002, 50));\nbox.add(new Coin(\"Kenya\", 2005, 10));\nbox.add(new Coin(\"Italy\", 2002, 50));\nbox.add(new Coin(\"Italy\", 2002, 20));\nHashMap<Coin, Integer> counts = countCoins(box);\nSystem.out.println(counts.get(new Coin(\"Italy\", 2002, 50)));\nSystem.out.println(counts.get(new Coin(\"Kenya\", 2005, 10)));\nSystem.out.println(counts.size());\n","expect":"2\n1\n3","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Coin> box = new ArrayList<>();\nSystem.out.println(countCoins(box).size());\nfor (int year = 2000; year <= 2003; year++) {\n    box.add(new Coin(\"Chile\", year, 100));\n    box.add(new Coin(\"Chile\", 2001, 100));\n}\nHashMap<Coin, Integer> counts = countCoins(box);\nSystem.out.println(counts.size() + \" \" + counts.get(new Coin(\"Chile\", 2001, 100)) + \" \" + counts.get(new Coin(\"Chile\", 2003, 100)));\nSystem.out.println(counts.get(new Coin(\"Chile\", 2004, 100)));\n","expect":"0\n4 5 1\nnull","hidden":true},{"name":"Test 3","stdin":"","call":"Coin a = new Coin(\"Kenya\", 2005, 10);\nString start = \"Ken\";\nCoin b = new Coin(start + \"ya\", 2005, 10);\nSystem.out.println(a.hashCode() == b.hashCode());\nSystem.out.println(a.hashCode() == new Coin(\"Kenya\", 2005, 20).hashCode());\n","expect":"true\nfalse","hidden":true}],"require":[{"pattern":"\\bpublic\\s+int\\s+hashCode\\s*\\(\\s*\\)","message":"Write the header exactly as `public int hashCode()`, so that the map uses your method."},{"pattern":"\\bObjects\\s*\\.\\s*hash\\s*\\(","message":"Work out the hash code with `Objects.hash`."},{"pattern":"\\bpublic\\s+static\\s+HashMap<Coin,\\s*Integer>\\s+countCoins\\s*\\(\\s*ArrayList<Coin>\\s+\\w+\\s*\\)","message":"Write the method as `public static HashMap<Coin, Integer> countCoins(ArrayList<Coin> coins)`."}],"forbid":[]},{"task":"A stamp has a country, a year and a condition, such as `mint` or `used`. `Stamp`'s `equals` says two stamps are equal when the country and the year match, whatever their condition. But its `hashCode` uses the condition too. What does this program print?\n","kind":"predict","seed":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Stamp, String> album = new HashMap<>();\n        album.put(new Stamp(\"Chile\", 1970, \"mint\"), \"page 4\");\n\n        Stamp used = new Stamp(\"Chile\", 1970, \"used\");\n        System.out.println(used.equals(new Stamp(\"Chile\", 1970, \"mint\")));\n        System.out.println(album.get(used));\n        System.out.println(album.get(new Stamp(\"Chile\", 1970, \"mint\")));\n        System.out.println(album.containsKey(new Stamp(\"Chile\", 1971, \"mint\")));\n    }\n}\n// ==== Stamp.java ====\nimport java.util.Objects;\n\npublic class Stamp {\n    private String country;\n    private int year;\n    private String condition;\n\n    public Stamp(String country, int year, String condition) {\n        this.country = country;\n        this.year = year;\n        this.condition = condition;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Stamp)) {\n            return false;\n        }\n        Stamp other = (Stamp) compared;\n        return this.country.equals(other.country) && this.year == other.year;\n    }\n\n    public int hashCode() {\n        return Objects.hash(this.country, this.year, this.condition);\n    }\n}\n","solution":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Stamp, String> album = new HashMap<>();\n        album.put(new Stamp(\"Chile\", 1970, \"mint\"), \"page 4\");\n\n        Stamp used = new Stamp(\"Chile\", 1970, \"used\");\n        System.out.println(used.equals(new Stamp(\"Chile\", 1970, \"mint\")));\n        System.out.println(album.get(used));\n        System.out.println(album.get(new Stamp(\"Chile\", 1970, \"mint\")));\n        System.out.println(album.containsKey(new Stamp(\"Chile\", 1971, \"mint\")));\n    }\n}\n// ==== Stamp.java ====\nimport java.util.Objects;\n\npublic class Stamp {\n    private String country;\n    private int year;\n    private String condition;\n\n    public Stamp(String country, int year, String condition) {\n        this.country = country;\n        this.year = year;\n        this.condition = condition;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Stamp)) {\n            return false;\n        }\n        Stamp other = (Stamp) compared;\n        return this.country.equals(other.country) && this.year == other.year;\n    }\n\n    public int hashCode() {\n        return Objects.hash(this.country, this.year, this.condition);\n    }\n}\n","hints":["`equals` ignores the condition, so the used stamp is equal to the mint one. But the condition is part of the hash code, so their hash codes differ, and the map looks for the used stamp with the wrong hash code.","A new mint Chile 1970 stamp has the same values as the key, so the same hash code, and the map finds it. The 1971 stamp isn't equal to any key."],"tests":[{"name":"Output","stdin":"","expect":"true\nnull\npage 4\nfalse","hidden":false}],"require":[],"forbid":[],"lines":["true","null","page 4","false"]}]}