{"id":"object-interaction-equals","slug":"equals","title":"Equal objects","text":"### == compares references\n\nWhen are two objects the same? Here are two theater seats, both in row B, seat 7:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Seat mine = new Seat(\"B\", 7);\n        Seat yours = new Seat(\"B\", 7);\n        Seat same = mine;\n        System.out.println(mine == yours);\n        System.out.println(mine == same);\n        System.out.println(mine.equals(yours));\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 String toString() {\n        return this.row + this.number;\n    }\n}\n```\n\n```output\nfalse\ntrue\nfalse\n```\n\n- As in module 22, `==` on two objects asks whether both variables refer to the **same object**. `mine` and `yours` were made by two `new`s, so they're two objects, even though what's in them is the same. `Seat same = mine;` copies the reference, so `mine == same` is true.\n- Seat has no method called `equals`, yet `mine.equals(yours)` compiles. Every class gets a few methods from Java without writing them, among them `toString` and `equals`. The `toString` it gets gives the class name and a code (module 18), and the `equals` it gets does the same as `==`.\n\nYou've met this with Strings: `==` asks whether two Strings are the same object, while `equals` compares their letters. That's why text is always compared with `equals`. To make `equals` compare the contents of your own objects, the class writes its own `equals`, just as it writes its own `toString`.\n\n### Writing equals\n\nTwo seats are equal when they have the same row and the same number. Here's the `equals` method for Seat:\n\n```java\npublic 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\nLine by line:\n\n- The header must be exactly `public boolean equals(Object compared)`. `Object` is Java's type for any object at all, so `equals` can be given a Seat, a String, a list or anything else. Java's own methods, such as a list's `contains` in the next step, use only an `equals` with exactly this header. (The parameter's name can be anything; `compared` is a common one.)\n- `if (this == compared)`: when it's the very same object, it's certainly equal, and nothing else needs checking.\n- `compared instanceof Seat` is true when `compared` is a Seat object. Anything else, such as a String, can't be equal to a seat, so the method returns `false`. `instanceof` is false for `null` too, so `seat.equals(null)` gives `false` without a crash.\n- `Seat other = (Seat) compared;` is a **cast**. `compared` is a Seat, but its type says only `Object`, and an Object has no `row` or `number`. The cast lets the code use it as a Seat. It's safe here, because the line before made sure it is one.\n- The last line compares the contents: Strings with `equals`, numbers with `==`. As in the previous step, `other.row` may read the private variables, because this code is in the Seat class.\n\nWith the method in the class:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Seat mine = new Seat(\"B\", 7);\n        Seat yours = new Seat(\"B\", 7);\n        Seat next = new Seat(\"B\", 8);\n        System.out.println(mine == yours);\n        System.out.println(mine.equals(yours));\n        System.out.println(mine.equals(next));\n        System.out.println(mine.equals(\"B7\"));\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 String toString() {\n        return this.row + this.number;\n    }\n}\n```\n\n```output\nfalse\ntrue\nfalse\nfalse\n```\n\n`==` still says `false`: `mine` and `yours` are two objects. But `equals` now compares what's in them, and says they're equal. A String is never equal to a seat, even when it looks like the seat printed out: `\"B7\"` doesn't pass the `instanceof` check.\n\nWhat counts as equal is up to the class. Two seats are equal when the row and the number match. A class for library members might say two members are equal when their membership numbers match, whatever names they were written down with.\n\nNewer versions of Java can do the `instanceof` check and the cast in one go (`compared instanceof Seat other`), but in this course they're written as two separate steps.\n","task":"Two playing cards are equal when they have the same suit and the same rank. In `PlayingCard.java`, write the method `equals`, in the way shown above. The check runs:\n\n```java\nPlayingCard first = new PlayingCard(\"hearts\", 7);\nPlayingCard second = new PlayingCard(\"hearts\", 7);\nPlayingCard third = new PlayingCard(\"spades\", 7);\nSystem.out.println(first.equals(second));\nSystem.out.println(first.equals(third));\n```\n\nand expects:\n\n```\ntrue\nfalse\n```\n","kind":"code","seed":"// ==== PlayingCard.java ====\npublic class PlayingCard {\n    private String suit;\n    private int rank;\n\n    public PlayingCard(String suit, int rank) {\n        this.suit = suit;\n        this.rank = rank;\n    }\n\n    // Write the equals method here.\n\n    public String toString() {\n        return this.rank + \" of \" + this.suit;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        PlayingCard first = new PlayingCard(\"hearts\", 7);\n        PlayingCard second = new PlayingCard(\"hearts\", 7);\n        PlayingCard third = new PlayingCard(\"spades\", 7);\n        System.out.println(first.equals(second));\n        System.out.println(first.equals(third));\n    }\n}\n","solution":"// ==== PlayingCard.java ====\npublic class PlayingCard {\n    private String suit;\n    private int rank;\n\n    public PlayingCard(String suit, int rank) {\n        this.suit = suit;\n        this.rank = rank;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof PlayingCard)) {\n            return false;\n        }\n        PlayingCard other = (PlayingCard) compared;\n        return this.suit.equals(other.suit) && this.rank == other.rank;\n    }\n\n    public String toString() {\n        return this.rank + \" of \" + this.suit;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        PlayingCard first = new PlayingCard(\"hearts\", 7);\n        PlayingCard second = new PlayingCard(\"hearts\", 7);\n        PlayingCard third = new PlayingCard(\"spades\", 7);\n        System.out.println(first.equals(second));\n        System.out.println(first.equals(third));\n    }\n}\n","hints":["Follow the Seat's `equals` from the lesson, with PlayingCard in place of Seat: the same header, the same two checks and the cast, and at the end a comparison of the suit and the rank. The suit is a String, so it's compared with `equals`.","`public boolean equals(Object compared) {`, then `if (this == compared) { return true; }`, `if (!(compared instanceof PlayingCard)) { return false; }`, `PlayingCard other = (PlayingCard) compared;` and last `return this.suit.equals(other.suit) && this.rank == other.rank;`."],"tests":[{"name":"Test 1","stdin":"","call":"PlayingCard first = new PlayingCard(\"hearts\", 7);\nPlayingCard second = new PlayingCard(\"hearts\", 7);\nPlayingCard third = new PlayingCard(\"spades\", 7);\nSystem.out.println(first.equals(second));\nSystem.out.println(first.equals(third));\n","expect":"true\nfalse","hidden":false},{"name":"Test 2","stdin":"","call":"PlayingCard card = new PlayingCard(\"clubs\", 3);\nSystem.out.println(card.equals(new PlayingCard(\"clubs\", 4)));\nSystem.out.println(card.equals(card));\nSystem.out.println(card.equals(\"3 of clubs\"));\nSystem.out.println(card.equals(null));\n","expect":"false\ntrue\nfalse\nfalse","hidden":true},{"name":"Test 3","stdin":"","call":"String start = \"dia\";\nPlayingCard built = new PlayingCard(start + \"monds\", 12);\nPlayingCard written = new PlayingCard(\"diamonds\", 12);\nSystem.out.println(built.equals(written));\nSystem.out.println(written.equals(built));\n","expect":"true\ntrue","hidden":true}],"require":[{"pattern":"\\bpublic\\s+boolean\\s+equals\\s*\\(\\s*Object\\s+\\w+\\s*\\)","message":"Write the header exactly as `public boolean equals(Object compared)`, so Java uses your method."},{"pattern":"\\binstanceof\\s+PlayingCard\\b","message":"Check with `instanceof PlayingCard` that the compared object is a card, before the cast."},{"pattern":"\\(\\s*PlayingCard\\s*\\)","message":"Cast the compared object to a card: `PlayingCard other = (PlayingCard) compared;`."}],"forbid":[],"more":[{"task":"What does this program print? Here two members are equal when their membership numbers are the same.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Member a = new Member(1042, \"Ana Silva\");\n        Member b = new Member(1042, \"A. Silva\");\n        Member c = new Member(2077, \"Ana Silva\");\n        System.out.println(a.equals(b));\n        System.out.println(a.equals(c));\n        System.out.println(a == b);\n        System.out.println(b.equals(a));\n    }\n}\n// ==== Member.java ====\npublic class Member {\n    private int number;\n    private String name;\n\n    public Member(int number, String name) {\n        this.number = number;\n        this.name = name;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Member)) {\n            return false;\n        }\n        Member other = (Member) compared;\n        return this.number == other.number;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Member a = new Member(1042, \"Ana Silva\");\n        Member b = new Member(1042, \"A. Silva\");\n        Member c = new Member(2077, \"Ana Silva\");\n        System.out.println(a.equals(b));\n        System.out.println(a.equals(c));\n        System.out.println(a == b);\n        System.out.println(b.equals(a));\n    }\n}\n// ==== Member.java ====\npublic class Member {\n    private int number;\n    private String name;\n\n    public Member(int number, String name) {\n        this.number = number;\n        this.name = name;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Member)) {\n            return false;\n        }\n        Member other = (Member) compared;\n        return this.number == other.number;\n    }\n}\n","hints":["`equals` compares only the numbers, so the names don't matter at all. `a` and `b` have the same number, `a` and `c` don't.","`==` still asks whether two variables refer to the same object, and `a` and `b` were made by two `new`s."],"tests":[{"name":"Output","stdin":"","expect":"true\nfalse\nfalse\ntrue","hidden":false}],"require":[],"forbid":[],"lines":["true","false","false","true"]},{"task":"A parking app looks for one car by its license plate. `LicensePlate` has an `equals` method, but it has two problems. With the input `ABC-123`, the plates aren't equal, although the codes are the same: the codes are Strings, compared with `==`. And comparing a plate with something that isn't a plate, such as the String `\"ABC-123\"`, crashes the program with a `ClassCastException`, since `(LicensePlate)` can't turn a String into a plate.\n\nRewrite `equals` the way the lesson showed: the `this ==` check, `instanceof`, the cast, and the code compared with `equals`. `Main.java` is ready: it reads a code and prints whether that plate equals the wanted one, and then whether it equals the String `\"ABC-123\"`, which it never does, because a String isn't a plate. For the input `ABC-123` the program prints:\n\n```\ntrue\nfalse\n```\n","kind":"code","seed":"// ==== LicensePlate.java ====\npublic class LicensePlate {\n    private String code;\n\n    public LicensePlate(String code) {\n        this.code = code;\n    }\n\n    public boolean equals(Object compared) {\n        LicensePlate other = (LicensePlate) compared;\n        return this.code == other.code;\n    }\n\n    public String toString() {\n        return this.code;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        LicensePlate wanted = new LicensePlate(\"ABC-123\");\n        LicensePlate seen = new LicensePlate(scanner.nextLine());\n        System.out.println(seen.equals(wanted));\n        System.out.println(seen.equals(\"ABC-123\"));\n    }\n}\n","solution":"// ==== LicensePlate.java ====\npublic class LicensePlate {\n    private String code;\n\n    public LicensePlate(String code) {\n        this.code = code;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof LicensePlate)) {\n            return false;\n        }\n        LicensePlate other = (LicensePlate) compared;\n        return this.code.equals(other.code);\n    }\n\n    public String toString() {\n        return this.code;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        LicensePlate wanted = new LicensePlate(\"ABC-123\");\n        LicensePlate seen = new LicensePlate(scanner.nextLine());\n        System.out.println(seen.equals(wanted));\n        System.out.println(seen.equals(\"ABC-123\"));\n    }\n}\n","hints":["Before the cast, add the check: `if (!(compared instanceof LicensePlate)) { return false; }`. Then a String never reaches the cast. The `if (this == compared)` check goes first, as in the lesson.","The codes are Strings, so the last line is `return this.code.equals(other.code);`."],"tests":[{"name":"Test 1","stdin":"ABC-123\n","expect":"true\nfalse","hidden":false},{"name":"Test 2","stdin":"XYZ-999\n","expect":"false\nfalse","hidden":true},{"name":"Test 3","stdin":"abc-123\n","expect":"false\nfalse","hidden":true},{"name":"Test 4","stdin":"","call":"LicensePlate plate = new LicensePlate(\"KLM-4\");\nSystem.out.println(plate.equals(plate));\nSystem.out.println(plate.equals(null));\nString letters = \"KLM\";\nSystem.out.println(plate.equals(new LicensePlate(letters + \"-4\")));\n","expect":"true\nfalse\ntrue","hidden":true}],"require":[{"pattern":"\\binstanceof\\s+LicensePlate\\b","message":"Check with `instanceof LicensePlate` before the cast, so comparing with something else gives false instead of a crash."}],"forbid":[{"pattern":"\\.code\\s*==|==\\s*\\w+\\.code\\b","message":"The codes are Strings: compare them with `equals`, not `==`."}]}]}