The Subtype–Supertype Relationship
A class defines a reference type, a data type whose objects can be accessed only by references. Therefore, the inheritance hierarchy can be regarded as a type hierarchy, embodying the subtype–supertype relationship between reference types. The subclass– superclass relationship is a special case of the subtype–supertype relationship that is between classes. The subclass–superclass relationship allows single inheritance of type, meaning that the subclass inherits the type of its direct superclass. This is in contrast to a class that implements several interfaces, resulting in multiple inheritance of type—that is, a class inherits the type of all interfaces it implements.
In the context of Java, the subtype–supertype relationship implies that the reference value of a subtype object can be assigned to a supertype reference because a subtype object can be substituted for a supertype object. This assignment involves a widening reference conversion, as references are assigned up the inheritance hierarchy. Using the reference types in Example 5.1, the following code assigns the reference value of an object of the subtype TubeLight to the reference light of the supertype Light:
Light light = new TubeLight(36, false, “Basement”,
1200, 26); // (1) widening reference conversion
An implicit widening conversion takes place under assignment, as the reference value of a narrower type (subtype TubeLight) object is being assigned to a reference of a broader type (supertype Light). We can now use the reference light to invoke those methods on the subtype object that are inherited from the supertype Light:
light.switchOn(); // (2)
Note that the compiler only knows about the static type (also called the declared type) of the reference light, which is Light, and ensures that only methods from this type can be called using the reference light. However, at runtime, the reference light will refer to an object of the subtype TubeLight when the call to the method switchOn() is executed. It is the type of the object that the reference refers to at runtime that determines which method is executed. The subtype object inherits the switchOn() method from its supertype Light, so this method is executed. The type of the object that the reference refers to at runtime is called the dynamic type (a.k.a. the runtime type or the object type) of the reference.
One might be tempted to invoke methods exclusive to the TubeLight subtype via the supertype reference light:
light.getTubeLength(); // (3) Compile-time error!
This code will not work, as the compiler does not know which object the reference light will denote at runtime; it only knows the declared type of the reference. As the declaration of the class Light does not have a method called getTubeLength(), this method call at (3) results in a compile-time error. Eliciting subtype-specific behavior using a supertype reference requires a narrowing reference conversion with an explicit cast (p. 278).