{"id":"polymorphism-instanceof","slug":"instanceof-and-casts","title":"instanceof and casts","text":"In a game, an `ArrayList<Enemy>` holds goblins, trolls and bats, and a loop over it can call anything every Enemy has. But some enemies have more. A troll can regenerate, and a bat flies at some altitude, which the hero's weapon may or may not reach. Through an Enemy variable, those methods can't be called: the variable's type decides what you may call, and not every Enemy is a troll or a bat. This step shows how a program asks an object what it is, and then gets a variable of the more specific type.\n\nHere's the game's hierarchy. Enemy is abstract, since every enemy is some particular kind of enemy (module 34), and `Flying` is an interface with one method, `altitude()`:\n\n```\nObject\n  Enemy        (abstract)\n    Goblin\n    Troll\n    Bat        implements Flying\n```\n\n### instanceof\n\n`instanceof` asks whether an object has a type:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Enemy squeak = new Bat(\"Squeak\", 3);\n        System.out.println(squeak instanceof Bat);\n        System.out.println(squeak instanceof Enemy);\n        System.out.println(squeak instanceof Flying);\n        System.out.println(squeak instanceof Object);\n        System.out.println(squeak instanceof Troll);\n\n        Enemy nobody = null;\n        System.out.println(nobody instanceof Enemy);\n    }\n}\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n\n    @Override\n    public String toString() {\n        return this.name + \" (\" + this.health + \")\";\n    }\n}\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n// ==== Bat.java ====\npublic class Bat extends Enemy implements Flying {\n    private int altitude;\n\n    public Bat(String name, int altitude) {\n        super(name, 8);\n        this.altitude = altitude;\n    }\n\n    @Override\n    public int altitude() {\n        return this.altitude;\n    }\n}\n// ==== Flying.java ====\npublic interface Flying {\n    int altitude();\n}\n```\n\n```output\ntrue\ntrue\ntrue\ntrue\nfalse\nfalse\n```\n\n- `value instanceof Type` is `true` when the object that `value` refers to has that type. That's any of its types from step 1, not only its own class: a Bat is a Bat, an Enemy, a Flying and an Object.\n- It looks at the object, not at the variable. `squeak` is an Enemy variable, and `squeak instanceof Flying` is still `true`.\n- It's `false` for `null`, which isn't an object at all. So `instanceof` never crashes.\n- Module 23's `equals` used it in the same way, to check that the compared object is of the right class.\n\n### Casts\n\nWhen `instanceof` says yes, a **cast** gets a variable of that type. Here the flying enemies report their altitude, and the troll regenerates:\n\n```java\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Enemy> enemies = new ArrayList<>();\n        enemies.add(new Troll(\"Grak\", 30));\n        enemies.add(new Bat(\"Squeak\", 3));\n        enemies.add(new Goblin(\"Snip\", 20));\n        enemies.add(new Bat(\"Flit\", 12));\n\n        for (Enemy enemy : enemies) {\n            if (enemy instanceof Flying) {\n                Flying flyer = (Flying) enemy;\n                System.out.println(enemy.getName() + \" flies at \" + flyer.altitude() + \" meters\");\n            } else {\n                System.out.println(enemy.getName() + \" is on the ground\");\n            }\n        }\n\n        Enemy first = enemies.get(0);\n        if (first instanceof Troll) {\n            Troll troll = (Troll) first;\n            troll.regenerate();\n        }\n        System.out.println(first);\n    }\n}\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n\n    @Override\n    public String toString() {\n        return this.name + \" (\" + this.health + \")\";\n    }\n}\n// ==== Goblin.java ====\npublic class Goblin extends Enemy {\n    public Goblin(String name, int health) {\n        super(name, health);\n    }\n}\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n// ==== Bat.java ====\npublic class Bat extends Enemy implements Flying {\n    private int altitude;\n\n    public Bat(String name, int altitude) {\n        super(name, 8);\n        this.altitude = altitude;\n    }\n\n    @Override\n    public int altitude() {\n        return this.altitude;\n    }\n}\n// ==== Flying.java ====\npublic interface Flying {\n    int altitude();\n}\n```\n\n```output\nGrak is on the ground\nSqueak flies at 3 meters\nSnip is on the ground\nFlit flies at 12 meters\nGrak (35)\n```\n\n- `(Flying) enemy` is a cast, as in module 23's `equals`. It doesn't create an object, and it doesn't change one. It gives a reference to the same object, with the type Flying, so javac lets `flyer.altitude()` through.\n- `enemy` and `flyer` refer to the same bat. Through `enemy` the loop calls Enemy's `getName()`. Through `flyer` it calls the `altitude()` that Flying lists, and the bat's own version runs.\n- The `if` makes the cast safe: it runs only for objects that are Flying.\n- A cast to a class works the same way. `(Troll) first` gives a reference of type Troll to the troll at index 0. `troll` and `first` refer to the same object, the one in the list, so after `regenerate()`, printing `first` shows 35.\n\n### A wrong cast crashes\n\njavac accepts a cast whenever it *could* work. Whether it does is only known when the program runs:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Enemy snip = new Goblin(\"Snip\", 20);\n        Troll troll = (Troll) snip;\n        troll.regenerate();\n    }\n}\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n}\n// ==== Goblin.java ====\npublic class Goblin extends Enemy {\n    public Goblin(String name, int health) {\n        super(name, health);\n    }\n}\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n```\n\n```crash\nException in thread \"main\" java.lang.ClassCastException: class Goblin cannot be cast to class Troll (Goblin and Troll are in unnamed module of loader 'app')\n\tat Main.main(Main.java:4)\n```\n\n- `snip` is an Enemy variable, and an Enemy might be a troll, so javac lets `(Troll) snip` through. When the line runs, Java sees that the object is a goblin, and stops the program with a **ClassCastException**.\n- A cast never turns an object into another class. A goblin stays a goblin. The cast works only when the object already has the type.\n- So check with `instanceof` before a cast, unless the code can be sure of the type in some other way.\n- A cast that could never work doesn't compile at all. `(String) snip` is an error, since no Enemy can be a String: javac says `incompatible types: Enemy cannot be converted to String`.\n\n### instanceof, or a method of its own?\n\n`instanceof` fits when only some objects have what the code needs: the flying enemies' altitude, or a troll's `regenerate()`. When every kind has its own answer to the same question, it's the wrong tool. Say each enemy is worth some points when it's defeated. This works:\n\n```java\npublic static int points(Enemy enemy) {\n    if (enemy instanceof Goblin) {\n        return 10;\n    } else if (enemy instanceof Troll) {\n        return 50;\n    } else if (enemy instanceof Bat) {\n        return 5;\n    }\n    return 0;\n}\n```\n\nBut every new kind of enemy needs another `else if`, here and in every method written this way, and a forgotten one quietly gives 0 points. Instead, give Enemy an abstract method `points()`, and let each class write its own (module 34). Then the code asks `enemy.points()`, and javac makes every new kind of enemy say what it's worth. The next step builds a whole program in that way.\n","task":"The hero's spear reaches enemies on the ground, and flying enemies up to a given height. In `Main.java`, write the method `inReach(ArrayList<Enemy> enemies, int reach)`. It returns a new list of the names of the enemies the spear can hit, in the order of the list: every enemy that doesn't fly, and every flying enemy whose altitude is at most `reach`. Ask whether an enemy flies with `instanceof Flying`, not whether it's a Bat, so that flying enemies added to the game later count too. The check runs:\n\n```java\nArrayList<Enemy> enemies = new ArrayList<>();\nenemies.add(new Bat(\"Squeak\", 3));\nenemies.add(new Goblin(\"Snip\", 20));\nenemies.add(new Bat(\"Flit\", 12));\nenemies.add(new Goblin(\"Nab\", 15));\nSystem.out.println(inReach(enemies, 5));\n```\n\nand expects:\n\n```\n[Squeak, Snip, Nab]\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Enemy> enemies = new ArrayList<>();\n        enemies.add(new Bat(\"Squeak\", 3));\n        enemies.add(new Goblin(\"Snip\", 20));\n        enemies.add(new Bat(\"Flit\", 12));\n        enemies.add(new Goblin(\"Nab\", 15));\n        System.out.println(inReach(enemies, 5));\n    }\n\n    // Write the method inReach here.\n}\n\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n\n    @Override\n    public String toString() {\n        return this.name + \" (\" + this.health + \")\";\n    }\n}\n\n// ==== Flying.java ====\npublic interface Flying {\n    int altitude();\n}\n\n// ==== Goblin.java ====\npublic class Goblin extends Enemy {\n    public Goblin(String name, int health) {\n        super(name, health);\n    }\n}\n\n// ==== Bat.java ====\npublic class Bat extends Enemy implements Flying {\n    private int altitude;\n\n    public Bat(String name, int altitude) {\n        super(name, 8);\n        this.altitude = altitude;\n    }\n\n    @Override\n    public int altitude() {\n        return this.altitude;\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Enemy> enemies = new ArrayList<>();\n        enemies.add(new Bat(\"Squeak\", 3));\n        enemies.add(new Goblin(\"Snip\", 20));\n        enemies.add(new Bat(\"Flit\", 12));\n        enemies.add(new Goblin(\"Nab\", 15));\n        System.out.println(inReach(enemies, 5));\n    }\n\n    public static ArrayList<String> inReach(ArrayList<Enemy> enemies, int reach) {\n        ArrayList<String> names = new ArrayList<>();\n        for (Enemy enemy : enemies) {\n            if (enemy instanceof Flying) {\n                Flying flyer = (Flying) enemy;\n                if (flyer.altitude() <= reach) {\n                    names.add(enemy.getName());\n                }\n            } else {\n                names.add(enemy.getName());\n            }\n        }\n        return names;\n    }\n}\n\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n\n    @Override\n    public String toString() {\n        return this.name + \" (\" + this.health + \")\";\n    }\n}\n\n// ==== Flying.java ====\npublic interface Flying {\n    int altitude();\n}\n\n// ==== Goblin.java ====\npublic class Goblin extends Enemy {\n    public Goblin(String name, int health) {\n        super(name, health);\n    }\n}\n\n// ==== Bat.java ====\npublic class Bat extends Enemy implements Flying {\n    private int altitude;\n\n    public Bat(String name, int altitude) {\n        super(name, 8);\n        this.altitude = altitude;\n    }\n\n    @Override\n    public int altitude() {\n        return this.altitude;\n    }\n}\n","hints":["Go through the enemies with a for-each loop. An enemy for which `enemy instanceof Flying` is `false` is on the ground: add its `getName()` to the list.","For a flying one, cast first: `Flying flyer = (Flying) enemy;`. Then add its name only when `flyer.altitude() <= reach`. Return the list after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Enemy> enemies = new ArrayList<>();\nenemies.add(new Bat(\"Squeak\", 3));\nenemies.add(new Goblin(\"Snip\", 20));\nenemies.add(new Bat(\"Flit\", 12));\nenemies.add(new Goblin(\"Nab\", 15));\nSystem.out.println(inReach(enemies, 5));\n","expect":"[Squeak, Snip, Nab]","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Enemy> enemies = new ArrayList<>();\nenemies.add(new Bat(\"Flit\", 12));\nenemies.add(new Bat(\"Dusk\", 0));\nenemies.add(new Goblin(\"Snip\", 20));\nSystem.out.println(inReach(enemies, 12));\nSystem.out.println(inReach(enemies, 11));\nSystem.out.println(inReach(enemies, 0) + \" \" + enemies.size());\n","expect":"[Flit, Dusk, Snip]\n[Dusk, Snip]\n[Dusk, Snip] 3","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Enemy> enemies = new ArrayList<>();\nSystem.out.println(inReach(enemies, 5));\nenemies.add(new Bat(\"High\", 50));\nenemies.add(new Bat(\"Higher\", 80));\nSystem.out.println(inReach(enemies, 49));\nSystem.out.println(inReach(enemies, 80));\n","expect":"[]\n[]\n[High, Higher]","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+ArrayList\\s*<\\s*String\\s*>\\s+inReach\\s*\\(\\s*ArrayList\\s*<\\s*Enemy\\s*>\\s+\\w+\\s*,\\s*int\\s+\\w+\\s*\\)","message":"Write the method as `public static ArrayList<String> inReach(ArrayList<Enemy> enemies, int reach)`."},{"pattern":"\\binstanceof\\s+Flying\\b","message":"Ask whether an enemy flies with `instanceof Flying`."}],"forbid":[{"pattern":"\\binstanceof\\s+Bat\\b","message":"Ask whether the enemy flies (`instanceof Flying`), not whether it's a Bat: other flying enemies may join the game later."}],"more":[{"task":"Casts between a class, an interface and Object. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Enemy a = new Bat(\"Squeak\", 3);\n        Flying b = (Flying) a;\n        Enemy c = (Enemy) b;\n        System.out.println(b.altitude() + \" \" + c.getName());\n        System.out.println((a == c) + \" \" + (c instanceof Bat));\n\n        Enemy grak = new Troll(\"Grak\", 30);\n        Object thing = grak;\n        Troll troll = (Troll) thing;\n        troll.regenerate();\n        System.out.println(grak.getHealth() + \" \" + (thing instanceof Flying));\n    }\n}\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n}\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n// ==== Bat.java ====\npublic class Bat extends Enemy implements Flying {\n    private int altitude;\n\n    public Bat(String name, int altitude) {\n        super(name, 8);\n        this.altitude = altitude;\n    }\n\n    @Override\n    public int altitude() {\n        return this.altitude;\n    }\n}\n// ==== Flying.java ====\npublic interface Flying {\n    int altitude();\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Enemy a = new Bat(\"Squeak\", 3);\n        Flying b = (Flying) a;\n        Enemy c = (Enemy) b;\n        System.out.println(b.altitude() + \" \" + c.getName());\n        System.out.println((a == c) + \" \" + (c instanceof Bat));\n\n        Enemy grak = new Troll(\"Grak\", 30);\n        Object thing = grak;\n        Troll troll = (Troll) thing;\n        troll.regenerate();\n        System.out.println(grak.getHealth() + \" \" + (thing instanceof Flying));\n    }\n}\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n}\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n// ==== Bat.java ====\npublic class Bat extends Enemy implements Flying {\n    private int altitude;\n\n    public Bat(String name, int altitude) {\n        super(name, 8);\n        this.altitude = altitude;\n    }\n\n    @Override\n    public int altitude() {\n        return this.altitude;\n    }\n}\n// ==== Flying.java ====\npublic interface Flying {\n    int altitude();\n}\n","hints":["No cast makes a new object. `a`, `b` and `c` all refer to the one bat, each with a different type, and the bat is still a Bat whichever variable you ask through.","`thing` and `troll` refer to the same troll as `grak`, so regenerating through `troll` heals the object that `grak` refers to. A troll doesn't fly."],"tests":[{"name":"Output","stdin":"","expect":"3 Squeak\ntrue true\n35 false","hidden":false}],"require":[],"forbid":[],"lines":["3 Squeak","true true","35 false"]},{"task":"At the end of each round, every troll regenerates. But `endRound` in `Main.java` crashes with a ClassCastException as soon as the list holds anything other than a troll. Fix it, so that the trolls regenerate and the other enemies are left as they are. `Main` is a test drive, and it prints:\n\n```\n[Grak (35), Snip (20), Mossback (55)]\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Enemy> enemies = new ArrayList<>();\n        enemies.add(new Troll(\"Grak\", 30));\n        enemies.add(new Goblin(\"Snip\", 20));\n        enemies.add(new Troll(\"Mossback\", 50));\n        endRound(enemies);\n        System.out.println(enemies);\n    }\n\n    public static void endRound(ArrayList<Enemy> enemies) {\n        for (Enemy enemy : enemies) {\n            Troll troll = (Troll) enemy;\n            troll.regenerate();\n        }\n    }\n}\n\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n\n    @Override\n    public String toString() {\n        return this.name + \" (\" + this.health + \")\";\n    }\n}\n\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n\n// ==== Goblin.java ====\npublic class Goblin extends Enemy {\n    public Goblin(String name, int health) {\n        super(name, health);\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Enemy> enemies = new ArrayList<>();\n        enemies.add(new Troll(\"Grak\", 30));\n        enemies.add(new Goblin(\"Snip\", 20));\n        enemies.add(new Troll(\"Mossback\", 50));\n        endRound(enemies);\n        System.out.println(enemies);\n    }\n\n    public static void endRound(ArrayList<Enemy> enemies) {\n        for (Enemy enemy : enemies) {\n            if (enemy instanceof Troll) {\n                Troll troll = (Troll) enemy;\n                troll.regenerate();\n            }\n        }\n    }\n}\n\n// ==== Enemy.java ====\npublic abstract class Enemy {\n    private String name;\n    private int health;\n\n    public Enemy(String name, int health) {\n        this.name = name;\n        this.health = health;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getHealth() {\n        return this.health;\n    }\n\n    public void heal(int amount) {\n        this.health += amount;\n    }\n\n    @Override\n    public String toString() {\n        return this.name + \" (\" + this.health + \")\";\n    }\n}\n\n// ==== Troll.java ====\npublic class Troll extends Enemy {\n    public Troll(String name, int health) {\n        super(name, health);\n    }\n\n    public void regenerate() {\n        this.heal(5);\n    }\n}\n\n// ==== Goblin.java ====\npublic class Goblin extends Enemy {\n    public Goblin(String name, int health) {\n        super(name, health);\n    }\n}\n","hints":["The cast crashes on Snip: a goblin is not a troll, and a cast can't make it one. Only cast an enemy that `instanceof` says is a Troll.","Put the two lines inside `if (enemy instanceof Troll) { ... }`. The other enemies then skip the cast, and are left as they are."],"tests":[{"name":"The test drive","stdin":"","expect":"[Grak (35), Snip (20), Mossback (55)]","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Enemy> enemies = new ArrayList<>();\nenemies.add(new Goblin(\"Nab\", 15));\nenemies.add(new Goblin(\"Snip\", 20));\nendRound(enemies);\nSystem.out.println(enemies);\nenemies.add(new Troll(\"Grak\", 0));\nendRound(enemies);\nendRound(enemies);\nSystem.out.println(enemies);\n","expect":"[Nab (15), Snip (20)]\n[Nab (15), Snip (20), Grak (10)]","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Enemy> enemies = new ArrayList<>();\nendRound(enemies);\nSystem.out.println(enemies.size());\nTroll troll = new Troll(\"Mossback\", 50);\nenemies.add(troll);\nenemies.add(new Goblin(\"Snip\", 20));\nenemies.add(troll);\nendRound(enemies);\nSystem.out.println(troll.getHealth() + \" \" + enemies.get(1));\n","expect":"0\n60 Snip (20)","hidden":true}],"require":[{"pattern":"\\binstanceof\\s+Troll\\b","message":"Check with `instanceof Troll` before the cast."}],"forbid":[]}]}