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 member private field sound
defined in the very same Animal
class.
The sound
from Animal
isn't visible to the Tiger
class, because it's private. So you declared a new sound
field for the Tiger
subclass, but that didn't override the original one from Animal
. The Animal
class still uses it's own version of sound
, because it's the only version it sees. Unlike methods, field can't be overriden.
One solution is to use getter/setter methods declared in the base class (Animal
) for all access to properties, even from the subclasses.
Another possible solution would be using abstract methods and polymorphism:
You don't implement sound method in the Animal base class, you just declare an abstract method and force subclasses to provide their 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";
}
}
Even though there is no implementation (no body with code) of the sound()
method in Animal, it is still possible to call that method from other methods of this class, such as roar()
.
Of course, this approach makes you unable to change the sound of an existing animal object (there is no setter), making animals immutable, which might seem inconvenient at first, but if you think about it for a while, you might find out that in many cases, you do not actually need to change state of the objects in this manner.
Using immutable objects is actually convenient, because the code is more simple and secure, because you don't have to think about all the possible states that can possible occur during the execution of the program.