2017-07-30 20 views
-5

因为我是Java和OOP的新手,所以我很在意。可以说我有一个类Animal,和Dog,Frog,Cat的子类扩展动物。 Animal及其所有子类都有一个move()方法。子类中的move()除了使用自己的代码外,还使用super.move()。我的Main类有一个变量currentAnimal,它基本上持有房间中当前动物的实例,因此一次只能存在1只动物(可以是Dog,Frog或Cat类)。Java创建子类的变量 - 多态性不起作用

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

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

主类:

public class Main { 
    static Animal currentAnimal = null; 

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

} 

Animal类:

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

Dog类:

public class Dog extends Animal { 
    int h; 
    int w; 
    public Dog(int h, int w){ 
     this.h = h; 
     this.w = w; 
    } 

    public void move(String s){ 
     super.move("s1", "s2"); 
     System.out.println("dog.move - parameters: " + s); 
    } 
} 

它结束了运行Animal.move()而不是Dog.move() 。我不能用新的Dog()声明一个变量,因为它的变化取决于用户在执行过程中给出的命令。

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

它将从Dog类执行,因为java polymorphism principlemove()方法:每当有没有动物,如果你声明这样的变量currentAnimal为空

+1

请张贴代码 – baao

+2

格式化您的文章。单片帖子往往被忽略。使用段落,将您的解释/示例捆绑在一起。就像你向忙碌的人解释问题一样,保持简洁。 –

+0

您将会看到Java已经通过多态性为您完成了这项工作。 –

回答

0

但是,您得到的错误是由于您的子类中的.move()方法的错误覆盖(签名),您的超类中的方法.move()

Animalmove()方法有签名:

public void move(String s1, String s2) 

Dog的一个是:

public void move(String s1); 

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

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

  • 返回相同的或更具体的(子类)返回类型 - 你不必在动物和狗返回类型(void)所以没问题
  • 具有相同数量的参数 - 你没有那个:Dog.move()需要两个参数,Animal.move只需要一个
  • Dog.move()的参数类型需要相同或更一般然后Animal.move(您的参数类型是字符串即可)
  • 在子类方法,你不应该引入额外的例外(在你的例子public)(不要不声明任何所以这是确定)
  • 访问声明应该是相同的或较少限制

所以在Dog中,向move()方法添加一个String参数,以便它需要两个字符串或移除Animal移动方法中的一个String参数,并获得预期行为。

注:它很好的做法,添加注释@Override上Dog.move()这样,所以你的IDE可以立即告诉你,当你做出一个错误的覆盖(继承)原则:

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

替代解决方案根据你的意见:如果你仍然需要动物的移动(String,String),但所有的子动物都有移动(String)方法,你可以给Animal添加一个抽象方法。 :

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 
    } 
} 

主要方法:

public static void main(String[] args) { 
    Animal animal = new Dog(...); 
    animal.move("str"); //calls the move(String) method in Dog, polymorphism 
} 
+0

我不能声明这样的变量,因为它在编译时为空,而且它的类根据用户命令而改变。添加我的代码 – Max

+0

嗯,你只能在用户输入后实例化子类(称为Dog/Frog/Cat构造函数)(因为只有这样你才知道要实例化哪个子类)。在你用一个子类实例化了你的动物之后,它不再是'null',只有这个对象存在,你可以调用它的'move()'方法 –

+0

谢谢你的解释,但是如果我特别需要'Animal.move()'和'Dog.move()'有不同的签名?所有的动物首先必须执行'Animal.move()',然后继续自己的move()。然后,我必须做出'动物'类抽象,并再做一个'move()'以匹配'Dog.move()'的签名?还是有更好的方法来做到这一点? – Max