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.