当前位置: 首页 > 知识库问答 >
问题:

为泛型的实现类的变量提供扩展功能到子类

朱宇航
2023-03-14

我不熟悉泛型,并且深入研究了一些基本上超出我知识范围的东西,所以请耐心听我说。也许我问的问题很傻,但我似乎无法找到一个明确的答案来说明我希望做的事情是否可行,也许是因为我不知道要寻找的正确术语。

我有两个Java类,它们由一个T类型的实体参数化——一个存储库和一个服务。由于我的所有存储库和所有服务都将执行一些相同的基本任务,因此我的通用repo和服务已经实现了上述任务,并通过受保护的功能将它们提供给任何扩展它们的东西。到目前为止,一切都很顺利。目前它们看起来像这样:

存储库类:

public interface GenericRepo<T> {
    protected T findObject();
}

服务等级:

public class GenericService<T> {
    private GenericRepo<T> repo;

    public GenericService(GenericRepo<T> repo) {
        this.repo = repo;
    }

    protected T findObject() {
        return this.repo.findObject();
    }
}

当我希望扩展我的服务并允许人们使用存储库的子类时,问题就来了。虽然许多实体是基本的,并且功能包含在泛型函数中,但有时需要特殊情况才能在实体上执行附加功能。在设置中,存储库被实现/扩展,然后扩展类被传递给服务(它接受它,因为它是GenericRepo的一种类型

public class ExtendedRepo implements GenericRepo<Entity> {
   protected Entity findObjectByWeirdKeyOnEntity(String weirdKey) {
       //awesome code that does stuff here
   }
}

我还将该服务声明为通用服务,因为该服务上也有很多定制功能的可能性。因此,GenericService的扩展如下:

public class ExtendedService extends GenericService<Entity> {
    public ExtendedService(ExtendedRepo repo) {
        super(repo);
    }

    public Entity findObjectByWeirdKeyOnEntity() {
        // Do stuff to generate weird key to search by
        return this.repo.findObjectByWeirdKeyOnEntity(weirdKey);
    }
}

这允许我在服务上执行自定义函数,但也可以利用通用服务上的所有基本函数,而无需复制代码。但是,因为GenericService中的变量repo被声明为类型GenericRepo

public class ExtendedService extends GenericService<Entity> {
    private ExtendedRepo extendedRepo;

    public ExtendedService(ExtendedRepo repo) {
        super(repo);
        this.extendedRepo = repo;
    }

    public Entity findObjectByWeirdKey() {
        return this.extendedRepo.findObjectByWeirdKeyOnEntity(weirdKey);
    }
}

在扩展服务中为存储库重新声明和保留一个单独的变量似乎是错误的,因为我本质上保留了同一个类的两个实例,以便我可以在扩展类中使用一个自定义函数,同时也使用超级类的所有常见功能。有没有办法在GenericService上创建变量GenericRepo,使其具有扩展GenericRepo的任何类型,这将允许扩展GenericService的类在GenericRepo类的扩展版本上使用自定义方法?


共有2个答案

逑景铄
2023-03-14

GenericService具有类型为GenericReporepo。您在ExtendedService的构造函数中所做的操作将仅在运行时可见,即repo实例的运行时类型将为ExtendedService(前提是它仅在ExtendedService对象中)
但是在编译时,repo属于GenericRepo类型,GenericRepo没有findObjectByWeirdKeyOnEntity方法
因此,如果要在ExtendedService类中使用它,必须显式地将其大小写为ExtendedService。所以只需这样做:返回((ExtendedRepo)这个。回购协议)。FindObjectByWeirdKeyOnenity(古怪钥匙);

或者

使用@Banannon的解决方案。这也是一个很好的例子。

冯开诚
2023-03-14

您可以向GenericService添加一个类型参数,它将表示GenericRepo的类型:

public class GenericService<R extends GenericRepo<T>, T> {
    protected R repo;

    public GenericService(R repo) {
        this.repo = repo;
    }

    protected T findObject() {
        return this.repo.findObject();
    }
}

public class ExtendedService extends GenericService<ExtendedRepo, Entity> {
    public ExtendedService(ExtendedRepo repo) {
        super(repo);
    }

    public Entity findObjectByWeirdKeyOnEntity(String weirdKey) {
        return this.repo.findObjectByWeirdKeyOnEntity(weirdKey);
    }
}

注意:在上一个示例中,您保留了对同一实例的两个引用,但不是对同一类的两个实例。

 类似资料:
  • 问题内容: 我正在尝试重构M类型确实扩展了任何内容的类和子类集,即使我们知道它必须是某种类型的子类也是如此。该类型已参数化,我希望其参数化类型可用于已经具有M值的子类。 有什么方法可以定义此类,而不必在参数列表中包括冗余的K和V泛型类型。我希望能够使编译器从子类映射到的M中推断出它们。 换句话说,我希望类声明看起来像这样: 从M的定义可以推断出K和V的类型。 问题答案: 问题在于,它们并没有真正地

  • 问题内容: 为了减少类的依赖性,我想将参数(使用泛型类)发送到扩展某些类并实现接口的构造函数,例如 可能吗? 此外,使用T类,我想使用T.getActivity()作为Context创建视图。 问题答案: T必须扩展Fragment并实现SomeInterface 在这种情况下,您可以声明以下内容: 这将需要扩展和实现类型的对象。 此外,使用T类,我想使用T.getActivity()作为Cont

  • 问题内容: 我不明白为什么要编译。我以为它检查了但没有检查? 问题答案: 泛型中的关键字在语义上与常规关键字略有不同。 当使用在泛型的上下文中,例如,这意味着,应该是一个类型的 任一 实现的接口(在情况下,当是接口), 或者 是子类(如果是一个类)。 可能的原因是,如果Generics中支持该关键字,则会使类型参数声明过于冗长。 例如,您将拥有: 相反,此方法的有效语法为: 实际上,您不需要关键字

  • 问题内容: 这是我一直试图找到解决方案的问题。 我们有两个类定义。两个之一扩展另一个。 要求是应该有一个列表来保持对象扩展T 但是,当我尝试将TT对象(似乎不是T的子类)放入列表时,就会出现问题。 编译错误信息 类型List中的方法add(capture#2-of?extended Cell)不适用于参数(Cell) 问题答案: 您可以直接创建一个,这可以允许T的所有子类型进入列表。这实际上很难理

  • 有人能告诉我第一个和第二个代码之间的区别吗?MaxPQ代表优先级队列,它是可以相互比较的“键”对象的集合。 代码1: 代码2: 第二个代码没有编译,但我不明白为什么在使用泛型时需要扩展而不是实现接口。

  • 问题内容: 是否可以为特殊/构造的泛型类型扩展泛型类?我想使用一种方法来扩展Int Arrays,以计算其元素的总和。 例如 问题答案: Swift 5.x: