Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么';Java允许我执行这种类型的多态性/继承吗?_Java_Inheritance_Polymorphism - Fatal编程技术网

为什么';Java允许我执行这种类型的多态性/继承吗?

为什么';Java允许我执行这种类型的多态性/继承吗?,java,inheritance,polymorphism,Java,Inheritance,Polymorphism,我正在重构一个巨大的if语句。我发现改进它的方法之一是使用多态性和继承。以一种非常简单的方式,这就是我的代码中的内容: public abstract class Animal { public abstract void doAction(); } public class Dog extends Animal { public void doAction() {System.out.println("run");} } public class Cat ex

我正在重构一个巨大的if语句。我发现改进它的方法之一是使用多态性和继承。以一种非常简单的方式,这就是我的代码中的内容:

public abstract class Animal {  
    public abstract void doAction();  
}

public class Dog extends Animal {  
    public void doAction() {System.out.println("run");} 
}

public class Cat extends Animal {  
    public void doAction() {System.out.println("sleep");}
}

public class RunActions {  
    public void runAction(Dog d) {
        d.doAction();
    }

    public void runAction(Cat c) {
        c.doAction();
    }
}

public class Start {
    public static void main(String args[]) {
        Animal animal = new Dog();
        new RunActions().runAction(animal); // Problem!
    }
}
我知道,我知道。我可以叫animal.doAction();。或者在RunActions中添加一个接收Animal作为参数的方法

但是为什么编译器不允许我调用最后一行“runAction(animal)”?JVM不应该知道animal在运行时是Dog的一个实例吗

有没有具体的原因不允许我这么做

编辑:忘记让狗和猫扩展动物。已修复。

最好执行以下操作

public interface Animal {  
    public void doAction();  
}

public class Dog implements Animal{  
    public void doAction() {System.out.println("run");  
}

public class Cat implements Animal{  
    public void doAction() {System.out.println("sleep");  
}

public class RunActions {  
    public void runAction(Animal d) {
        d.doAction();
    }
}

public class Start {
    public static void main(String args[]) {
        Animal animal = new Dog();
        new RunActions().runAction(animal);
    }
}

首先,
应该扩展
动物

public class Dog exttends Animal{  
    @Override
    public void doAction() {System.out.println("run");  
}
和使用:

public class RunActions {  
    public void runAction(Animal a) {
        a.doAction();
    }
}

由于
都是
动物
,您可以使用
动物
参数。

首先,您没有在狗和猫中扩展动物。所以先这样做

在继承中,遵循ISA主体

比如说

public class Dog extends Animal
在这里,狗扩展了动物,所以狗就是动物,但反过来说,动物不一定是狗。在你的情况下,它也可能是猫

因此,当您将动物的引用传递给接受狗或猫分配的方法时

Dog d=animal;
动物就是狗,但事实并非如此

所以编译器不允许您这样做

关于为什么Java不允许这样做,是为了实现它能够实现的特性

例如,Java允许您将动物对象传递给该方法,并允许您执行该方法

那么在这种情况下

Animal animal=new Dog();
Dog d= animal;
d.doSomething(); // let's say java allowed this no problem since animal is DOG.
但是,


因此,为了避免这种情况,java足够智能,可以在您做错事情时阻止您。希望这能消除您的疑虑并帮助您理解这一点。

编译器不能保证在运行时有合适的方法

您有一个方法,它接受一只
,您有一个方法,它接受一只
。您正试图传递引用狗的
动物
变量。如果引用一头
大象
,该怎么办?那么在运行时就没有合适的方法了。这就是为什么它不允许您编译

Animal animal = new Elephant();
new RunActions().runAction(animal); // real problem now!

让您想要的东西变得不可能的主要基本概念是Java是一种单一的调度语言,就像几乎所有其他被称为“OOP”的语言一样。这意味着,运行时决定调用哪个方法只考虑第一个方法参数,该参数在语法上位于点之前,其值将绑定到
这个
特殊变量


您可能还想知道为什么在大多数语言中使用单一分派。。。这与封装的基本思想有关,对象是其方法的所有者。考虑你的情况:<代码> RunActudio<代码>属于<代码>运行> <代码>还是<代码>动物< /代码>?它平等地属于两者;更好的说法是:它不属于任何一方。这带来了一个完全不同的编程模型,一个没有封装的模型。

问题是并非所有动物都是猫或狗。考虑:

public class Fish implements Animal{  
    public void doAction() {System.out.println("swim");  
}
您希望您的RunActions类做什么

这就是编译器抱怨的原因



有几种方法可以让你的情况发挥作用。最简单的方法是有一个接受Animal的方法,并使用一系列的
instanceof
测试来确定你想对Animal的每个特定子类做什么。

Animal可以是一个抽象类,例如实现所有类型的
Animal
共享的一些公共特性。不过,我认为问题是为什么。例如,CLOS以OP在Java.Common Lisp对象系统中尝试的方式进行调度;它使用多个分派。@DaveNewton:好的。不知道。请参阅。它解释了一切。你救了我的击键+1这很容易理解。非常感谢。既然我们在讨论这个问题:有没有办法“欺骗”编译器,使其认为调用是可以的?例如某种getClass()(或其他反射内容)来欺骗编译器,使其认为调用可以工作?我不会那么做的。我保证。这只是出于好奇。@LucasTulio:不,没有。编译器查看并查看是否找到要调用的适用方法。如果是,好的,如果不是,你的错误。OP知道他可能会这样做。他的问题是为什么不允许他发布代码。
public class Fish implements Animal{  
    public void doAction() {System.out.println("swim");  
}