{"id":"interfaces-variable-type","slug":"variable-type","title":"An interface as a variable's type","text":"An interface is a type, just like a class. It can be the type of a variable, and such a variable can refer to an object of any class that implements the interface:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Switchable device = new Heater(\"hall\", 21);\n        device.turnOn();\n        System.out.println(device);\n\n        device = new GardenLight(\"patio\");\n        System.out.println(device.isOn());\n        device.turnOn();\n        System.out.println(device);\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n// ==== Heater.java ====\npublic class Heater implements Switchable {\n    private String room;\n    private int degrees;\n    private boolean on;\n\n    public Heater(String room, int degrees) {\n        this.room = room;\n        this.degrees = degrees;\n        this.on = false;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    public int getDegrees() {\n        return this.degrees;\n    }\n\n    @Override\n    public String toString() {\n        if (this.on) {\n            return \"Heater in the \" + this.room + \": on, \" + this.degrees + \" degrees\";\n        }\n        return \"Heater in the \" + this.room + \": off\";\n    }\n}\n// ==== GardenLight.java ====\npublic class GardenLight implements Switchable {\n    private String place;\n    private boolean on;\n    private int switchOns;\n\n    public GardenLight(String place) {\n        this.place = place;\n        this.on = false;\n        this.switchOns = 0;\n    }\n\n    @Override\n    public void turnOn() {\n        if (!this.on) {\n            this.on = true;\n            this.switchOns++;\n        }\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public String toString() {\n        return \"Garden light (\" + this.place + \"): \" + this.switchOns + \" switch-ons\";\n    }\n}\n```\n\n```output\nHeater in the hall: on, 21 degrees\nfalse\nGarden light (patio): 1 switch-ons\n```\n\n- `Switchable device = new Heater(\"hall\", 21);` compiles because Heater implements Switchable: a Heater is a Switchable. It's the same idea as module 34's `Adventurer hero = new Knight(\"Oren\");`, with an interface in place of the superclass.\n- Calls on `device` run the object's own methods: Heater's while `device` refers to the heater, and GardenLight's after the assignment.\n- `println(device)` calls the object's own `toString`. Every object has Object's methods, so a variable of an interface type can use them too, even though Switchable doesn't list them.\n\n### The variable's type decides what you may call\n\nWhile `device` refers to the heater, the heater has a `getDegrees()`. Still, this doesn't compile:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Switchable device = new Heater(\"hall\", 21);\n        System.out.println(device.getDegrees());\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n// ==== Heater.java ====\npublic class Heater implements Switchable {\n    private String room;\n    private int degrees;\n    private boolean on;\n\n    public Heater(String room, int degrees) {\n        this.room = room;\n        this.degrees = degrees;\n        this.on = false;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    public int getDegrees() {\n        return this.degrees;\n    }\n}\n```\n\n```javac\nMain.java:4: error: cannot find symbol\n        System.out.println(device.getDegrees());\n                                 ^\n  symbol:   method getDegrees()\n  location: variable device of type Switchable\n1 error\n```\n\njavac knows only that `device` holds some Switchable, and a garden light or a sprinkler has no degrees. These are module 34's two rules again:\n\n- The **variable's type** decides which methods you may call. Through a Switchable variable, that's Switchable's three methods (and Object's).\n- The **object's class** decides which version of a method runs.\n\nSo pick the type that fits what the code needs. Code that only switches devices on and off can use Switchable, and then it works with every device. Code that sets the heater's temperature needs a Heater variable.\n\n### No objects of an interface\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Switchable device = new Switchable();\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n```\n\n```javac\nMain.java:3: error: Switchable is abstract; cannot be instantiated\n        Switchable device = new Switchable();\n                            ^\n1 error\n```\n\nAn interface has no code to run, so there are no Switchable objects as such. Every object comes from a class, and a Switchable variable refers to an object of some class that implements Switchable, or to nothing (`null`).\n\nAn object whose class implements several interfaces fits in a variable of each of them: step 2's robot vacuum can be a Switchable and a Chargeable. Module 36 looks more closely at one object seen through each of its types.\n","task":"Step 2's laptop and headphones again: the laptop gains 1 percent a minute, the headphones 5, and neither goes above 100. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Chargeable gadget = new Laptop(20);\n        gadget.charge(30);\n        System.out.println(gadget.batteryPercent());\n\n        Headphones headphones = new Headphones(10);\n        gadget = headphones;\n        gadget.charge(4);\n        System.out.println(gadget.batteryPercent() + \" \" + headphones.batteryPercent());\n    }\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== Laptop.java ====\npublic class Laptop implements Chargeable {\n    private int battery;\n\n    public Laptop(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n// ==== Headphones.java ====\npublic class Headphones implements Chargeable {\n    private int battery;\n\n    public Headphones(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 5 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Chargeable gadget = new Laptop(20);\n        gadget.charge(30);\n        System.out.println(gadget.batteryPercent());\n\n        Headphones headphones = new Headphones(10);\n        gadget = headphones;\n        gadget.charge(4);\n        System.out.println(gadget.batteryPercent() + \" \" + headphones.batteryPercent());\n    }\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== Laptop.java ====\npublic class Laptop implements Chargeable {\n    private int battery;\n\n    public Laptop(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n// ==== Headphones.java ====\npublic class Headphones implements Chargeable {\n    private int battery;\n\n    public Headphones(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 5 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n","hints":["`gadget` first refers to a Laptop, so the Laptop's `charge` runs. Later, `gadget = headphones;` doesn't copy anything.","The Laptop gains 1 percent a minute: 20 plus 30 is 50. After `gadget = headphones;`, both variables refer to the same Headphones object, and the Headphones' `charge` runs. 10 plus 5 times 4 is 30, whichever variable you ask."],"tests":[{"name":"Output","stdin":"","expect":"50\n30 30","hidden":false}],"require":[],"forbid":[],"lines":["50","30 30"],"more":[{"task":"Fill in the blank, a type, so that the program compiles. The one variable refers to a laptop first and to headphones later.\n","kind":"fill","seed":"public class Main {\n    public static void main(String[] args) {\n        [[Chargeable]] gadget = new Laptop(30);\n        gadget.charge(20);\n        System.out.println(gadget.batteryPercent());\n        gadget = new Headphones(30);\n        gadget.charge(4);\n        System.out.println(gadget.batteryPercent());\n    }\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== Laptop.java ====\npublic class Laptop implements Chargeable {\n    private int battery;\n\n    public Laptop(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n// ==== Headphones.java ====\npublic class Headphones implements Chargeable {\n    private int battery;\n\n    public Headphones(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 5 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Chargeable gadget = new Laptop(30);\n        gadget.charge(20);\n        System.out.println(gadget.batteryPercent());\n        gadget = new Headphones(30);\n        gadget.charge(4);\n        System.out.println(gadget.batteryPercent());\n    }\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== Laptop.java ====\npublic class Laptop implements Chargeable {\n    private int battery;\n\n    public Laptop(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n// ==== Headphones.java ====\npublic class Headphones implements Chargeable {\n    private int battery;\n\n    public Headphones(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 5 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n","hints":["A `Laptop` variable can't refer to headphones, and a `Headphones` variable can't refer to a laptop. What type do both classes share?","Both classes implement `Chargeable`, and the program calls only Chargeable's methods on `gadget`."],"tests":[{"name":"Output","stdin":"","expect":"50\n50","hidden":false}],"require":[],"forbid":[]},{"task":"The app has one button that controls one device, chosen when the app starts. The program reads one word, `fan` or `heater`. Declare one variable of type `Switchable`. If the word is `fan`, give it `new CeilingFan()`; otherwise give it `new Heater(\"bedroom\", 19)`. Then, after the `if`, turn the device on and print it, each just once, whichever device it is. The classes are ready. With the input `fan`, the program prints:\n\n```\nCeiling fan: speed 1\n```\n","kind":"code","seed":"// ==== 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        String word = scanner.nextLine();\n\n    }\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== CeilingFan.java ====\npublic class CeilingFan implements Switchable {\n    private int speed;\n\n    @Override\n    public void turnOn() {\n        if (this.speed == 0) {\n            this.speed = 1;\n        }\n    }\n\n    @Override\n    public void turnOff() {\n        this.speed = 0;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.speed > 0;\n    }\n\n    @Override\n    public String toString() {\n        return \"Ceiling fan: speed \" + this.speed;\n    }\n}\n\n// ==== Heater.java ====\npublic class Heater implements Switchable {\n    private String room;\n    private int degrees;\n    private boolean on;\n\n    public Heater(String room, int degrees) {\n        this.room = room;\n        this.degrees = degrees;\n        this.on = false;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public String toString() {\n        if (this.on) {\n            return \"Heater in the \" + this.room + \": on, \" + this.degrees + \" degrees\";\n        }\n        return \"Heater in the \" + this.room + \": off\";\n    }\n}\n","solution":"// ==== 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        String word = scanner.nextLine();\n        Switchable device = new Heater(\"bedroom\", 19);\n        if (word.equals(\"fan\")) {\n            device = new CeilingFan();\n        }\n        device.turnOn();\n        System.out.println(device);\n    }\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== CeilingFan.java ====\npublic class CeilingFan implements Switchable {\n    private int speed;\n\n    @Override\n    public void turnOn() {\n        if (this.speed == 0) {\n            this.speed = 1;\n        }\n    }\n\n    @Override\n    public void turnOff() {\n        this.speed = 0;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.speed > 0;\n    }\n\n    @Override\n    public String toString() {\n        return \"Ceiling fan: speed \" + this.speed;\n    }\n}\n\n// ==== Heater.java ====\npublic class Heater implements Switchable {\n    private String room;\n    private int degrees;\n    private boolean on;\n\n    public Heater(String room, int degrees) {\n        this.room = room;\n        this.degrees = degrees;\n        this.on = false;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public String toString() {\n        if (this.on) {\n            return \"Heater in the \" + this.room + \": on, \" + this.degrees + \" degrees\";\n        }\n        return \"Heater in the \" + this.room + \": off\";\n    }\n}\n","hints":["`Switchable device = new Heater(\"bedroom\", 19);` works as a start. Then an `if` gives `device` a new CeilingFan when the word is `fan`. Compare Strings with `equals`.","After the `if`, `device.turnOn();` and `System.out.println(device);` work for either device: each object runs its own `turnOn` and its own `toString`."],"tests":[{"name":"Test 1","stdin":"fan\n","expect":"Ceiling fan: speed 1","hidden":false},{"name":"Test 2","stdin":"heater\n","expect":"Heater in the bedroom: on, 19 degrees","hidden":true}],"require":[{"pattern":"\\bSwitchable\\s+\\w+\\s*[=;]","message":"Declare one variable of type `Switchable`, such as `Switchable device`."},{"pattern":"\\.turnOn\\s*\\(","max":1,"message":"Call `turnOn()` just once, after the `if`, on the Switchable variable."},{"pattern":"System\\.out\\.println\\s*\\(","max":1,"message":"Print just once, after the `if`: `System.out.println(device);` prints either device."}],"forbid":[]}]}