Java创建子类变量 - 多态无效

时间:2017-07-30 19:30:34

标签: java

由于我是Java和OOP的新手,这对我来说很有用。假设我有一个类Animal,以及扩展Animal的子类DogFrogCatAnimal及其所有子类都有move()方法。除了自己的代码之外,子类中的move()在其中使用super.move()。我的Main类有一个变量currentAnimal,它基本上保存了房间中当前动物的实例,因此一次只能存在1只动物(可以是Dog,Frog或Cat类)。

我将currentAnimal初始化为Animal currentAnimal = null(使它成为Animal类可能是错误的,因为它永远不会是Animal类,而是一些子动物类(Frog,Dog,Cat) ),但我没有看到更好的选择,键入Object而不是Animal似乎不起作用)。程序运行时,它接受来自用户的命令,例如,如果命令为"new Dog",则执行以下Main.currentAnimal = new Dog()

然后我希望用户能够调用“move”命令,该命令将执行当前存储在move()中的对象的currentAnimal。问题发生在这里,因为编译器认为currentAnimal是Animal类的实例,它告诉我Animal类具有move()方法但具有不同的签名且无法编译。但我不希望它调用Animal.move(),而是希望它调用move()中当前对象的currentAnimal(例如,如果对象属于Dog类,那么它将使用{{} 1}},而不是Dog.move())。如果我知道当前存储在currentAnimal中的哪个动物我将使用强制转换,但我不知道,我只知道currentAnimal中的动物有Animal.move()方法,我想调用它。我该怎么做?

主要课程:

move()

动物类:

public class Main {
    static Animal currentAnimal = null;

    public static void main(String[] args) {
    currentAnimal = new Dog(2,3);
    currentAnimal.move("asd");
    }

}

狗班:

public class Animal {
    public void move(String s1, String s2){
        System.out.println("animal.move - parameters: " + s1 + " " + s2);
    }
}

它最终运行Animal.move()而不是Dog.move()。我不能用新的Dog()声明一个变量,因为它的变化取决于用户在执行期间给出的命令。只要没有动物,currentAnimal就为空

1 个答案:

答案 0 :(得分:0)

如果你声明一个这样的变量:

Animal animal = new Dog();
animal.move();

由于java polymorphism principle,它将从move()类执行Dog方法。

但是,您获得的错误是由于子类中.move()方法的覆盖(签名)不正确,与超类.move()中的Animal方法有关。< / p>

来自move()的{​​{1}}方法具有签名:

Animal

public void move(String s1, String s2) 中的一个是:

Dog

那不是覆盖,而是重载(=相同的方法名称,但是参数不同,所以实际上只是一种不同的方法)。多态性仅适用于重写的方法。

要从超类覆盖方法,方法必须

  • 返回相同或更具体(子类)的返回类型 - 您在Animal和Dog中没有返回类型(public void move(String s1); ),这样就可以了
  • 具有相同数量的参数 - 你没有:Dog.move()有两个参数,Animal.move只有一个
  • 来自Dog.move()的参数类型需要与Animal.move相同或更通用(你的参数类型是String就可以了)
  • 你不应该在你的子类方法中引入额外的异常(不要声明任何,所以没关系)
  • 访问声明应该相同或更少限制(在您的示例中为void

所以在public中,向Dog方法添加一个String参数,这样它需要两个字符串,或者在move() move方法中删除一个String参数,然后你得到了预期的行为。

注意:在Animal上添加注释@Override是一种很好的做法,因此当您对覆盖(继承)原则产生错误时,IDE会立即告诉您:

Dog.move()

基于您的评论的替代解决方案:如果您仍需要Animal上的move(String,String),但所有子动物都有move(String)方法,您可以向Animal添加一个抽象方法。 :

//in Dog
@Override
public void move(String s1, String s2) {
    super.move("s1", "s2")
    (...)
}

子类:

public abstract class Animal {
    //protected because this will only be called from sub classes
    protected void move(String st1, String st2) {
        //implementation of method
    }

    //overload of the other move method (not override)
    public abstract void move(String str);  //no implementation
}

主要方法:

public class Dog extends Animal {

    //mandatory override as this defined on the Animal level as abstract
    @Override
    public void move(String str) {
        this.move("st1", "st2");    //call overloaded move defined on Animal level

        //the rest of the implementation
    }
}