SpingNewbie
SpingNewbie

Reputation: 39

Misleading example of hiding names in Java

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

Answers (1)

Ralf Kleberhoff
Ralf Kleberhoff

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.

Why "b" and "d" are printed

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

Related Questions