Calling the superclass constructor
The parent is always constructed first, whether or not you say so.
Before a subclass constructor body runs, the superclass constructor must complete. You can say which one:
public class Circle extends Shape {
private final double radius;
public Circle(String name, double radius) {
super(name);
this.radius = radius;
}
}
super(...) must be the first statement. So must this(...), which is why you cannot have both, a constructor delegates either sideways or upwards, never both.
The invisible super()
Omit it and the compiler inserts super(). The no-argument superclass constructor.
That is fine until the parent does not have one:
public class Shape {
Shape(String name) { ... } // no no-arg constructor
}
public class Circle extends Shape {
Circle() { } // won't compile
}
The error message talks about an implicit super() that does not exist. The fix is to call the constructor that does:
Circle() { super("circle"); }
This is the usual reason a subclass suddenly stops compiling after someone adds a constructor to the parent. Adding any constructor removes the free no-argument one.
Order of initialisation
For new Circle(...):
Object’s constructor, then each ancestor down the chain- The superclass’s field initialisers and instance blocks
- The superclass constructor body
- The subclass’s field initialisers
- The subclass constructor body
Field initialisers run after the parent constructor, which is the trap below.
Why not to call overridable methods
class Shape {
Shape() { draw(); } // overridable
void draw() { }
}
class Circle extends Shape {
private double radius = 5;
@Override void draw() { System.out.println(radius); }
}
new Circle() prints 0.0. The parent constructor calls draw(), the subclass override runs, and radius has not been initialised yet, step 3 happens before step 4.
Make anything a constructor calls private, final or static.
super outside constructors
super.method() calls the parent’s version. The usual way to extend rather than replace behaviour:
@Override
public String toString() {
return super.toString() + " radius=" + radius;
}