1
class Parent {
    String st = "external";

    void print() {
        System.out.println(st); 
        System.out.println(this.st);
    }
}

class Child extends Parent {
    String st = "inner";
}

public static void main(String[] args) {
    new Child().print(); // shows "external"
}

Why does print() called on subclass not show the string "inner"?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Vivyen
  • 67
  • 1
  • 6
  • 2
    You're [hiding](https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html) your superclass variable with the one in your subclass, not overriding it. – JonK Nov 30 '16 at 14:25
  • 1
    in my opinion a good question +1 – Willi Mentzel Nov 30 '16 at 15:06
  • actually i found similar problem here: [link](http://stackoverflow.com/questions/12244670/hiding-fields-in-java-inheritance) – Vivyen Nov 30 '16 at 16:36
  • @VivyenAndzuana yes, that is exactly the same problem. I would prefer you question nevertheless (although it is a duplicate) because it is really minimal and thus easier to understand. would be really great if you keep it that way in the future. SO is full of oversized questions... where mostly one line is in question :D – Willi Mentzel Nov 30 '16 at 16:40

4 Answers4

2

why print() called on subclass doesn't show string - "inner" ?

Because member variables cannot be overridden. The member variable st in class Child does not override the member variable st in class Parent. The two member variables are two separate variables, which happen to have the same name.

The methods in class Parent see the member variable st that is defined in class Parent, and not the one in class Child, even if the object is really an instance of class Child.

Only methods can be overridden.

More information in Oracle's Java Tutorials: Hiding Fields (thanks @JonK).

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 2
    Here's the official documentation of this feature if you want to include a link to it: https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html – JonK Nov 30 '16 at 14:27
  • Thanks, so how to access child field from print method without overriding the method? – Vivyen Nov 30 '16 at 14:31
  • That would only be possible by casting to `Child`: `System.out.println(((Child) this).st);` but that would be bad design in a real Java application. A superclass should not depend on a specific subclass in that way. – Jesper Nov 30 '16 at 14:36
  • To dig deeper on this, why can't you override the method? In this trivial example, it's definitely the right call. Is there some real-world constraint that prevents this? – Ironcache Nov 30 '16 at 14:37
  • Sure i can, but now i gonna work on understanding of hiding because i didn't know that i could stumble on this =) – Vivyen Nov 30 '16 at 14:45
1

As the others mentioned the field st of the Parent class is hidden. Just an addition if you want it to print "inner".

Change Child class to this:

class Child extends Parent {
    public Child() {
        st = "inner";
    }
}

This way the value of st from the Parent class is overriden!

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
  • Just note that this only works if `Parent` and `Child` are in the same package - if they're in different packages you would need to declare `st` to be `protected` in `Parent`. – JonK Nov 30 '16 at 16:44
  • @JonK this is true. but this is not the case as the example suggests. – Willi Mentzel Nov 30 '16 at 16:47
  • Yes - it's just something that the OP needs to be aware of – JonK Nov 30 '16 at 17:03
  • @JonK at this stage it will only confuse OP... so.. in my opinion too much information. there is a lot to inheritance which OP will learn, but here only this special question mattered. – Willi Mentzel Nov 30 '16 at 21:11
0

why print() called on subclass doesn't show string - "inner" ?

why should it? you are calling the method print() that is only override in the parent class up there in the parent class st is only holding the value "external"

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
0

The other answers cover why the behavior you notice is expected, so I won't touch on that. In terms of a solution to your problem, there are a few worth mention (neglecting things like reflection and subclass casting; technically solutions, but poor ones).

Option 1: Set Parameter

As Will mentioned, can simply set the parameter in Child:

class Child extends Parent{
    public Child() {
        st = "inner";
    }
}

Option 2: Method Override

Can also override the print() method (because, as mentioned, only methods can be overridden). Child would become something along the lines of:

class Child extends Parent{
    ...

    @Override
    void print() {
        // Child-specific implementation here.
    }
}

This will result in Child objects using their print method in place of Parent's method.

Option 3: Strategy Pattern

Another option is to use Strategy pattern. Consider the following:

public interface Strategy {
    String getString();
}

public class ParentStrategy implements Strategy {
    @Override
    public String getString() {
        return "external";
    }
}

public class ChildStrategy implements Strategy {
    @Override
    public String getString() {
        return "inner";
    }   
}

From here, all you need to do is change your Parent object so that it defaults to ParentStrategy, provide accessors to change the Strategy, change its print method to use the getString() method of its Strategy object, and change the Strategy in Child to use ChildStrategy:

class Parent{
    Strategy strat = new ParentStrategy();

    void setStrategy(Strategy s) {
        strat = s;
    }

    void print() {
        System.out.println(strat.getString()); 
    }
}
class Child extends Parent{
    public Child() {
        super();
        setStrategy(new ChildStrategy());
    }
}

In real world applications, this pattern is a fundamental tool to making flexible applications.

Ironcache
  • 1,719
  • 21
  • 33