具有泛型和协变返回的 Java 并行继承层次结构

标签 java generics inheritance

假设我有这两个继承层次结构:

class EntityA { ... }
class EntityB extends EntityA { ... }

class EntityAPrime extends AbstractPrime<EntityA> { ... }
class EntityBPrime extends EntityAPrime { ... }

我还想要协变返回类型:

public class EntityA {
  public EntityAPrime prime() {
    return new EntityAPrime();
  }
}

public class EntityB extends EntityA {
  @Override
  public EntityBPrime prime() {
    return new EntityBPrime();
  }
}

到目前为止一切顺利。

问题是我想要EntityBPrime最终延长AbstractPrime<EntityB>但由于它扩展了 EntityAPrime它最终延伸AbstractPrime<EntityA> .

我可以做EntityAPrimeEntityBPrime通用,但随后我失去了协变返回类型:

public class EntityA {
  public EntityAPrime<EntityA> prime() {
    return new EntityAPrime();
  }
}

public class EntityB extends EntityA {
  @Override
  public EntityBPrime<B> prime() {  // ERROR: EntityBPrime extends EntityAPrime
    return new EntityBPrime();      // but can't substitute <EntityB> for <EntityA>
  }
}

如果我返回绑定(bind)通配符,一切正常,但有 disadvantages与此相关,我将无法在 AbstractPrime 上调用特定的 setter .

我的另一个想法是制作 EntityAEntityB它们本身是通用的。

public class EntityA<T extends EntityA> {
  public EntityAPrime<T> prime() { ... }
}

public class EntityB<T extends EntityB> extends EntityA<T> {
    @Override
    public EntityBPrime<T> prime() { ... }
}

这应该可行,但我认为它会变得困惑(我们有超过 100 个实体会使用类似的模式)。

那么,有什么办法:

  • 保持协变返回
  • 不在 EntityA 上使用泛型和EntityB
  • 没有prime()返回绑定(bind)的通配符
  • 并且有EntityBPrime最终延长AbstractPrime<EntityB>而不是AbstractPrime<EntityA>

注意:主要类是生成的代码,但我可以控制生成的代码。

最佳答案

首先,你的接口(interface)和类都被称为A,这有点令人困惑。和B 。因此,我将这些类重命名为 AImplBImpl分别。另外,你的类(class)APrimeBPrime没有输入(它们需要输入),所以我假设它们是在 <T extends A> 上输入的和<T extends B>分别(如果我误解了您的意图/目标/要求,我深表歉意)。

private interface A {}
private interface B extends A {}
private abstract class AbstractPrime<T extends A>{}
private class APrime<T extends A> extends AbstractPrime<T>{}
private class BPrime<T extends B> extends APrime<T>{}
private class AImpl {...}
private class BImpl {...}

正如您所考虑的那样,我的第一直觉是在接口(interface)上键入实现。这会起作用:

private class AImpl<T extends A> {
  public APrime<T> prime(){
    return new APrime<>();
  }
}

private class BImpl<T extends B> extends AImpl<T> {
  public BPrime<T> prime(){
    return new BPrime<>();
  }
}

但是,如果您输入 APrime<T extends A>BPrime<T extends B> ,是否需要prime()的返回类型要打字吗?以下解决方案可能适合您吗?

class APrime<T extends A> extends AbstractPrime<T>{}
class BPrime<T extends B> extends APrime<T>{}

public class AImpl {
  public APrime prime(){
    return new APrime<>();
  }
}

public class BImpl extends AImpl {
  public BPrime prime(){
    return new BPrime<>();
  }
}

我想这个问题的答案在某种程度上取决于您是否设想需要以下内容:

private interface C extends B {}

public void main(String[] args) {
  BPrime<C> prime = new BImpl<C>().prime(); // do you need this?
  BPrime<B> prime = new BImpl<>().prime(); // do you need this?


  BPrime prime = new BImpl().prime(); or is this sufficient...?
}

关于具有泛型和协变返回的 Java 并行继承层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18472837/

相关文章:

java - Azure 连接无法连接证书错误

c# - 将通用列表转换为 CSV 字符串

java - 如何使用通配符在 Java 中复制通用集合

C# 泛型方法拒绝类型,即使它实现了所需的接口(interface)

'DTYPE' 中的 java、MySQL 和未知列 'field list'

java - 设计问题: to what extent should I rely on exceptions for the flow of control?

java - 如何将具有不同值的相同对象生成到 ArrayList 中?

java - 无法从类 io.netty.channel.sctp.nio.NioSctpChannel 创建 channel

c++ - C++中的函数签名和继承

java - List的逐次继承