Method Dispatch and Casting

exercises
tutorial
java
polymorphism
casting

Applied class exercises for week 4, covering java-polymorphism (dynamic method dispatch) and java-casting in more depth.

On the HTML site, fill in each blank with your answer (as a quoted string, e.g. "Car.topSpeed()"), then click Run Code to check it. In the PDF, the Working callout is shown as a static answer key instead (interactive checking needs a browser).

Question 1 — Apparent type vs actual type

Every object has an apparent type (compile-time type, from variable/method declarations) and an actual type (runtime type, fixed by whichever class’s new constructed it). The compiler always ensures the apparent type is the actual type or one of its superclasses, decides whether a call is legal using the apparent type, but dispatches the call to the method as implemented by the actual type.

class Animal { void eat() {...} }
class Lion extends Animal {}
class Dog extends Animal implements Pet {
    void eat() {...}
    void eat(int howMuch) {...}
}
class Poodle extends Dog {}
interface Pet {}

What happens when you call simba.eat(200), given Lion simba = new Lion();?

Lion’s apparent AND actual type is Lion, which has no eat(int) method (only the no-arg eat() inherited from Animal) — the compiler rejects the call outright, since legality is checked against the apparent type’s available methods.

Full worked example, one line at a time:

Statement Outcome
Dog evie = new Dog(); OK
Animal animal = evie; OK (upcast, implicit)
Lion mufasa = animal; Must be cast. Will fail (an Animal referencing a Dog is never a Lion).
Dog harlee = animal; Must be cast. Will succeed (the actual object really is a Dog).
Poodle bruiser = evie; Must be cast. Will fail (evie’s actual type is Dog, not Poodle).
Lion simba = new Lion(); OK
Lion scar = new Poodle(); Will not compile — Poodle and Lion share no inheritance relationship.
Pet charley = new Poodle(); OK (Poodle extends Dog, which implements Pet).
Dog lassie = charley; Must be cast. Will succeed.
Animal scooby = charley; Will not compile — Pet is not related to Animal (an interface doesn’t know about unrelated classes).
simba.eat(); OK
simba.eat(200); No method found — compile error.

Question 2 — A larger hierarchy

class Location {...}
interface RoadLegal { int topSpeed(); boolean licenceRequired(); }
interface PublicTransport { double calculateFare(Location start, Location end); }

class Vehicle {
    int travelTime(Location start, Location end) {...}
    int topSpeed() {...}
}
class HumanPowered extends Vehicle {
    int getWeight() {...}
    int topSpeed() {...}
}
class Motorised extends Vehicle implements RoadLegal {
    int travelTime(Location start, Location end) {...}
    int topSpeed() {...}
    boolean licenceRequired() {...}
}
class Skateboard extends HumanPowered {}
class Bicycle extends HumanPowered implements RoadLegal {
    boolean licenceRequired() {...}
}
class Motorbike extends Motorised {
    int topSpeed() {...}
    int travelTime(Location location) {...} // overloaded, single-Location version
}
class Car extends Motorised { int topSpeed() {...} }
class Taxi extends Car {}
class Bus extends Motorised implements PublicTransport {
    int topSpeed() {...}
    double calculateFare(Location start, Location end) {...}
}
classDiagram
    Vehicle <|-- HumanPowered
    Vehicle <|-- Motorised
    HumanPowered <|-- Skateboard
    HumanPowered <|-- Bicycle
    RoadLegal <|.. Bicycle
    Motorised <|-- Motorbike
    Motorised <|-- Car
    Motorised <|.. RoadLegal
    Car <|-- Taxi
    Motorised <|-- Bus
    Bus <|.. PublicTransport

For each, what method implementation is actually called?

Vehicle vehicle = new Taxi(); vehicle.topSpeed();

Vehicle vehicle = new Bicycle(); vehicle.topSpeed();

RoadLegal roadLegal = new Bicycle(); roadLegal.topSpeed();

Vehicle vehicle = new Motorbike(); vehicle.travelTime(location1, location2);

Even though roadLegal’s apparent type is the RoadLegal interface, dispatch always goes to the actual type’s implementation — Bicycle doesn’t override topSpeed() itself, so it’s inherited from HumanPowered. Similarly Motorbike doesn’t override the two-Location travelTime, only the single-Location overload, so the two-argument call dispatches to Motorised’s version.

Some other statements to check yourself against — whether each compiles, and why:

  • Vehicle bus = new Bus(); — compiles (upcast).
  • Motorised skateboard = new Skateboard(); — does not compile: no relationship between Motorised and Skateboard.
  • Motorbike vehicle = new Vehicle(); — does not compile: downcast needs an explicit cast.
  • Motorised motorbike = new Motorbike(); motorbike.travelTime(destination); — does not compile: neither Motorised nor its parents declare a single-argument travelTime(Location).
  • Car car = new Taxi(); Taxi taxi = car; — does not compile: downcast needs an explicit cast.
  • Vehicle bike = new Bicycle(); bike.getWeight(); — does not compile: Vehicle has no getWeight() method (it’s declared on HumanPowered).
  • Motorised bus = new Bus(); PublicTransport trip = bus; — does not compile: Motorised can’t be implicitly cast to the unrelated PublicTransport interface.

Question 3 — Casting rules

When changing a value’s apparent type:

  1. Casting to a superclass of the current apparent type can be implicit.
  2. Casting to a subclass should be checked via instanceof (a runtime check).
  3. If the two types share no inheritance relationship, Java refuses to compile at all.

For each instanceof pattern-match below (assuming each variable holds an instance of its own class, e.g. bus is a Bus), does it compile, and if so, could the match be guaranteed true at compile time ("implicit")?

Expression Compiles? Guaranteed true?
bus instanceof Vehicle vehicle Yes Yes — Vehicle is a superclass of Bus
car instanceof Taxi taxi Yes No — Taxi is a subclass of Car, needs a runtime check
motorised instanceof Bicycle bike No Motorised and Bicycle share no relationship (siblings under Vehicle)
motorbike instanceof RoadLegal legal Yes Yes — Motorbike extends Motorised, which implements RoadLegal
taxi instanceof Vehicle vehicle Yes Yes — Vehicle is a superclass all the way up the TaxiCarMotorisedVehicle chain

Where would an electric scooter fit into this hierarchy? (Discussion question — not every real-world model fits neatly into single inheritance.)