Inheritance
Definitions
A class that is derived from another class is called a subclass (also a derived class, extended class, or child class). The class from which the subclass is derived is called a superclass (also a base class or a parent class).
- SuperclassBase classParent class
- SubclassDerived classChild class
Excepting Object
, which has no superclass, every class has one and only one direct superclass (single inheritance).
A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.
Subclass
What You Can Do in a Subclass?
A subclass inherits all of the public and protected members of its parent, no matter what package the subclass is in. If the subclass is in the same package as its parent, it also inherits the package-private members of the parent. You can use the inherited members as is, replace them, hide them, or supplement them with new members:
- You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it (not recommended).
- You can declare new fields in the subclass that are not in the superclass.
- The inherited methods can be used directly as they are.
- You can write a new instance method in the subclass that has the same signature as the one in the superclass, thus overriding it.
- You can write a new static method in the subclass that has the same signature as the one in the superclass, thus hiding it.
- You can declare new methods in the subclass that are not in the superclass.
- You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword
super
.
A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass.
Polymorphism
Method Override
Source Code
Output
Run the following commands.
The complete output ofjavap -verbose Test
is in the last section. Here we only focus on two parts.
Constant Pool
Bytecode
Bytecode Tear Down
Bytecode contains two parts: the constructor and the method.
The Constructor
The Method
caution
Why Parent
print method is called instead of Child
's?
Because that is all the compiler knows.
- The compiler knows
o
isParent
type, so it callsParent
's method.
Constant Pool Tear Down
Let's read a few lines of Constant Pool.
Because the first line of the code is Parent o = new Child();
, it will call super();
then it initialized itself.
More information are available at:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
Polymorphism
From Bytecode, we see that
is going to be called, which is Parent.print
.
But polymorphism gives us a different result. Why?
VTable
If take C++
approach as JVM's implementation, we can safely assume for each object, there is a VTable corresponding to it.
When we declare Parent o
, a VTable is created
Name | Reference |
---|---|
Object.toString() | Object.toString() |
Object.something else | Object.something else |
Parent.print() | Parent.print() |
✍ When o
was initialized to Child
, Parent.print()
would be updated to Child.print()
, resulting the following VTable :
Name | Reference |
---|---|
Object.toString() | Object.toString() |
Object.something else | Object.something else |
Parent.print() | Child.print() |
JVM will look up this VTable at running time to find #4 Test$Parent.print
and would find that it's actually pointing to Child.print()
. That's why it's called running time binding or dynamic binding, or late binding.
Complete Output
info
You may notice that there isn't that much information about the inner classes Parent
and Child
. This is because they are compiled to the other two files:Test$Parent.class
and Test$Child.class
.