0

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 ?

TT.
  • 15,774
  • 6
  • 47
  • 88
SpingNewbie
  • 39
  • 1
  • 4
  • "setter setClassName set public className in case of class Base and private field className in case of Derived. It is my intuition." Your intuition failed you in this case `this.className` used in `Base` will always refer to `className` defined in base(`setClassName` always set `Base.className`). related: https://stackoverflow.com/questions/9414990/if-you-overwrite-a-field-in-a-subclass-of-a-class-the-subclass-has-two-fields-w – Oleg Sep 24 '17 at 17:18
  • removing `this` doesn't help – SpingNewbie Sep 24 '17 at 17:28
  • help with what? what are you trying to achieve? removing `this` you will get `Base` `Base` because then your `setClassName` won't do anything it will assign the parameter to itself. – Oleg Sep 24 '17 at 17:29
  • No, I modified name of parameter. I mean that it still prints output different from my expactations – SpingNewbie Sep 24 '17 at 17:34
  • Well, you need to base your expectations on the Java language specification and not on your intuition and then you will not have this problem. – Oleg Sep 24 '17 at 17:40
  • My question is straigtforward: Why in setter method refers to public field, instead of private. – SpingNewbie Sep 24 '17 at 17:50
  • It has nothing to do with them being `public` or `private` asking why a banana is an apple is also straightforward and makes as much sense as your question. – Oleg Sep 24 '17 at 17:55
  • The most surprising thing is that you pay your attention to `this` - it doesn't matter here. Look at answer below. – Haskell Fun Sep 24 '17 at 18:24
  • @HaskellFun What do you mean "pay your attention to this"? You are the one who decided in your alternate moniker that removing it can help. Reread the answer you got and my first comment, now you are capable of understanding it. – Oleg Sep 25 '17 at 02:18

1 Answers1

1

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.

Ralf Kleberhoff
  • 6,990
  • 1
  • 13
  • 7
  • Yes, your answer is very helpful. Simply, variables are bounded statically (it can be seen by making pubilc className in subclass - then output is the same- because as you said: setter in base class can't know about fields in subclasses - after all, variables are bounded at compile time. Thanks! – Haskell Fun Sep 24 '17 at 17:57
  • @HaskellFun Are you SpingNewbie? What is this some kind of test? How did I score? – Oleg Sep 24 '17 at 18:06