Polymorphism in java: Why do we set parent referen

2020-02-09 09:15发布

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?

8条回答
地球回转人心会变
2楼-- · 2020-02-09 09:58

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.

查看更多
甜甜的少女心
3楼-- · 2020-02-09 10:00

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.

查看更多
家丑人穷心不美
4楼-- · 2020-02-09 10:05

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.

查看更多
相关推荐>>
5楼-- · 2020-02-09 10:06

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.

查看更多
Root(大扎)
6楼-- · 2020-02-09 10:07

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.

查看更多
疯言疯语
7楼-- · 2020-02-09 10:08

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.

查看更多
登录 后发表回答