Reputation: 39
Look at following source, please:
public class Base {
public String className = "Base";
public void setClassName(String className){
this.className = className;
}
}
public class Derived extends Base {
private String className = "Derived";
}
public class PrivateMatter {
private static void test (Base b){
System.out.println(b.className);
}
public static void main (String[] args){
Derived d = new Derived();
d.setClassName("d");
Base b = new Base();
b.setClassName("b");
test(b); // it prints b
test(d); // it prints d
}
}
I expected output:
b
Base
What should do test
? It should retrieve className
from class Base
, because in Derived
class it is private
.
However, setter setClassName
set public className
in case of class Base
and private field className
in case of Derived
. It is my intuition.
In order to sum up (my way of thinking):
Derived d = new Derived();
d.setClassName("d"); // it set private field (which did hide field from class Base)
Base b = new Base();
b.setClassName("b"); // it set public field (which is originally placed in `Base` class
test(b); // it prints b - it is ok for me
test(d); // it prints d - why ? After all, d.setClassName("d") should modify private field, however test should print public field
Could someone explain this strange thing ?
Upvotes: 0
Views: 78
Reputation: 7290
Short answer: A field can't override a field of the same name, it can only make it invisible. That's a major difference to methods.
You have two fields, one in Base
, and one in Derived
, which (by bad style) happen to have the same name className
. But they are completely distinct things. If you rename the Base class one to baseClassName and the Derived one to derivedClassName, the code will behave the same. (From now on, I'll use the new names to make clear what happens.)
You have one setClassName()
method in Base
, and it sets the field named className
known in the Base
class, being the baseClassName
field. This method can't even know that in some subclass there might be another field happening to have a colliding name. And as there is no field overriding in Java, it sets the baseClassName
, never the derivedClassName
.
The test()
method refers to Base.className
, being the baseClassName
field, never derivedClassName
. So this method prints the value that was set in the setClassName() call.
Upvotes: 1