I want to understand the use-case of setting a parent reference to a child object. Example: Dog class extends Animal class. (No interfaces, mind it) I would normally create an object of Dog like this:
Dog obj = new Dog();
Now, since Dog is a subclass of Animal it already has access to all of Animal's methods and variables. Then, what difference does this make:
Animal obj = new Dog();
Please provide a proper use-case with an code snippet of it's use. No theoretical articles about 'Polymorphism' or 'Coding to interfaces' please!
Code:
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Dog();
Dog obj2 = new Dog();
obj1.shout(); //output is bark..
obj2.shout(); //output is bark..
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Dog extends Animal{
public void shout(){
System.out.println("bark..");
}
}
class Lion extends Animal{
public void shout(){
System.out.println("roar..");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh");
}
}
Output is the same for both the cases. Then why do we set parent reference to child object?
This would be when you want the code that you're writing to work against the Animal interface instead of the Dog implementation. Creating an object in this way makes your code more robust in the long term.
I frequently use:
This is important when defining class level variables, because you want your whole object to work even if you change an unimportant detail later.
Think generally, you will know java casting/oop concept.
Dog
is a type ofAnimal
so you can assign it to an animal.But you can't assign
Animal
to aDog
. Because it can be any other animal likeCat
. If you are sure the object isDog
, you can caste that toAnimal
. If theAnimal
is of typeDog
then you cannot magically cast to aGoat
.Although there are some good answers (among the "meh" ones), it seems like none was acceptable for you. Maybe they are too theoretical or contain details that you are not interested in. So another try:
For the example that you described, it does not matter. If you really only have a two-line method like
then you could also have written
and this would not have a direct disadvantage.
One could even generalize this statement: For a reference that is only used locally, it does not matter. When you declare the reference in the method, and only use this reference in this method, and do not pass it to other methods, then there is no direct advantage in declaring it as
Animal
instead of asDog
. You can to both.But...
even if you are not interested in this, I can't omit it:
... using the parent type is part of a best practice:
This has various technical reasons, regarding abstraction, generalization, flexibility, the application of polymorphism, and one could even go so far to call it a sort of "type hygiene".
And this explicitly also refers to the case where the reference is only used locally: If you don't want to call methods that are specific for the type
Dog
, but only want to call methods from theAnimal
class, then you should make this clear by declaring the variable as anAnimal
- simply because that's the least specific type that you need. So there is an indirect advantage of using the typeAnimal
in these cases - namely that it is clear that the following code will only use methods of theAnimal
class, and none of theDog
class.One could continue and go very far with further justifications, use case examples and technical details here. But for this, you may refer to the other answers, or some intermediate or advanced texbooks and tutorials.
Okay. I think I got my answer.
So, when we use parent reference for child class object, we cannot access any specific methods in child class (that are not present in parent class) using that object.
Let me code some time.
Oh wait ..I'm gone mad. I want to use
LinkedList
instead ofArrayList
Yup, I have to change only declaration part. No need to touch all of my code. Thanks to programming to interfaces and with super classes.
When you start with such a simple example, you can't see any benefits because you have tightly coupled the variable to the actual type of object it will hold.
Polymorphism comes into its own only when you consider method declarations where the parameter is of the least specific type needed by the method's implementation: then you can call it with any subtype and the method will know what to do with it, even though it has no knowledge of the actual object type. That's the essence of Liskov substitutability of types.
So imagine you have a method
The method will work against any
Animal
, even those you defined after defining the method.But, if you happen to understand the above, yet ask specifically why one would write
then it still often makes sense: you promise up-front that you won't refer to any dog-specific aspects of the instance. Typically you'll see
and in this case we know that the rest of the code doesn't rely on the specific choice of
ArrayList
as list implementation. This is a much smaller difference than the one decribed above, but it's a combination of brevity, safety, and custom which makes it stick.