I'll start with a code example:
class A {
public A() {
f(); //When accessed through super() call this does not call A.f() as I had expected.
}
public void f() {} //I expect this to be called from the constructor.
}
class B extends A {
private Object o;
public B() {
super();
o = new Object(); //Note, created after super() call.
}
@Override
public void f() {
//Anything that access o.
o.hashCode(); //Throws NullPointerException.
super.f();
}
}
public class Init {
public static void main(String[] args) {
B b = new B();
}
}
This program throws a NullPointerException
. When the object b enters the constructor of its superclass A
and makes a call to the method f()
which is overridden by the class B B.f()
is called, instead of A.f()
which I would have expected.
I thought a superclass wasn't supposed to know if it was subclassed or not but surely this can be used by a class to tell if it's been subclassed or not? What's the reason behind this? Is there any workaround if I really want A.f()
to be called instead of B.f()
?
Thanks in advance.
Follow up question:
Thanks for the answers. I now understand why it is like it is, but here's a follow up question. Perhaps I'm mistaken but a principle of subtyping is that the supertype should not know that it's been subtyped. This "mechanism" lets a class know if it's been subclassed or not. Consider this code example:
class A {
private boolean isSubclassed = true;
public A() {
f(); //A.f() unsets the isSubclassed flag, B.f() does not.
if(this.isSubclassed) {
System.out.println("I'm subclassed.");
} else {
System.out.println("I'm not subclassed.");
}
}
public void f() {
this.isSubclassed = false;
}
}
class B extends A {
public B() {
super();
}
@Override
public void f() {}
}
public class Init {
public static void main(String[] args) {
new B(); //Subclass.
new A();
}
}
The output of this program is:
I'm subclassed.
I'm not subclassed.
Here A
knows it's been subclassed. It's unkown by whom but that doesn't matter. How is this explained? Am I misinformed?