Change the Tiger class to:
public class Tiger extends Animal { public Tiger() { setSound("ROAR"); } }
The problem is that the roar() method defined in Animal uses the private field of the sound member defined in the same Animal class.
sound from Animal not displayed to the Tiger class because it is closed. Thus, you declared a new sound field for the Tiger subclass, but that did not override the source code from Animal . The Animal class still uses its own version of sound because it is the only version it sees. Unlike methods, a field cannot be overridden .
One solution is to use getter / setter methods declared in the base class ( Animal ) for all access to properties, even from subclasses.
Another possible solution would be to use abstract and polymorphism methods:
You do not use the sound method in the base class Animal, you simply declare an abstract method and substitute subclasses in your own implementations:
public abstract class Animal { public void roar() { System.out.println(sound()); } public abstract String sound(); } public class Tiger extends Animal { public String sound() { return "ROAR"; } } public class Dog extends Animal { public String sound() { return "HOOF HOOF"; } }
Despite the fact that in Animal there is no implementation (without a body with code) of the sound() ) method, you can still call this method from other methods of this class, for example roar() .
Of course, this approach does not allow you to change the sound of an existing animal object (there is no setter), making the animals unchanged , which may seem uncomfortable at first, but if you think about it for a while, you may find that in many cases you actually do not need to change the state objects that way.
Using immutable objects is actually convenient, because the code is simpler and more secure, because you do not need to think about all the possible states that may occur during program execution.