java中的多态性:为什么我们设置父对象对象?

时间:2015-08-21 13:54:12

标签: java oop polymorphism

我想了解为子对象设置父引用的用例。 示例:Dog类扩展了Animal类。 (没有接口,请记住) 我通常会像这样创建一个Dog的对象:

Dog obj = new Dog();

现在,由于Dog是Animal的一个子类,因此它已经可以访问所有Animal的方法和变量。然后,这有什么不同:

Animal obj = new Dog(); 

请提供正确的用例以及其使用的代码段。没有关于多态性的理论文章'或者'编码到接口'请!

代码:

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");
    }
}

两种情况的输出相同。那么我们为什么要设置对子对象的父引用呢?

8 个答案:

答案 0 :(得分:8)

让我编写一些时间。

List<String> list = new ArrayList<String>;
list.doThis();
list.doThat();
等等。我疯了。我想使用LinkedList代替ArrayList

List<String> list = new LinkedList<String>;
list.doThis();
list.doThat();
是的,我必须只改变声明部分。无需触摸我的所有代码。感谢对接口和超类的编程。

答案 1 :(得分:3)

一般来说,你会了解java cast / oop概念。

DogAnimal的一种类型,因此您可以将其分配给动物。

但您无法将Animal分配给Dog。因为它可以是任何其他动物,如Cat。如果您确定该对象为Dog,则可以将其结算为Animal。如果Animal的类型为Dog,那么您就无法神奇地投射到Goat

答案 2 :(得分:2)

这是一个原则的实现,说 -

  

编程到接口,而不是实现。

例如,如果您设计一个方法来接受Animal类型的引用,那么将来您可以轻松地将= Cat实现传递给它(当然提供{{1} }}是Cat的子类型。

这意味着 -

Animal

比 -

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

因为对于第一种方法,您可以轻松地执行类似的操作 -

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

如果您决定创建新的doSomethingWithAnimal(new Cat()); 类型,则继承自Cat

答案 3 :(得分:1)

虽然有一些好的答案(在&#34; meh&#34;之中),但似乎没有人能接受你。也许他们太理论化或包含你不感兴趣的细节。所以另一个尝试:

对于您描述的示例,无关紧要。如果你真的只有像

这样的双线方法
void doit()
{
    Animal x = new Dog();
    x.shout();
}

然后你也可以写

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

这将直接劣势。

甚至可以概括这句话:对于仅使用本地的参考,这无关紧要。当您声明方法中的引用时,在此方法中使用此引用,并且将其传递给其他方法,那么将其声明为Animal而不是Dog并不是直接的优势。你可以两个。

但是...

即使你对此不感兴趣,我也不能忽略它:

...使用父类型是最佳实践的一部分:

  

您应该始终使用足以满足您要求的

的最小特定类型

这有各种技术原因,涉及抽象,概括,灵活性,多态性的应用,甚至可以将其称为某种类型的卫生&#34;。

明确指的是引用仅在本地使用的情况:如果您不想调用特定于Dog类型的方法,只想调用Animal类中的方法,然后你应该通过将变量声明为Animal来明确这一点 - 只是因为它是你需要的最不具体的类型。因此,在这些情况下使用类型Animal存在间接优势 - 即很明显以下代码将仅使用Animal类的方法,并且< Dog类的em> none 。

可以继续进行,并在此处进一步说明进一步的理由,用例和技术细节。但为此,您可以参考其他答案,或一些中级或高级教科书和教程。

答案 4 :(得分:1)

好。我想我得到了答案。

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..");
    }
}

因此,当我们对子类对象使用父引用时,我们无法使用该对象访问子类中的任何特定方法(父类中不存在)。

答案 5 :(得分:0)

当你从这样一个简单的例子开始时,你看不到任何好处,因为你已经将变量与它将保持的实际对象类型紧密耦合。

只有当您考虑方法声明时,多态性才会出现,其中参数是方法实现所需的最小特定类型:然后您可以使用任何子类型调用它,并且该方法将知道如何处理它,即使它不知道实际的对象类型。这是Liskov类型可替代性的本质。

所以想象你有一个方法

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

该方法适用于任何Animal,即使是在定义方法后定义的那些。

但是,如果您碰巧理解了上述内容,那么请专门询问 为什么会写

Animal a = new Dog();

然后它仍然经常有意义:你事先承诺,你不会引用实例的任何特定于狗的方面。通常你会看到

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

在这种情况下,我们知道代码的其余部分并不依赖于ArrayList作为列表实现的特定选择。这比上面描述的差异要小得多,但它是简洁,安全和习惯的结合,使它坚持下去。

答案 6 :(得分:0)

当您希望您正在编写的代码针对Animal接口而不是Dog实现时,就会出现这种情况。以这种方式创建对象可以使您的代码在长期内更加健壮。

我经常使用:

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

这在定义类级别变量时很重要,因为即使您稍后更改了不重要的细节,也希望整个对象都能正常工作。

答案 7 :(得分:0)

看看这个问题: -

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

在下面的方法中(工厂模式): -

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

你得到一种动物和Dog或Cat的实际对象,所以调用Animal的方法会调用在Dog或Cat的实际Object中重写的方法,如果被调用的方法在基类中被覆盖的话。它为您提供运行时的灵活性,以决定运行哪种方法,具体取决于实际对象和基类中的重写方法(如果有)。

完整示例如下: -

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

AnimalFactory有一个返回Animal的createAnimal方法。因为狗,狮子和马都是动物。因此,我们可以使用Animal返回类型创建Dog,Lion和Horse对象。我们使用Animal返回类型实现的是

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

没有Animal返回类型是不可能的。

如果我在createAnimal方法中使用返回类型作为Dog,那么它就不能返回Lion或Horse并且明智。