{"id":"interfaces-promise","slug":"promise","title":"An interface: a promise of methods","text":"Module 34's abstract classes listed methods that every subclass must write, such as the instruments' `sound()`. An **interface** is that idea on its own: a list of methods, with no code, that a class can promise to have. A class doesn't extend an interface. It **implements** it.\n\n### Switchable\n\nA smart home app controls all kinds of devices: heaters, fans, garden lights, sprinklers. For the app's on and off buttons, what a device does doesn't matter. What matters is that it can be turned on and off, and that it can say whether it's on. Here's that as an interface:\n\n```java\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n```\n\n- It's written like a class, with the word `interface` in place of `class`, and it goes in a file of its own, `Switchable.java`.\n- Each method is a header followed by a semicolon, with no body, just like an abstract method. The interface says *what* a Switchable can do, and leaves *how* to each class.\n- A method an interface lists (a header with no body) is always public, so there's no need to write `public` in front of it.\n- An interface has no instance variables and no constructor. It isn't a recipe for objects, only a list of promises.\n\n### implements\n\nHere's a heater that keeps the promise:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Heater heater = new Heater(\"hall\", 21);\n        System.out.println(heater);\n        heater.turnOn();\n        System.out.println(heater.isOn());\n        System.out.println(heater);\n        heater.turnOff();\n        System.out.println(heater.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    @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```\n\n```output\nHeater in the hall: off\ntrue\nHeater in the hall: on, 21 degrees\n21\n```\n\n- `public class Heater implements Switchable` promises that Heater has every method that Switchable lists.\n- Heater writes each of them with the same header, and with `public` in front.\n- `@Override` works here too. Above a method that implements an interface's method, it checks that the interface really has a method with that header, so a misspelled `turnon` is caught. This course writes it above every such method, as it does above `toString`.\n- A class may have more than the interface asks for: Heater has instance variables, a constructor, `getDegrees` and a `toString`. The interface only sets the minimum.\n\n### javac holds the class to its promise\n\nA garden light that forgot `isOn` doesn't compile:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        GardenLight light = new GardenLight();\n        light.turnOn();\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n// ==== GardenLight.java ====\npublic class GardenLight implements Switchable {\n    private boolean on;\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```\n\n```javac\nGardenLight.java:1: error: GardenLight is not abstract and does not override abstract method isOn() in Switchable\npublic class GardenLight implements Switchable {\n       ^\n1 error\n```\n\nIt's the same message as for module 34's harp without a `sound()`. To javac, the methods an interface lists are abstract methods, and a class that implements the interface must write every one of them.\n\nThey must also be `public`. Without a word in front, a method can be used only by the classes of its own package (module 34), which is less than the interface promised:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        GardenLight light = new GardenLight();\n        light.turnOn();\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n// ==== GardenLight.java ====\npublic class GardenLight implements Switchable {\n    private boolean on;\n\n    @Override\n    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```\n\n```javac\nGardenLight.java:5: error: turnOn() in GardenLight cannot implement turnOn() in Switchable\n    void turnOn() {\n         ^\n  attempting to assign weaker access privileges; was public\n1 error\n```\n\nIt's the rule module 34 gave for a `toString` that isn't public: a method can't be less visible than the method it overrides or implements. Switchable's `turnOn` is public, so GardenLight's must be public too.\n","task":"The garden sprinkler joins the app. `Switchable.java` is ready. In `Sprinkler.java`, write the class `Sprinkler`, which implements Switchable, with:\n\n- a constructor `Sprinkler(String zone)`; a new sprinkler is off\n- `turnOn()`, `turnOff()` and `isOn()`, each with `@Override` above it\n- `toString()`, which returns `Sprinkler (front lawn): on` or `Sprinkler (front lawn): off`, with the sprinkler's own zone\n\nThe check runs:\n\n```java\nSprinkler sprinkler = new Sprinkler(\"front lawn\");\nSystem.out.println(sprinkler);\nsprinkler.turnOn();\nSystem.out.println(sprinkler.isOn());\nSystem.out.println(sprinkler);\n```\n\nand expects:\n\n```\nSprinkler (front lawn): off\ntrue\nSprinkler (front lawn): on\n```\n","kind":"code","seed":"// ==== Sprinkler.java ====\npublic class Sprinkler {\n\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Sprinkler sprinkler = new Sprinkler(\"front lawn\");\n        System.out.println(sprinkler);\n        sprinkler.turnOn();\n        System.out.println(sprinkler.isOn());\n        System.out.println(sprinkler);\n    }\n}\n","solution":"// ==== Sprinkler.java ====\npublic class Sprinkler implements Switchable {\n    private String zone;\n    private boolean on;\n\n    public Sprinkler(String zone) {\n        this.zone = zone;\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 \"Sprinkler (\" + this.zone + \"): on\";\n        }\n        return \"Sprinkler (\" + this.zone + \"): off\";\n    }\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Sprinkler sprinkler = new Sprinkler(\"front lawn\");\n        System.out.println(sprinkler);\n        sprinkler.turnOn();\n        System.out.println(sprinkler.isOn());\n        System.out.println(sprinkler);\n    }\n}\n","hints":["Start with `public class Sprinkler implements Switchable {`, and give the class two instance variables: the zone, and a boolean that says whether the sprinkler is on.","Each of the three methods is `public`, with `@Override` above it: `turnOn` sets the boolean to `true`, `turnOff` sets it to `false`, and `isOn` returns it. `toString` returns one text or the other, depending on the boolean."],"tests":[{"name":"Test 1","stdin":"","call":"Sprinkler sprinkler = new Sprinkler(\"front lawn\");\nSystem.out.println(sprinkler);\nsprinkler.turnOn();\nSystem.out.println(sprinkler.isOn());\nSystem.out.println(sprinkler);\n","expect":"Sprinkler (front lawn): off\ntrue\nSprinkler (front lawn): on","hidden":false},{"name":"Test 2","stdin":"","call":"Sprinkler back = new Sprinkler(\"back yard\");\nSprinkler roses = new Sprinkler(\"roses\");\nback.turnOn();\nback.turnOn();\nSystem.out.println(back.isOn() + \" \" + roses.isOn());\nback.turnOff();\nroses.turnOn();\nSystem.out.println(back + \" / \" + roses);\n","expect":"true false\nSprinkler (back yard): off / Sprinkler (roses): on","hidden":true},{"name":"Test 3","stdin":"","call":"Switchable device = new Sprinkler(\"hedge\");\nSystem.out.println(device.isOn());\ndevice.turnOn();\ndevice.turnOff();\nSystem.out.println(device.isOn() + \" \" + device);\n","expect":"false\nfalse Sprinkler (hedge): off","hidden":true}],"require":[{"pattern":"\\bclass\\s+Sprinkler\\s+implements\\s+Switchable\\b","message":"Write the header as `public class Sprinkler implements Switchable`, so that a sprinkler keeps Switchable's promise."},{"pattern":"@Override","min":3,"message":"Put `@Override` above each of the methods that Switchable asks for, so that javac checks their headers."}],"forbid":[],"more":[{"task":"A ceiling fan has three speeds, and speed 0 means that it's off. The fan keeps no boolean: `isOn` works the answer out from the speed. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        CeilingFan fan = new CeilingFan();\n        fan.faster();\n        System.out.println(fan.isOn() + \" \" + fan.getSpeed());\n        fan.turnOn();\n        fan.faster();\n        fan.faster();\n        fan.faster();\n        fan.turnOn();\n        System.out.println(fan.isOn() + \" \" + fan.getSpeed());\n        fan.turnOff();\n        System.out.println(fan.isOn() + \" \" + fan.getSpeed());\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\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    public void faster() {\n        if (this.speed > 0 && this.speed < 3) {\n            this.speed++;\n        }\n    }\n\n    public int getSpeed() {\n        return this.speed;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        CeilingFan fan = new CeilingFan();\n        fan.faster();\n        System.out.println(fan.isOn() + \" \" + fan.getSpeed());\n        fan.turnOn();\n        fan.faster();\n        fan.faster();\n        fan.faster();\n        fan.turnOn();\n        System.out.println(fan.isOn() + \" \" + fan.getSpeed());\n        fan.turnOff();\n        System.out.println(fan.isOn() + \" \" + fan.getSpeed());\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\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    public void faster() {\n        if (this.speed > 0 && this.speed < 3) {\n            this.speed++;\n        }\n    }\n\n    public int getSpeed() {\n        return this.speed;\n    }\n}\n","hints":["A new fan's speed is 0, and `faster` changes nothing while the fan is off. `turnOn` starts the fan at speed 1, but only if it's off.","After `turnOn`, three calls to `faster` stop at speed 3. The second `turnOn` finds the fan already running, so it keeps speed 3. `turnOff` sets the speed back to 0, and `isOn` is worked out from the speed."],"tests":[{"name":"Output","stdin":"","expect":"false 0\ntrue 3\nfalse 0","hidden":false}],"require":[],"forbid":[],"lines":["false 0","true 3","false 0"]},{"task":"The garage door opener implements Switchable too, but `GarageDoor.java` doesn't compile. Read javac's messages and fix the class: `turnOn` opens the door, `turnOff` closes it, and `isOn` should say whether the door is open. Keep `isOpen` as it is, since other code uses it. Put `@Override` above each of the three methods that Switchable asks for. The program should print:\n\n```\ntrue true\nfalse false\n```\n","kind":"code","seed":"// ==== GarageDoor.java ====\npublic class GarageDoor implements Switchable {\n    private boolean open;\n\n    void turnOn() {\n        this.open = true;\n    }\n\n    public void turnOff() {\n        this.open = false;\n    }\n\n    public boolean isOpen() {\n        return this.open;\n    }\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        GarageDoor door = new GarageDoor();\n        door.turnOn();\n        System.out.println(door.isOn() + \" \" + door.isOpen());\n        door.turnOff();\n        System.out.println(door.isOn() + \" \" + door.isOpen());\n    }\n}\n","solution":"// ==== GarageDoor.java ====\npublic class GarageDoor implements Switchable {\n    private boolean open;\n\n    @Override\n    public void turnOn() {\n        this.open = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.open = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.open;\n    }\n\n    public boolean isOpen() {\n        return this.open;\n    }\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        GarageDoor door = new GarageDoor();\n        door.turnOn();\n        System.out.println(door.isOn() + \" \" + door.isOpen());\n        door.turnOff();\n        System.out.println(door.isOn() + \" \" + door.isOpen());\n    }\n}\n","hints":["javac finds two problems: `turnOn` isn't public, and the class has no `isOn()` at all. `isOpen` has another name, so it doesn't count as Switchable's `isOn`.","Write `public void turnOn()`, and add a method `public boolean isOn()` that returns `this.open`. Then put `@Override` above `turnOn`, `turnOff` and `isOn`, but not above `isOpen`, which Switchable doesn't have."],"tests":[{"name":"The program's output","stdin":"","expect":"true true\nfalse false","hidden":false},{"name":"Test 2","stdin":"","call":"GarageDoor door = new GarageDoor();\nSystem.out.println(door.isOn());\nSwitchable button = door;\nbutton.turnOn();\nSystem.out.println(door.isOpen() + \" \" + button.isOn());\n","expect":"false\ntrue true","hidden":true}],"require":[{"pattern":"@Override","min":3,"message":"Put `@Override` above `turnOn`, `turnOff` and `isOn`, the three methods that Switchable asks for."},{"pattern":"\\bpublic\\s+boolean\\s+isOn\\s*\\(\\s*\\)","message":"GarageDoor needs the method `public boolean isOn()`, which Switchable asks for."}],"forbid":[]}]}