首页 > 解决方案 > Java泛型、接口和类继承

问题描述

考虑抽象类:

public abstract class Animal { ...}

和界面:

public interface Canine<T extends Animal> {...}

我已经定义了具体的类:

public class Dog extends Animal implements Canine<Dog> {...}
public class Wolf extends Animal implements Canine<Wolf> {...}

我想建立一个repository访问动物数据库并返回它们的类。我用以下方式定义了它:

public interface Repository {
    Option<Dog>  findById(String id, Class<Dog>  type);
    Option<Wolf> findById(String id, Class<Wolf> type);

注:Option取自vavr图书馆

此存储库用于以下类:

public abstract AbstractFinderClass<T extends Animal & Canine<T>> {

    private Class<T> animalType;

    public AbstractFinderClass(Class<T> animalType) {
        this.animalType = animalType;
    }

    public Option<T> findMyAnimal(String id) {
        return repository.findById(id, this.animalType);
    }
}

这又以具体的形式实现:

public class DogFinder extends AbstractFinderClass<Dog> {
    public DogFinder() {
        super(Dog.class);
    }
}

现在,该行return repository.findById(id, this.animalType)导致两个错误:

  1. 在第二个参数上,this.animalType是类型Class<T>,而预期类型是Class<Dog>,这些显然是不兼容的;
  2. 返回类型应该是Option<T>while 而不是我得到Option<Dog>

恐怕我错过了一些“小”细节,正如我所期望的那样Dog,并且T是兼容的。你能帮我解决这个问题吗?

标签: javagenerics

解决方案


第一个问题是你有一个不必要的类型参数DogFinder。它是一个寻狗器,因此它所找到的类型参数是多余的(非常规命名的类型参数Dog可能表明存在问题)。它应该是:

class DogFinder extends AbstractFinderClass<Dog> {
    public DogFinder() {
        super(Dog.class);
    }
}

其次,您的Repository类型具有绑定到特定类型的方法。这没有什么意义,因为您希望它是通用的。因此,您可以只使用一种方法,(可选)使存储库本身具有通用性(在解决签名冲突问题的过程中):

interface Repository<T extends Animal> {
    Option<T> findById(String id, Class<T> type);
}

第三,除非我们缺少上下文,否则我相信您的Canine类型不需要是通用的(除非事情必须令人费解):

interface Canine {
}

如果你需要一个专门的 canine finder,你可以简单地改变你的存储库类,如下所示:

abstract class CanineFinderClass<T extends Animal & Canine>
    implements Repository<T> {...}

作为旁注,DogFinder存储库是多余的,除非它提供特殊的狗方法,例如findAllPuppies(). 否则,制作AbstractFinderClass具体就足够了,因为类型是通用的(只是一个例子):

class AnimalFinderClass<T extends Animal> implements Repository<T> {

    Repository<T> repository;

    private Class<T> animalType;


    public AbstractFinderClass(Class<T> animalType) {
        this.animalType = animalType;
    }

    public Option<T> findMyAnimal(String id) {
        return repository.findById(id, this.animalType);
    }
}

推荐阅读