This is a good question, and it’s a common confusion when you’re learning about inheritance.
The way I think about it is there are two things to ask:
- What can the compiler know ahead of time, when you’re writing your code?
- What does the Java Runtime Environment know when you actually run your code?
Let’s say you have these classes:
public class MessagePrinter {
public void printMessage() {
System.out.println("Hello world!");
}
}
public class GoodbyePrinter extends MessagePrinter {
public void printMessage() {
System.out.println("Goodbye world!");
}
}
public class BetterMessagePrinter extends MessagePrinter {
private String name;
public void setName(String name) {
this.name = name;
}
public void printMessage() {
System.out.println("Hello " + name);
}
}
Now in your code, you can write a function like this:
public void doSomething(MessagePrinter mp) {
mp.printMessage();
}
Which you can call like this:
MessagePrinter one = new MessagePrinter();
doSomething(one);
GoodbyePrinter two = new GoodbyePrinter();
doSomething(two);
BetterMessagePrinter three = new BetterMessagePrinter();
three.setName("ascyrax");
doSomething(three);
All of this will work: because GoodbyePrinter
and BetterMessagePrinter
both extend MessagePrinter
, you can pass instances of them into the doSomething()
function.
However, back in your doSomething()
function, you can’t do this:
public void doSomething(MessagePrinter mp) {
mp.setName("ascyrax"); // Compiler error!
mp.printMessage();
}
This will give you a compiler error, because the compiler can’t guarantee that the mp
argument will have a setName()
function. After all, what if you pass in an instance of GoodbyePrinter
?
So all of that was to explain the first part: your compiler can’t know ahead of time what subtypes you’ll pass in, which is why you’re only allowed to reference methods from the parent class.
However, the Java Runtime Environment does know which subtype an instance is when the code is running. That’s why it’s able to call the overridden printMessage()
methods in the above example.