{"id":"equals-hashcode-what-hashcode-is","slug":"what-hashcode-is","title":"What a hash code is","text":"### A number for every object\n\nEvery object has a method `hashCode()`, just as every object has `equals` and `toString`. It returns an `int` called the object's **hash code**: a number worked out from the object, a kind of short summary of it. Strings and Integers have a `hashCode` of their own:\n\n```java\nSystem.out.println(\"abc\".hashCode());\nSystem.out.println(\"Ada\".hashCode());\n\nString start = \"Ad\";\nString built = start + \"a\";\nSystem.out.println(built == \"Ada\");\nSystem.out.println(built.equals(\"Ada\"));\nSystem.out.println(built.hashCode());\n\nSystem.out.println(Integer.valueOf(2024).hashCode());\n```\n\n```output\n96354\n65662\nfalse\ntrue\n65662\n2024\n```\n\n- A String's hash code is worked out from its characters. `built` is made while the program runs, so it's a different object from the `\"Ada\"` in the code, and `==` says `false`. But it has the same characters, so it's equal to `\"Ada\"`, and it has the same hash code.\n- String's `hashCode` starts from 0 and, for each character in turn, multiplies what it has by 31 and adds the character's code. The codes of `a`, `b` and `c` are 97, 98 and 99, so for `\"abc\"`: 0 * 31 + 97 is 97, 97 * 31 + 98 is 3105, and 3105 * 31 + 99 is 96354. A String of one character has that character's code as its hash code.\n- For longer Strings, the number soon grows past the largest `int` and wraps around (module 4), so a hash code can be any `int`, a negative one too. `\"Oakdale\".hashCode()` is -22733073.\n- An Integer's hash code is its own value.\n\n### How a hash map uses it\n\nA hash map keeps its entries in many small groups, called **buckets**, and the key's hash code decides which bucket an entry goes into:\n\n- `put(key, value)` works out the key's hash code, picks a bucket from it, and puts the key and the value there. If an equal key is in that bucket already, it replaces that key's value instead.\n- `get(key)` works out the hash code of the key it's given, goes straight to that bucket, and looks only at the keys there. It compares a key with `equals` only when the two hash codes are the same.\n\nSo a lookup looks at a few keys, not at all of them, and a hash map finds a key about as fast among a million keys as among ten. A list's `contains` compares with every element in turn, like module 28's linear search.\n\nHere's a picture of that with 8 buckets. One simple way to pick a bucket is the remainder of the hash code divided by the number of buckets. (Java's `HashMap` picks its bucket in a slightly different way, and adds more buckets as it grows, but the idea is the same.)\n\n| Key | Hash code | Bucket: hash code % 8 |\n| --- | --- | --- |\n| `\"Ada\"` | 65662 | 6 |\n| `\"Ben\"` | 66667 | 3 |\n| `\"Cy\"` | 2198 | 6 |\n\n`\"Ada\"` and `\"Cy\"` share bucket 6. `get(\"Cy\")` goes to bucket 6, finds two keys there, and the hash codes and `equals` tell it which one is `\"Cy\"`. `get(\"Ben\")` goes to bucket 3 and never looks at the other keys at all.\n\n### Why the seats weren't found\n\nSeat in step 1 has no `hashCode` of its own, so it has the one every class gets from Java. Like the `equals` every class gets, it knows nothing about rows and numbers: it gives, as far as it can, a different number to every object, even to two seats with the same values. Java makes no promise about those numbers: they can change from one run of the program to the next, and from one Java system to another. That's why this course never prints them.\n\nSo `new Seat(\"B\", 7)` almost certainly has a different hash code from the B7 seat in the map. Nothing promises that, but in practice two objects hardly ever get the same default hash code. `get` looks in the bucket of the new hash code, and even if that happens to be the right bucket, the hash codes differ, so `equals` is never called: `null`. The second `put` went the same way: it found no equal key, so it added a second B7.\n\n### The rule\n\nFor a hash map to work, `equals` and `hashCode` must agree. Java's documentation of `hashCode` sets out the rule:\n\n- If two objects are equal according to `equals`, calling `hashCode` on each of them must give the same `int`.\n- Two objects that aren't equal may have the same hash code. That's allowed, but different hash codes for different objects can make a hash map faster, since fewer keys share a bucket.\n- Calling `hashCode` on the same object again, while the program runs, must give the same number, as long as nothing that `equals` compares has changed.\n\nSeat breaks the first rule: its `equals` says two B7 seats are equal, but their default hash codes almost certainly differ. Strings and Integers follow it, as the program above showed with `built` and `\"Ada\"`. That's why module 31's String and Integer keys just worked.\n\nThe rule goes one way only. Equal objects must have equal hash codes, but equal hash codes don't make two objects equal. There are far more possible Strings than `int` values, so some different Strings must share a hash code. The last challenge of this step shows two of them.\n\nThat makes comparing hash codes a quick first check, which the MOOC calls **approximate comparison**: for a class that follows the rule, different hash codes mean that two objects aren't equal, and the same hash code means that they may be. Only `equals` gives the final answer. A hash map works this way: it calls `equals` only for keys whose hash code is the same.\n","task":"A ticket machine keeps the fare to each station, in cents, in a `HashMap<String, Integer>`. 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<String, Integer> fares = new HashMap<>();\n        fares.put(\"Oakdale\", 450);\n\n        String first = \"Oak\";\n        String typed = first + \"dale\";\n        System.out.println(typed == \"Oakdale\");\n        System.out.println(typed.equals(\"Oakdale\"));\n        System.out.println(typed.hashCode() == \"Oakdale\".hashCode());\n        System.out.println(fares.get(typed));\n        System.out.println(Integer.valueOf(450).hashCode());\n    }\n}\n","solution":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<String, Integer> fares = new HashMap<>();\n        fares.put(\"Oakdale\", 450);\n\n        String first = \"Oak\";\n        String typed = first + \"dale\";\n        System.out.println(typed == \"Oakdale\");\n        System.out.println(typed.equals(\"Oakdale\"));\n        System.out.println(typed.hashCode() == \"Oakdale\".hashCode());\n        System.out.println(fares.get(typed));\n        System.out.println(Integer.valueOf(450).hashCode());\n    }\n}\n","hints":["`typed` is made while the program runs, so it's a different object from the `\"Oakdale\"` in the code, and `==` says false. But its characters are the same, so `equals` says true.","Equal Strings always have equal hash codes, so the map finds the key and gives its value. An Integer's hash code is its own value."],"tests":[{"name":"Output","stdin":"","expect":"false\ntrue\ntrue\n450\n450","hidden":false}],"require":[],"forbid":[],"lines":["false","true","true","450","450"],"more":[{"task":"Work out buckets the way the table above does. Write the method `bucketOf(String key, int buckets)`, which returns the bucket of a key in a map with the given number of buckets: the remainder of the key's hash code divided by the number of buckets. A hash code can be negative, and then so is the remainder, so return it without its minus sign (`Math.abs`, module 7). The check runs:\n\n```java\nSystem.out.println(bucketOf(\"Ada\", 8));\nSystem.out.println(bucketOf(\"Ben\", 8));\nSystem.out.println(bucketOf(\"Cy\", 8));\n```\n\nand expects:\n\n```\n6\n3\n6\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(bucketOf(\"Ada\", 8));\n        System.out.println(bucketOf(\"Ben\", 8));\n        System.out.println(bucketOf(\"Cy\", 8));\n    }\n\n    // Write the method bucketOf here.\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(bucketOf(\"Ada\", 8));\n        System.out.println(bucketOf(\"Ben\", 8));\n        System.out.println(bucketOf(\"Cy\", 8));\n    }\n\n    public static int bucketOf(String key, int buckets) {\n        return Math.abs(key.hashCode() % buckets);\n    }\n}\n","hints":["`key.hashCode()` gives the hash code, and `%` gives the remainder: `key.hashCode() % buckets`.","Put it inside `Math.abs(...)`, so that a negative remainder loses its minus sign: `return Math.abs(key.hashCode() % buckets);`."],"tests":[{"name":"Test 1","stdin":"","call":"System.out.println(bucketOf(\"Ada\", 8));\nSystem.out.println(bucketOf(\"Ben\", 8));\nSystem.out.println(bucketOf(\"Cy\", 8));\n","expect":"6\n3\n6","hidden":false},{"name":"Test 2","stdin":"","call":"System.out.println(bucketOf(\"Oakdale\", 8));\nSystem.out.println(bucketOf(\"Lisbon\", 16));\nSystem.out.println(bucketOf(\"Grace Hopper\", 16));\n","expect":"1\n5\n12","hidden":true},{"name":"Test 3","stdin":"","call":"String start = \"Ad\";\nSystem.out.println(bucketOf(start + \"a\", 8) + \" \" + bucketOf(\"Ada\", 1) + \" \" + bucketOf(\"\", 5));\nSystem.out.println(bucketOf(\"Aa\", 5) == bucketOf(\"BB\", 5));\n","expect":"6 0 0\ntrue","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+int\\s+bucketOf\\s*\\(\\s*String\\s+\\w+\\s*,\\s*int\\s+\\w+\\s*\\)","message":"Write the method as `public static int bucketOf(String key, int buckets)`."},{"pattern":"\\.hashCode\\s*\\(","message":"Work out the key's hash code with `key.hashCode()`."}],"forbid":[]},{"task":"Two different Strings can have the same hash code. What does this program print? The character codes are 65 for `A`, 66 for `B` and 97 for `a`.\n","kind":"predict","seed":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(\"Aa\".hashCode());\n        System.out.println(\"BB\".hashCode());\n        System.out.println(\"Aa\".equals(\"BB\"));\n\n        HashMap<String, Integer> points = new HashMap<>();\n        points.put(\"Aa\", 1);\n        points.put(\"BB\", 2);\n        System.out.println(points.size());\n        System.out.println(points.get(\"Aa\"));\n    }\n}\n","solution":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(\"Aa\".hashCode());\n        System.out.println(\"BB\".hashCode());\n        System.out.println(\"Aa\".equals(\"BB\"));\n\n        HashMap<String, Integer> points = new HashMap<>();\n        points.put(\"Aa\", 1);\n        points.put(\"BB\", 2);\n        System.out.println(points.size());\n        System.out.println(points.get(\"Aa\"));\n    }\n}\n","hints":["Use String's recipe: start from 0, and for each character, multiply by 31 and add the code. For `\"Aa\"`: 0 * 31 + 65 is 65, and 65 * 31 + 97 is 2112. Work out `\"BB\"` the same way.","The hash codes are the same, but the Strings aren't equal. The map keeps both keys in the same bucket, and `equals` tells them apart, so nothing is lost."],"tests":[{"name":"Output","stdin":"","expect":"2112\n2112\nfalse\n2\n1","hidden":false}],"require":[],"forbid":[],"lines":["2112","2112","false","2","1"]}]}