Reputation: 213
This question is taken from an AP Computer Science practice test.
public class Bird
{
public void act()
{
System.out.print("fly");
makeNoise();
}
public void makeNoise()
{
System.out.print("chirp");
}
}
public class Dove extends Bird
{
public void act()
{
super.act();
System.out.print("waddle");
}
public void makeNoise()
{
super.makeNoise();
System.out.print("coo");
}
}
Suppose the following declaration appears in a class other than Bird or Dove:
Bird pigeon = new Dove();
What is printed as a result of the call pigeon.act()
?
I thought the answer would be "fly chirp", but the textbook says that the answer is "fly chirp coo waddle". I thought that 'pigeon' could only access methods available in Bird? I was under the impression that, if the user wanted to access methods in Dove, 'pigeon' would have to be cast to Dove.
Would Bird pigeon = new Bird();
give the same output? How about Dove pigeon = new Dove();
?
Upvotes: 5
Views: 305
Reputation: 5316
From your question "I thought that 'pigeon' could only access methods available in Bird? I was under the impression that, if the user wanted to access methods in Dove, 'pigeon' would have to be cast to Dove." This is actually true.
Lets try to find the mssing link in the understanding.
When we have code like Bird pigeon = new Dove();
where Dove
extends Bird
we have actual object of Dove
and reference type is of Bird
. As the object is of Dove
so it has the methods, both inherited from super class as well as the ones which are added.
Another important point is all the overriden
methods have only one instance. Its Overriden meaning the behavior of the same method has been modified, its not an additional separate method. There is only one copy of inherited method not both. Its the overloaded methods which are separate, just the names are same but signature is different. This is the reason you get the behaviour of Dove when you invoke any overriden method.
This one is simple super
, using it a sub class can access the accessible (visible) entities (instance properties and methods) of its super class. If a sub class uses super
keyword to invoke a method then its the method of the parent class which gets invoked. But again this can be considered that the author of the sub class did it intentionally. Once the class is written and Objects of such class is created then on the object using .
(dot operator) users can only invoke whats there in the object. If any method has used super
keyword its part of the behavior of the object. Users of the Sub class object can not invoke behavior of the parent class method if its overridden in sub class.
Lastly yes if you wish to invoke any additional method of Dove
(Sub class ) using a reference of Bird
(Super class) then you need to cast it to Dove
.
Upvotes: 1
Reputation: 140427
What you experience here is polymorphism in action. And instead of answering your various questions directly; I will simply explain the case you are observing.
You call act()
on an instance of Dove; that causes a call to super; printing "fly".
That super method then calls makeNoise()
... on "itself". But as said: "itself" is a Dove object; thus you get the Dove noise! "coo"!
Then the Dove implementation ends; and prints "waddle".
The essence is: the exact version of a method that is invoked is determined at runtime and it only depends on the exact type of the object the method is invoked on.
The above gives you all the information you need to answer your other questions yourself. In that sense: don't request answers; ask for explanations; and use those to solve the puzzle yourself!
Upvotes: 2
Reputation: 8068
Dove
does override the methods act
and makeNoise
of class Bird
. Overriding means changing the behavior of a method visible to the sub-class, (in your case Dove
). Methods are visible to a sub-class if they have a public
or protected
access modifier or if they have a package private
access modifier and the sub-class belongs to the same package as the super-class does. pigeon
is an instance of Dove
.pigeon.act()
results in calling Dove.act
.Dove.act
calls super.act
which is Bird.act
.Bird.act
prints fly
and calls makeNoise
on pigeon
resulting in calling Dove.makeNoise
.Dove.makeNoise
calls super.makeNoise
which is Bird.makeNoise
.Bird.makeNoise
print chirp
.Dove.makeNoise
prints coo
after calling super.makeNoice
Upvotes: 2
Reputation: 726529
Long story short, when you access act
method of pigeon
, its override from Dove
is called.
I thought that 'pigeon' could only access methods available in Bird?
That is certainly true, at least, for situations when no casting is applied. However, method act
is available on the class Bird
, the statically known type of pigeon
, so the call compiles fine.
However, accessing methods is only about being able to call them. What methods do when you call them is decided at runtime based on the dynamic type of pigeon
. This is where method overriding comes into play, because Dove
overrides Bird
's methods, but in addition it also calls Bird
's methods. That is why the code hits all four printouts.
Would
Bird pigeon = new Bird();
give the same output?
No, the output would be different, because in this case both dynamic and static types of pigeon
would be the same, i.e. Bird
, so only Bird
's implementations would be invoked.
Upvotes: 3