10

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 its 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?

Y.H.
  • 2,687
  • 1
  • 29
  • 38
Subhadeep Banerjee
  • 225
  • 1
  • 2
  • 12
  • Dog is a type of animal so you can assign to animal. but you can't assign animal to dog. becuase it can be different. if you sure it is dog animal you name it as dog using casting. if the animal is a dog then you can not say it is goat so you can not cast dog animal to goat – Raghavendra Aug 21 '15 at 13:57
  • 4
    Your key word to google is `programming to interface.` – Suresh Atta Aug 21 '15 at 13:57
  • 1
    Since tomorrow you might want to implement with some other Animal, Lion or Tiger. – Kulbhushan Singh Aug 21 '15 at 13:57
  • 2
    http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface – Reimeus Aug 21 '15 at 14:01
  • @Sandeep Luckily I wrote an article on the same. Used same Class names :) http://codeinventions.blogspot.in/2014/10/programming-with-interface-and-programming-to-interface-in-java-difference.html – Suresh Atta Aug 21 '15 at 14:02
  • @suresh, Actually my question is more confined to a parent class, rather than an interface. The interface example is fine but that's not really my question. – Subhadeep Banerjee Aug 21 '15 at 14:38
  • 3
    The fact that it's a class, not an interface, makes **no difference in this discussion.** Note that most of the answers are talking about interfaces. It's not important to do `Animal animal = new Dog()` if `Animal` is a class. Also, **requests for examples** are off topic on Stack Overflow because they can't be answered properly - everyone can come up with a different example. – durron597 Aug 21 '15 at 15:14
  • @SubhadeepBanerjee See my edited response below. – Goyal Vicky Aug 21 '15 at 17:16

8 Answers8

8

Let me code some time.

List<String> list = new ArrayList<String>;
list.doThis();
list.doThat();

Oh wait ..I'm gone mad. I want to use LinkedList instead of ArrayList

List<String> list = new LinkedList<String>;
list.doThis();
list.doThat();

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.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • First thing is List is an interface. My question is more confined to parent & sub classes. Secondly, If you would have used: ArrayList list = new ArrayList(); even then the change would be similar (in one line, 2 places) LinkedList list = new LinkedList(); How much difference does it make? – Subhadeep Banerjee Aug 21 '15 at 14:53
  • @SubhadeepBanerjee That is why I mentioned in the last. `hanks to programming to interfaces and with super classes.` – Suresh Atta Aug 21 '15 at 15:44
  • @SubhadeepBanerjee `LinkedList list = new LinkedList();` You are not seeing any change but consider there are few methods added in only in `ArrayList` and those which are not available in `LinkedList` – Suresh Atta Aug 21 '15 at 15:46
4

This is an implementation of a principle which says -

Program to an interface, not to an implementation.

