簡體   English   中英

抽象類繼承具有不同參數類型的抽象方法

[英]Abstract Classes inheriting abstract methods with differing parameter type

想象一下,我有一個帶有方法的抽象類Animal:

public abstract void fetch(Animal ani);

然后,我有一個使用以下內容擴展此抽象類的類:

public class GoldenRetriever extends Animal {
       public void fetch(GoldenRetriever pup) { 
             pup.paws = "I have paws"; 
       }
}

我希望每個擴展Animal的類都具有fetch()方法。 但是,提取方法為有問題的動物(狗的爪子,貓的爪子等)分配了一些獨特的功能。 例如,對於cat的fetch()將采用參數fetch(FelineCat kitty)並說:

public void fetch(FelineCat kitty) { kitty.claws = "I have claws."; }

因此,訪存方法采用了擴展抽象類Animal(因此是動物)的參數。 我已經在Animal中定義了方法fetch()以采用Animal類型的任何參數。 對我來說,這是有道理的,因為貓和狗是動物,但是Java表示GoldenRetriever無法覆蓋抽象方法fetch(Animal ani)。 為什么是這樣?

不知道我是否100%正確地理解了您的問題,但我認為我有某種解決方案。 以下代碼可以正常工作,因為您總是必須使用通用參數,但這可能不是最佳選擇,但是至少鍵入是正確的。

public abstract class Animal<T extends Animal> {

    public abstract void fetch(T ani);
}

public class GoldenRetriever extends Animal<GoldenRetriever> {

    @Override
    public void fetch(GoldenRetriever ani) {

    }
}

該方法不會覆蓋,因為參數類型不同。 您必須這樣聲明方法:

public class GoldenRetriever extends Animal {
    public void fetch(Animal pup) { 

即參數類型仍然必須是Animal ,即使您正在編寫擴展Animal的類。

這是有充分的理由的。 假設您還有其他方法

public void someMethod(Animal x) 

您可以傳遞任何Animal作為參數,包括GoldenRetriever

GoldenRetriever gr = ...;
someMethod(gr);

假設在someMethod您有:

public void someMethod(Animal x) {
    FelineCat kitty;
    ...
    x.fetch(FelineCat);

由於Animalfetch方法可以接受任何Animal ,因此編譯器認為進行此調用必須可以,因為FelineCatAnimal 它無法知道x實際上是GoldenRetriever 如果它允許重寫方法采用GoldenRetriever參數,則會出現問題,因為該參數實際上是FelineCat ,而不是GoldenRetriever 那么,當fetch被多態調用,並且參數類型錯誤時,那又如何呢?

編譯器無法阻止這種情況,因為它無法知道x的類型。 從理論上講,Java 可以允許重寫更改參數類型,並在運行時進行檢查(如果嘗試獲取GoldenRetriever以獲取其他某種Animal則可能拋出ClassCastException )。 我不知道為什么他們沒有這樣做,但是我敢肯定有充分的理由不這樣做。

但是您可以進行自己的運行時檢查:

public class GoldenRetriever extends Animal {
    public void fetch(Animal pup) { 
        if (pup instanceof GoldenRetriever) {
            GoldenRetriever puppy = (GoldenRetriever)pup;
            // now puppy is viewed as a GoldenRetriever, and any methods or
            // instance variables particular to GoldenRetrievers can be accessed
        } else {
           throw new WrongSpeciesException("..."); // or whatever
        }
    }
}

更新:上面的答案假定方法簽名確實是您想要的。 但是按照Mixone的評論,可能是您打算建立涉及兩個動物的操作,在這種情況下,您根本不需要參數。

public void fetch(GoldenRetriever pup)

假設您有一個GoldenRetriever可以與另一個GoldenRetriever一起GoldenRetriever ,並且您只是不希望GoldenRetriever與其他種類的動物GoldenRetriever做。 在那種情況下,我認為運行時檢查是最好的方法。 但是,如果您想要只對一只動物起作用的手術,那您就把它寫錯了。

覆蓋另一個方法的方法必須具有完全相同的參數,否則稱為重載。 您的fetch方法必須這樣聲明:

public void fetch(Animal ani)

您可以將Animal類設為通用類

abstract class Animal<TAnimal extends Animal<?>> {
    public abstract void fetch(TAnimal ani);
}

class GoldenRetriever extends Animal<GoldenRetriever> {

    String paws;

    @Override
    public void fetch(GoldenRetriever pup) { 
         pup.paws = "I have paws"; 
    }
}

這稱為好奇重復模板模式

    /*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package fetchanimal;

/**
 *
 * @author Amin
 */
public abstract class Animal <T>{


    public abstract void fetch(T animalType);
}

現在創建一個新類

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package fetchanimal;

/**
 *
 * @author Amin
 */
public class FelineCat extends Animal<FelineCat> {
   public String claws ;
    @Override
    public void fetch(FelineCat animalType) {
     //   throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        animalType.claws = "hello";

    }

}

現在創建第三類

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package fetchanimal;

/**
 *
 * @author Amin
 */
public class GoldenRetriever extends Animal<GoldenRetriever>{
    public String paws ;  


    @Override
    public void fetch(GoldenRetriever animalType) {
      //  throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
       animalType.paws = "hello" ; 
        }


}

只需復制粘貼代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM