Is it possible to call subclasses' methods on a superclass object?
Animal is a superclass of Dog and Dog has a method called bark
public void bark()
{
System.out.println("woof");
}
Consider the following:
Animal a = new Dog();
if (a instanceof Dog){
a.bark();
}
What will happen?
- the assignment isn't allowed
- the call to bark is allowed and "woof" is printed at run time
- the call to bark is allowed but nothing is printed
- the call to bark causes a compile time error
- the call to bark results in a run time error
I said 2 as we are checking if the object is a dog; as dog is the class with the bark method in it, if it is then we call it which will print out :s
Is my understanding correct here?
Solution 1:
This won't compile since Animal does not have a method called bark. Think of it this way, all dogs are animals, but not all animals are dogs. All dogs bark, but not all animals bark.
Solution 2:
no - the answer is;
4) the call to bark causes a compile time error
the bark method isnt defined as a method on the assigned type Animal, which will therefore result in compile time issue; this could be solved by casting;
((Dog)a).bark();
Solution 3:
The key is in the following line:
Animal a = new Dog();
Although a new instance of Dog
was created, its reference is by a
which is declared to be of the type Animal
. Therefore, any references to a
makes the new Dog
be handled as an Animal
.
Therefore, unless Animal
has a bark
method, the following line will cause a compiler error:
a.bark();
Even though a
is tested to see if it is an instance of Dog
, and a instanceof Dog
will actually return true
, the variable a
is still of is of type Animal
, so the block inside the if
statement still handles a
as an Animal
.
This is a feature of statically-typed languages where variables are assigned a type ahead of time, and checked at compile-time to see that the types match. If this code were performed on a dynamically-typed language, where the types are checked at runtime, something like the following could be allowed:
var a = new Dog();
if (a instanceof Dog)
a.bark();
a.bark()
is guaranteed only to execute when the instance is a Dog
, so the call to bark
will always work. However, Java is a statically-typed language, so this type of code is not allowed.
Solution 4:
In Head First Java they use the very good analogy of a TV remote control for a reference and your TV as the object that the reference points to. If your remote only has buttons (methods) for on, off, channel up and down, and volume up and down, it doesn't matter what cool features your TV has. You can still only do those few basic things from your remote. You can't mute your TV, for example, if your remote has no mute button.
The Animal reference only knows about Animal methods. It doesn't matter what other methods the underlying object has, you can't access them from an Animal reference.