As an example, if you design a method to accept a reference of type Animal, then in future you can easily pass an= Cat implementation to it (provided of course that the Cat is a sub-type of Animal.

Which means -

public void doSomethingWithAnimal(Animal animal) {
    // perform some action with/on animal
}

is much more flexible than -

public void doSomethingWithAnimal(Dog d) {
    // your code
}

because for the first method, you can easily do something like -

doSomethingWithAnimal(new Cat());

if you ever decide to create new Cat type, inheriting from Animal.

MD Sayem Ahmed
  • 28,628
  • 27
  • 111
  • 178
  • Wow, people are so fast to downvote answers these days. Could someone please point out what did I say in my answer that is wrong? Perhaps I will be able to correct myself and learn something new. – MD Sayem Ahmed Aug 21 '15 at 14:04
  • no idea. i have a doubt why the answer is blinking? – Raghavendra Aug 21 '15 at 14:07
  • @Reddy When an answer gets -3, it fades away. You seen that. Now someone up voted this and became -2. So you won't see that fade now. – Suresh Atta Aug 21 '15 at 14:25
  • I have no idea why the .... this was downvoted. It was at least as clear and IMHO more spot-on than other answers. – Marco13 Aug 21 '15 at 14:30
3

Think generally, you will know java casting/oop concept.

Dog is a type of Animal so you can assign it to an animal.

But you can't assign Animal to a Dog. Because it can be any other animal like Cat. If you are sure the object is Dog, you can caste that to Animal. If the Animal is of type Dog then you cannot magically cast to a Goat.

Raghavendra
  • 3,530
  • 1
  • 17
  • 18
2

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

void doit()
{
    Animal x = new Dog();
    x.shout();
}

then you could also have written

void doit()
{
    Dog x = new Dog();
    x.shout();
}

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 as Dog. 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:

You should always use the least specific type that is sufficient for what you want to do

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 the Animal class, then you should make this clear by declaring the variable as an Animal - simply because that's the least specific type that you need. So there is an indirect advantage of using the type Animal in these cases - namely that it is clear that the following code will only use methods of the Animal class, and none of the Dog 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.

Marco13
  • 53,703
  • 9
  • 80
  • 159
1

Okay. I think I got my answer.

public class Polymorphism {
    public static void main(String[] args){
        Animal obj1 = new Horse();
        Horse obj2 = new Horse();

        obj1.shout();    //output is neigh..
        obj2.shout();    //output is neigh..
        obj1.winRaces(); /*But this is not allowed and throws compile time error, 
                           even though the object is of Animal type.*/ 
    }   
}

class Animal{
    public void shout(){
        System.out.println("Parent animal's shout");
    }       
}

class Horse extends Animal{
    public void shout(){
        System.out.println("neigh..");
    }
    public void winRaces(){
        System.out.println("won race..");
    }
}

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.

Subhadeep Banerjee
  • 225
  • 1
  • 2
  • 12
0

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

int getAge(Animal a) {
   return Days.toYears(currentDate() - a.dateOfBirth());
}

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

Animal a = new Dog();

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

List<String> strings = new ArrayList<>();

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.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Marko, I understand what you're saying. But cat, dog, monkey etc are already subclasses of the Animal type. Hence you can pass any subclass type to the method as well. So why the jugglery with the object reference? – Subhadeep Banerjee Aug 21 '15 at 14:33
  • So, you can see the value of the more generic method parameter, but you don't see the value of the type of the actual declaration? Your question is not only poorly articulated, but who cares? It is so pedantic it isn't even worth the effort. If you build an application that has a clear separation between interfaces and implementations, you will use the interface everywhere. You keep making the distinction between parent classes and interfaces, but this is a distinction without a difference. – CaTalyst.X Aug 22 '15 at 00:15
0

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:

List<Object> aList = new ArrayList<>();

This is important when defining class level variables, because you want your whole object to work even if you change an unimportant detail later.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
Thom
  • 14,013
  • 25
  • 105
  • 185
0

Looking at the question:-

Polymorphism in java: Why do we set parent reference to child object?

In a method like below(Factory Pattern):-

public Animal doSomething(String str){
if(str.equals("dog")){
    return new Dog();
    }
else if(str.equals("cat")){
    return new Cat();
    }
else {
    return new Animal();
    }
}

You get a type of Animal and actual object of either Dog or Cat so calling a method of Animal will call the method overridden in actual Object of either Dog or Cat if the called method is overridden in base class. It provides you with the flexibility at run time to decide which method to run depending on the actual object and overridden method in base class if any.

The complete example is as under :-

package com.test.factory;

public class Animal{
    public void shout(){
        System.out.println("Parent animal's shout");
    }       
}

package com.test.factory;

public class Dog extends Animal{

    @Override
    public void shout(){
        System.out.println("bark..");
    }
}

package com.test.factory;

public class Horse extends Animal{

    @Override
    public void shout(){
        System.out.println("neigh");
    }
}

package com.test.factory;

public class Lion extends Animal{

    @Override
    public void shout(){
        System.out.println("roar..");
    }
}

    package com.test.factory;

    public class AnimalFactory {

        public Animal createAnimal(String str){

            if(str.equals("dog")){
                return new Dog();
                }
            else if (str.equals("horse")){
                return new Horse();
                }

            else if(str.equals("lion")){
                return new Lion();
                }
            else{
                return new Animal();
            }
        }

    }

    package com.test.factory;


  package com.test.factory;


public class Polymorphism {
    public static void main(String[] args){

        AnimalFactory factory = new AnimalFactory();
        Animal animal = factory.createAnimal("dog");
        animal.shout();
        animal = factory.createAnimal("lion");
        animal.shout();
        animal = factory.createAnimal("horse");
        animal.shout();
        animal = factory.createAnimal("Animal");
        animal.shout();

    }   
}


    Output is :-
    bark..
    roar..
    neigh
    Parent animal's shout

The AnimalFactory has a createAnimal method which returns Animal. Since Dog, Lion and Horse are all animals. So we are able to create Dog, Lion and Horse objects by using Animal return type. What we achieved using Animal return type is

Animal animal = new Dog();
Animal animal = new Lion();
Animal animal = new Horse();

which is not possible without the Animal return type.

If I use return type as Dog in createAnimal method then it cannot return Lion or Horse and like wise.

Goyal Vicky
  • 1,249
  • 16
  • 16