Abstract类继承具有不同参数类型的抽象方法

时间:2016-03-12 08:00:09

标签: java oop inheritance

想象一下,我有一个带有方法的抽象类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."; }

因此,fetch方法接受扩展抽象类Animal的参数(因此是动物)。我在Animal中定义了方法fetch()来获取Animal类型的任何参数。对我来说,这是有道理的,因为猫和狗是动物,但Java说GoldenRetriever无法覆盖抽象方法fetch(Animal ani)。为什么是这样?

5 个答案:

答案 0 :(得分:1)

不确定我是否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) {

    }
}

答案 1 :(得分:1)

该方法不会覆盖,因为参数类型不同。你必须声明这样的方法:

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);

由于Animal fetch方法可以接受任何Animal,因此编译器认为进行此调用必须正常,因为FelineCatAnimal x。它无法知道GoldenRetriever实际上是GoldenRetriever。如果它允许覆盖方法采用FelineCat参数,则会出现问题,因为参数实际上是GoldenRetriever,而不是fetch。那么当多态地调用x时,参数类型是错误的,那么呢?

编译器无法阻止这种情况,因为它无法知道ClassCastException的类型是什么。从理论上讲,Java 可以允许覆盖更改参数类型,并在运行时进行检查(如果它试图让GoldenRetriever获取其他某些内容,可能会抛出Animal有点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 } } } )。我不知道为什么他们没有,但我确信有充分的理由不这样做。

但是你可以进行自己的运行时检查:

public void fetch(GoldenRetriever pup)

更新:上述答案假定方法签名确实是您想要的。但是根据Mixone的评论,可能是你尝试设置涉及两只动物的操作,在这种情况下你不应该有参数所有。像

这样的方法
GoldenRetriever

假设您有一个GoldenRetriever将与另一个GoldenRetriever做某事,并且您不希望int a, b; a = 7; b = 2; std::cout << a / b << std::endl; 与其他种类的动物一起做。在这种情况下,我认为运行时检查是最好的方法。但是,如果你想要一个只对一只动物起作用的手术,你就写错了。

答案 2 :(得分:0)

覆盖另一个方法的方法必须具有完全相同的参数,否则称为重载。  您的fetch方法必须声明如下:

public void fetch(Animal ani)

答案 3 :(得分:0)

您可以将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"; 
    }
}

这称为Curiously recurring template pattern

答案 4 :(得分:0)

    /*
 * 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" ; 
        }


}

只需复制粘贴代码

即可