Solution:
This is a problem of initialization order. The subclass constructor will not have had a chance to run yet and there is no way to force it to run it before the parent class. Consider the following example class:
public abstract class Widget {
private final int cachedWidth;
private final int cachedHeight;
public Widget() {
this.cachedWidth = width();
this.cachedHeight = height();
}
protected abstract int width();
protected abstract int height();
}
This seems like a good start for an abstract Widget: it allows subclasses to fill in width
and height
, and caches their initial values. However, look when you spec out a typical subclass implementation like so:
public class SquareWidget extends Widget {
private final int size;
public SquareWidget(int size) {
this.size = size;
}
@Override
protected int width() {
return size;
}
@Override
protected int height() {
return size;
}
}
Now we’ve introduced a subtle bug: Widget.cachedWidth
and Widget.cachedHeight
will always be zero for SquareWidget
instances! This is because the this.size = size
assignment occurs after the Widget
constructor runs.
Avoid calling abstract methods in your abstract classes’ constructors, as it restricts how those abstract methods can be implemented.