{"id":"polymorphism-many-types","slug":"many-types","title":"Hierarchies: one object, many types","text":"Modules 34 and 35 gave classes two ways to be related: a class extends one superclass, and it can implement any number of interfaces. Together, the classes and interfaces of a program form a **hierarchy**, a family tree of types. This module looks at what that means for one object, and for programs that handle many kinds of objects at once. The idea has a name, **polymorphism**, from the Greek for \"many forms\": one object can be used as several types, and one variable can refer to objects of many classes.\n\n### A toll booth's vehicles\n\nA toll booth charges every vehicle that goes through. A plain `Vehicle`, such as a motorbike, pays 3. A `Car` pays 6. A `Taxi` is a car, and pays 2 less than other cars. A `Truck` pays 5 for each axle. Taxis and trucks work for companies, which get a bill every month, so both implement an interface, `Commercial`, with one method: `company()`. Here's the hierarchy, with each class under the one it extends:\n\n```\nObject\n  Vehicle\n    Car\n      Taxi     implements Commercial\n    Truck      implements Commercial\n```\n\nVehicle doesn't say what it extends, so it extends Object (module 34). Here's the program, with one taxi in five variables:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Taxi taxi = new Taxi(\"TX-12\", \"Metro Cabs\");\n        Car car = taxi;\n        Vehicle vehicle = taxi;\n        Commercial customer = taxi;\n        Object thing = taxi;\n\n        System.out.println(taxi.toll() + \" \" + car.toll() + \" \" + vehicle.toll());\n        System.out.println(customer.company());\n        System.out.println(thing);\n        System.out.println(thing == customer);\n    }\n}\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n// ==== Car.java ====\npublic class Car extends Vehicle {\n    public Car(String plate) {\n        super(plate);\n    }\n\n    @Override\n    public int toll() {\n        return 6;\n    }\n}\n// ==== Taxi.java ====\npublic class Taxi extends Car implements Commercial {\n    private String company;\n\n    public Taxi(String plate, String company) {\n        super(plate);\n        this.company = company;\n    }\n\n    @Override\n    public int toll() {\n        return super.toll() - 2;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n```\n\n```output\n4 4 4\nMetro Cabs\nTX-12 pays 4\ntrue\n```\n\n- There's one `new`, so there's one object, a Taxi. Five variables refer to it, and each has a different type.\n- Each assignment compiles because a Taxi *is* each of those things: a Car, since Taxi extends Car; a Vehicle, since Car extends Vehicle; a Commercial, since Taxi implements it; and an Object, as every object is.\n- Putting the object in another variable doesn't change it or copy it. `thing == customer` is `true`: both refer to the same Taxi.\n- The toll is 4 through every variable. The object's class decides which version of a method runs (module 34), and this object is a Taxi, whatever the variable's type.\n\n### Every type an object has\n\nThe taxi has five types. In general, an object's types are:\n\n- its own class,\n- every class above it, all the way up to Object,\n- every interface that its class, or any class above it, implements,\n- and every interface above those, all the way up, since an interface can extend another one, as Set extends Collection (module 35).\n\nA variable of any of those types can refer to the object. The last two rules mean that interfaces are inherited, like methods: a class that extends Taxi is Commercial too, without writing `implements` again, and an ArrayList, which implements List, is a Collection too.\n\nWhat changes from variable to variable is what you may call through it, since the variable's type decides that (modules 34 and 35):\n\n| Through a variable of type | you may call |\n| --- | --- |\n| `Taxi` | `toll()`, `getPlate()` and `company()` |\n| `Car` or `Vehicle` | `toll()` and `getPlate()` |\n| `Commercial` | `company()` |\n| `Object` | only Object's methods, such as `toString()` and `equals(...)` |\n\nObject's methods can be called through all of them, since every object has those.\n\n### Up the tree, never across\n\nA variable can refer to objects of its own type and of every type below it in the tree. Other assignments don't compile:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Car car = new Truck(\"TR-88\", \"Nordic Freight\", 3);\n        Commercial customer = new Car(\"CR-55\");\n    }\n}\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n}\n// ==== Car.java ====\npublic class Car extends Vehicle {\n    public Car(String plate) {\n        super(plate);\n    }\n}\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n```\n\n```javac\nMain.java:3: error: incompatible types: Truck cannot be converted to Car\n        Car car = new Truck(\"TR-88\", \"Nordic Freight\", 3);\n                  ^\nMain.java:4: error: incompatible types: Car cannot be converted to Commercial\n        Commercial customer = new Car(\"CR-55\");\n                              ^\n2 errors\n```\n\n- A Truck is a Vehicle, and so is a Car. But a Truck isn't a Car: classes side by side in the tree share only what's above them.\n- A plain Car isn't Commercial, even though Taxi, a class below it, is. Types are passed down the tree, never up: a Car doesn't get what its subclasses add.\n\n### Java's own classes\n\nJava's own classes are built the same way. An ArrayList is a List and a Collection (module 35), and an Object:\n\n```java\nArrayList<String> plates = new ArrayList<>();\nplates.add(\"TX-12\");\nplates.add(\"TR-88\");\nList<String> list = plates;\nCollection<String> collection = plates;\nObject thing = plates;\n\nlist.add(\"CR-55\");\nSystem.out.println(collection.size());\nSystem.out.println(thing);\nSystem.out.println(thing == collection);\n```\n\n```output\n3\n[TX-12, TR-88, CR-55]\ntrue\n```\n\nFour variables, one list: `list.add` adds to the same list that `collection.size()` counts, and printing it through `thing` runs ArrayList's own `toString`. An ArrayList has a few more types, such as the abstract class AbstractList that module 35 mentioned. Java's documentation lists the superclasses and interfaces of each of its classes.\n","task":"At the end of the day, the booth adds up the tolls of every vehicle that went through, and lists the companies to bill. Fill in the type of each list. `passed` holds all three vehicles, and its loop calls `toll()` on each. `customers` holds the taxi and the truck, and its loop calls `company()`. Each list's type must be one that every object on it has, and that has the method its loop calls. The program prints:\n\n```\nTolls today: 25\nBill to Metro Cabs\nBill to Nordic Freight\n```\n","kind":"fill","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        Taxi taxi = new Taxi(\"TX-12\", \"Metro Cabs\");\n        Car car = new Car(\"CR-55\");\n        Truck truck = new Truck(\"TR-88\", \"Nordic Freight\", 3);\n\n        ArrayList<[[Vehicle]]> passed = new ArrayList<>();\n        passed.add(taxi);\n        passed.add(car);\n        passed.add(truck);\n        int total = 0;\n        for (int i = 0; i < passed.size(); i++) {\n            total += passed.get(i).toll();\n        }\n        System.out.println(\"Tolls today: \" + total);\n\n        ArrayList<[[Commercial]]> customers = new ArrayList<>();\n        customers.add(taxi);\n        customers.add(truck);\n        for (int i = 0; i < customers.size(); i++) {\n            System.out.println(\"Bill to \" + customers.get(i).company());\n        }\n    }\n}\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n// ==== Car.java ====\npublic class Car extends Vehicle {\n    public Car(String plate) {\n        super(plate);\n    }\n\n    @Override\n    public int toll() {\n        return 6;\n    }\n}\n// ==== Taxi.java ====\npublic class Taxi extends Car implements Commercial {\n    private String company;\n\n    public Taxi(String plate, String company) {\n        super(plate);\n        this.company = company;\n    }\n\n    @Override\n    public int toll() {\n        return super.toll() - 2;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        Taxi taxi = new Taxi(\"TX-12\", \"Metro Cabs\");\n        Car car = new Car(\"CR-55\");\n        Truck truck = new Truck(\"TR-88\", \"Nordic Freight\", 3);\n\n        ArrayList<Vehicle> passed = new ArrayList<>();\n        passed.add(taxi);\n        passed.add(car);\n        passed.add(truck);\n        int total = 0;\n        for (int i = 0; i < passed.size(); i++) {\n            total += passed.get(i).toll();\n        }\n        System.out.println(\"Tolls today: \" + total);\n\n        ArrayList<Commercial> customers = new ArrayList<>();\n        customers.add(taxi);\n        customers.add(truck);\n        for (int i = 0; i < customers.size(); i++) {\n            System.out.println(\"Bill to \" + customers.get(i).company());\n        }\n    }\n}\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n// ==== Car.java ====\npublic class Car extends Vehicle {\n    public Car(String plate) {\n        super(plate);\n    }\n\n    @Override\n    public int toll() {\n        return 6;\n    }\n}\n// ==== Taxi.java ====\npublic class Taxi extends Car implements Commercial {\n    private String company;\n\n    public Taxi(String plate, String company) {\n        super(plate);\n        this.company = company;\n    }\n\n    @Override\n    public int toll() {\n        return super.toll() - 2;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n","hints":["Go up the tree from each object on the list until you reach a type they all share. The taxi, the car and the truck meet at Vehicle, and Vehicle has `toll()`.","The taxi and the truck share Vehicle too, but Vehicle has no `company()`. The type they share that has it is the interface they both implement."],"tests":[{"name":"Output","stdin":"","expect":"Tolls today: 25\nBill to Metro Cabs\nBill to Nordic Freight","hidden":false}],"require":[],"forbid":[],"more":[{"task":"The booth's truck, seen through several variables. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Truck truck = new Truck(\"TR-88\", \"Nordic Freight\", 2);\n        Vehicle vehicle = truck;\n        Commercial customer = truck;\n        Object thing = customer;\n\n        System.out.println(vehicle.toll() + \" \" + customer.company());\n        System.out.println(thing);\n        System.out.println(thing.getClass().getName());\n        System.out.println(thing == vehicle);\n\n        Vehicle twin = new Truck(\"TR-88\", \"Nordic Freight\", 2);\n        System.out.println(twin == vehicle);\n    }\n}\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Truck truck = new Truck(\"TR-88\", \"Nordic Freight\", 2);\n        Vehicle vehicle = truck;\n        Commercial customer = truck;\n        Object thing = customer;\n\n        System.out.println(vehicle.toll() + \" \" + customer.company());\n        System.out.println(thing);\n        System.out.println(thing.getClass().getName());\n        System.out.println(thing == vehicle);\n\n        Vehicle twin = new Truck(\"TR-88\", \"Nordic Freight\", 2);\n        System.out.println(twin == vehicle);\n    }\n}\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n","hints":["`vehicle`, `customer` and `thing` all refer to the one Truck that the first `new` made. Printing `thing` runs the object's own `toString`, which is Vehicle's, and it calls the truck's `toll()`.","`getClass().getName()` names the object's class, not the variable's type. `twin` is a second object, made by another `new`, so `==` is `false`, even though its values are the same."],"tests":[{"name":"Output","stdin":"","expect":"10 Nordic Freight\nTR-88 pays 10\nTruck\ntrue\nfalse","hidden":false}],"require":[],"forbid":[],"lines":["10 Nordic Freight","TR-88 pays 10","Truck","true","false"]},{"task":"Some trucks carry fuel, and pay 10 more than other trucks with the same number of axles. In `TankerTruck.java`, write the class `TankerTruck`, which extends Truck, with:\n\n- a constructor `TankerTruck(String plate, String company, int axles)`\n- `toll()` overridden to return Truck's toll plus 10: get Truck's toll with `super.toll()`\n\nDon't write `implements Commercial` or `company()`: a TankerTruck gets both from Truck. The check runs:\n\n```java\nTankerTruck tanker = new TankerTruck(\"TK-4\", \"Coastal Fuels\", 3);\nVehicle vehicle = tanker;\nCommercial customer = tanker;\nTruck truck = tanker;\nSystem.out.println(vehicle);\nSystem.out.println(customer.company() + \" \" + truck.toll());\n```\n\nand expects:\n\n```\nTK-4 pays 25\nCoastal Fuels 25\n```\n","kind":"code","seed":"// ==== TankerTruck.java ====\npublic class TankerTruck {\n\n}\n\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        TankerTruck tanker = new TankerTruck(\"TK-4\", \"Coastal Fuels\", 3);\n        Vehicle vehicle = tanker;\n        Commercial customer = tanker;\n        Truck truck = tanker;\n        System.out.println(vehicle);\n        System.out.println(customer.company() + \" \" + truck.toll());\n    }\n}\n","solution":"// ==== TankerTruck.java ====\npublic class TankerTruck extends Truck {\n    public TankerTruck(String plate, String company, int axles) {\n        super(plate, company, axles);\n    }\n\n    @Override\n    public int toll() {\n        return super.toll() + 10;\n    }\n}\n\n// ==== Truck.java ====\npublic class Truck extends Vehicle implements Commercial {\n    private String company;\n    private int axles;\n\n    public Truck(String plate, String company, int axles) {\n        super(plate);\n        this.company = company;\n        this.axles = axles;\n    }\n\n    @Override\n    public int toll() {\n        return 5 * this.axles;\n    }\n\n    @Override\n    public String company() {\n        return this.company;\n    }\n}\n\n// ==== Vehicle.java ====\npublic class Vehicle {\n    private String plate;\n\n    public Vehicle(String plate) {\n        this.plate = plate;\n    }\n\n    public String getPlate() {\n        return this.plate;\n    }\n\n    public int toll() {\n        return 3;\n    }\n\n    @Override\n    public String toString() {\n        return this.plate + \" pays \" + this.toll();\n    }\n}\n\n// ==== Commercial.java ====\npublic interface Commercial {\n    String company();\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        TankerTruck tanker = new TankerTruck(\"TK-4\", \"Coastal Fuels\", 3);\n        Vehicle vehicle = tanker;\n        Commercial customer = tanker;\n        Truck truck = tanker;\n        System.out.println(vehicle);\n        System.out.println(customer.company() + \" \" + truck.toll());\n    }\n}\n","hints":["Start with `public class TankerTruck extends Truck {`. The constructor hands all three values to Truck's constructor with `super(plate, company, axles);`.","Override `toll()`, with `@Override` above it, and return `super.toll() + 10`. Everything else, `company()` and being Commercial included, comes from Truck."],"tests":[{"name":"Test 1","stdin":"","call":"TankerTruck tanker = new TankerTruck(\"TK-4\", \"Coastal Fuels\", 3);\nVehicle vehicle = tanker;\nCommercial customer = tanker;\nTruck truck = tanker;\nSystem.out.println(vehicle);\nSystem.out.println(customer.company() + \" \" + truck.toll());\n","expect":"TK-4 pays 25\nCoastal Fuels 25","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Vehicle> passed = new ArrayList<>();\npassed.add(new TankerTruck(\"TK-1\", \"Coastal Fuels\", 2));\npassed.add(new Truck(\"TR-2\", \"Nordic Freight\", 2));\npassed.add(new Vehicle(\"MC-3\"));\nint total = 0;\nfor (Vehicle vehicle : passed) {\n    total += vehicle.toll();\n}\nSystem.out.println(total + \" \" + passed.get(0));\n","expect":"33 TK-1 pays 20","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Commercial> customers = new ArrayList<>();\ncustomers.add(new TankerTruck(\"TK-9\", \"Blue Ridge Oil\", 5));\ncustomers.add(new Truck(\"TR-7\", \"Nordic Freight\", 1));\nfor (Commercial customer : customers) {\n    System.out.println(customer.company());\n}\nObject thing = customers.get(0);\nSystem.out.println(thing + \" \" + thing.getClass().getName());\n","expect":"Blue Ridge Oil\nNordic Freight\nTK-9 pays 35 TankerTruck","hidden":true}],"require":[{"pattern":"\\bclass\\s+TankerTruck\\s+extends\\s+Truck\\b","message":"Write the header as `public class TankerTruck extends Truck`."},{"pattern":"\\bsuper\\s*\\.\\s*toll\\s*\\(\\s*\\)","message":"Get Truck's toll with `super.toll()`, and add 10 to it."}],"forbid":[{"pattern":"\\bclass\\s+TankerTruck\\s+extends\\s+Truck\\s+implements\\b","message":"TankerTruck is already Commercial, because Truck is. Leave out `implements Commercial`."}]}]}