Tuesday, May 15, 2007

Overriding an Instance Field Should be a Compile Error

Consider this scenario:
class A {
String s = "A";
void bar() {
  System.out.println(s);
}
}

class B extends A {
String s = "B";
}

public static void main(String[] args) {
B foo = new B();
foo.bar();
}
What gets printed, A or B? The answer is A. I expected B. Since B doesn't define bar(), B inherits the definition from A. My OOP intuition says that B should do just that---inherit the definition of bar(), and call it as if it were defined in B. Clearly, this isn't what Java does. Creation of constructors for A, "A(){System.out.println("A()");}", and B, "B(){}", provide insight into what Java is doing. Running main() with these constructors yields "A()" on standard out. I.e. even though the constructor for A is never explicitly called, it is still being called---Java is creating a phantom instance of A which handles inherited function calls. The problem here is that class B is hiding the s field of class A. I.e. two s fields are instantiated, one for A and one for B. The foo.bar() call executes the class A function, so it uses the class A field. What I find a bit disturbing is that Java allows field hiding. What's the point? The new field can't affect invocations of superclass methods. So, the new field is sufficiently distinct from the superclass field so as to deserve a different name. Seems to me that field hiding only creates confusion. Update 12/18/07: Field hiding ("Hiding Superclass Fields") is discussed by Flanagan. Also, see "Overriding Superclass Methods".

No comments: