Polymorphism

Nathan Sprague

LoudToy

/**
 * Class representing a generic loud toy. 
 * Exists only to serve as a superclass.
 */
public class LoudToy {

    public void makeNoise() {
        // This should be overridden in subclasses.
        System.out.println("Generic noise.");
    }
}

ToyRobot

public class ToyRobot extends LoudToy {

    private int chargeLevel;
    
    public ToyRobot() {
        chargeLevel = 5;
    }

    @Override
    public void makeNoise() {
        System.out.println("Beep Beep!");
    }

    public void recharge() {
        chargeLevel = 10;
        System.out.println("Charged up!");
    }
}

ToySheep

Socrative Quiz…

What will be printed?

LoudToy toy;
toy = new ToySheep();
toy.makeNoise();
toy = new ToyRobot();
toy.makeNoise();
Generic noise.
Generic noise.
Baaa.
Beep Beep!
Generic noise.
Baaa.
Generic noise.
Beep Beep!
  1. Will not compile

Socrative Quiz…

Which code sample will result in the following terminal output?

Beep Beep!
Charged up!
LoudToy toy;
toy = new ToyRobot();
toy.makeNoise();
toy.recharge();
LoudToy toy;
ToyRobot bot;
toy = new ToyRobot();
toy.makeNoise();
bot = toy;
bot.recharge();
LoudToy toy;
ToyRobot bot;
toy = new ToyRobot();
toy.makeNoise();
bot = (ToyRobot)toy;
bot.recharge();
  1. None of the above.

  2. More than one of the above.

How about this…

LoudToy toy;
ToyRobot bot;
toy = new ToySheep();
bot = (ToyRobot)toy;
bot.makeNoise();

Will it compile?

Will it execute without an exception?

If so, what will be printed?

How about this…

LoudToy toy;
ToyRobot bot;
toy = new ToySheep();
bot = (ToyRobot)toy;
bot.makeNoise();

Will it compile?

YES! The Java compiler will take our word for it that the assignment on line 4 makes sense.

Will it execute without an exception?

NO! The assignment on line 4 will result in an exception. A ToySheep IS NOT a ToyRobot, so it can never be stored in a ToyRobot variable.

If so, what will be printed?

Adding Volume…

One option…

Protected Access…

Protected members are visible in all subclasses (and all other classes in the same package).

Overloaded Methods…

/**
 *  Utility methods to help us play with toys.
 */
public class PlayUtils {

    public static void playWithLoudToy(LoudToy toy) {
        System.out.println("This is a fun loud toy!");
        toy.makeNoise();
    }

    public static void playWithLoudToy(ToyRobot robot) {
        System.out.println("This is a fun robot!");
        robot.makeNoise();
    }
}
ToyRobot bot = new ToyRobot();
LoudToy toy = bot;
ToySheep sheep = new ToySheep();

PlayUtils.playWithLoudToy(bot);
PlayUtils.playWithLoudToy(toy);
PlayUtils.playWithLoudToy(sheep);

Result:

Which overloaded method will be called is determined at compile time based on the type of the variable that is passed as an argument. If there is no exact match, the closest ancestor will be selected:

ToyRobot bot = new ToyRobot();
LoudToy toy = bot;
ToySheep sheep = new ToySheep();

PlayUtils.playWithLoudToy(bot);  // Second method is called. (ToyRobot version)

PlayUtils.playWithLoudToy(toy);  // First method is called. (LoudToy version)
                                 // even though the toy variable
                                 // actually contains a ToyRobot.

PlayUtils.playWithLoudToy(sheep); // First method is called, even though
                                  // ToySheep is not the parameter type. 
                                  // a ToySheep is-a LoudToy, and there 
                                  // is no version that expects a ToySheep
                                  // explicitly.
This is a fun robot!
Beep Beep!
This is a fun loud toy!
Beep Beep!
This is a fun loud toy!
Baaa.