2017-07-30 22 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