Initializing the base class
Since there are now two classes involvedthe base class and the derived classinstead of just one, it can be a bit confusing to try to imagine the resulting object produced by a derived class. From the outside, it looks like the new class has the same interface as the base class and maybe some additional methods and fields. But inheritance doesnt just copy the interface of the base class. When you create an object of the derived class, it contains within it a subobject of the base class. This subobject is the same as if you had created an object of the base class by itself. Its just that from the outside, the subobject of the base class is wrapped within the derived-class object.
Of course, its essential that the base-class subobject be initialized correctly, and theres only one way to guarantee this: perform the initialization in the constructor by calling the base-class constructor, which has all the appropriate knowledge and privileges to perform the base-class initialization. Java automatically inserts calls to the base-class constructor in the derived-class constructor. The following example shows this working with three levels of inheritance:
//: c06:Cartoon.java
// Constructor calls during inheritance.
import com.bruceeckel.simpletest.*;
class Art {
Art() {
System.out.println("Art constructor");
}
}
class Drawing extends Art {
Drawing() {
System.out.println("Drawing constructor");
}
}
public class Cartoon extends Drawing {
private static Test monitor = new Test();
public Cartoon() {
System.out.println("Cartoon constructor");
}
public static void main(String[] args) {
Cartoon x = new Cartoon();
monitor.expect(new String[] {
"Art constructor",
"Drawing constructor",
"Cartoon constructor"
});
}
} ///:~
You can see that the construction happens from the base outward, so the base class is initialized before the derived-class constructors can access it. Even if you dont create a constructor for Cartoon( ), the compiler will synthesize a default constructor for you that calls the base class constructor.
Constructors with
arguments
The preceding example has default constructors; that is, they dont have any arguments. Its easy for the compiler to call these because theres no question about what arguments to pass. If your class doesnt have default arguments, or if you want to call a base-class constructor that has an argument, you must explicitly write the calls to the base-class constructor using the super keyword and the appropriate argument list:
//: c06:Chess.java
// Inheritance, constructors and arguments.
import com.bruceeckel.simpletest.*;
class Game {
Game(int i) {
System.out.println("Game constructor");
}
}
class BoardGame extends Game {
BoardGame(int i) {
super(i);
System.out.println("BoardGame constructor");
}
}
public class Chess extends BoardGame {
private static Test monitor = new Test();
Chess() {
super(11);
System.out.println("Chess constructor");
}
public static void main(String[] args) {
Chess x = new Chess();
monitor.expect(new String[] {
"Game constructor",
"BoardGame constructor",
"Chess constructor"
});
}
} ///:~
If you dont call the base-class constructor in BoardGame( ), the compiler will complain that it cant find a constructor of the form Game( ). In addition, the call to the base-class constructor must be the first thing you do in the derived-class constructor. (The compiler will remind you if you get it wrong.)
Catching base constructor exceptions
As just noted, the compiler forces you to place the base-class constructor call first in the body of the derived-class constructor. This means nothing else can appear before it. As youll see in Chapter 9, this also prevents a derived-class constructor from catching any exceptions that come from a base class. This can be inconvenient at times.