接受类及其接口(interface)的 Java 类型(逆变)

标签 java inheritance types polymorphism

我有一个类和一个像这样的接口(interface):

interface Employee {...}

class Developer implements Employee {...}

然后我有一些类来实现入职流程中的步骤:

interface OnboardingStep<T extends Employee> {
  void perform(T newEmployee);
}

class GeneralOnboardingStep implements OnboardingStep<Employee> {
  GeneralOnboardingStep() {}

  @Override
  void perform(Employee newEmployee) {...}
}

class DeveloperOnboardingStep implements OnboardingStep<Developer> {
  DeveloperOnboardingStep() {}

  @Override
  void perform(Developer newDeveloper) {...}
}

完整的入职流程包括一般入职培训和针对开发人员的特定入职培训。

所以我想做的是:

abstract class OnboardingProcess<T extends Employee> {

  // This is where I need help, see below
  private final List<OnboardingStep<T>> onboardingSteps;

  protected OnboardingProcess(List<OnboardingStep<T>> onboardingSteps) {
    this.onboardingSteps = onboardingSteps;
  }

  public void perform(T newEmployee) {
    for (var onboardingStep: onboardingSteps) {
      onboardingStep.perform(newEmployee);
  }
}

class DeveloperOnboardingProcess extends OnboardingProcess<Developer> {

  DeveloperOnboardingProcess() {
    // This does not work
    super(List.of(
      new GeneralOnboardingStep(),
      new DeveloperOnboardingStep()
    ));
  }
}

这不起作用,因为 DeveloperOnboardingProcess 中的列表只能包含OnboardingStep<Developer>而不是OnboardingStep<Employee> .

但它应该可以工作,因为 Developer实现Employee 。 (“应该有效”我的意思是:“我希望它有效”)。

如何调整抽象类中的列表类型以接受界面的入门步骤?

最佳答案

您可能想要的是这个(但见下文):

private final List<OnboardingStep<? super T>> onboardingSteps;

protected OnboardingProcess(List<OnboardingStep<? super T>> onboardingSteps) {
    this.onboardingSteps = onboardingSteps;
}

? super T表示每个列表元素的 perform方法保证接受 T 实例,因为它将构造函数参数限制为类型为 T 或 T 的父类(super class)的步骤。因此,对于 DeveloperOnboardingProcess,构造函数可以采用 OnboardingStep<Developer> 的列表元素。或者一个 OnboardStep,其泛型类型是 Developer 的任何父类(super class),包括 Employee 本身。

但是,您不能做的一件事就是传递 List<DeveloperOnboardingStep>List<DeveloperOnboardingStep> 等于List<OnboardingStep<Developer>>List<OnboardingStep<Employee>> ,因为后者有 add (以及 addAll 等)方法,该方法允许 OnboardingStep、DeveloperOnboardingStep 或 OnboardingStep 的任何其他 future 子类,而 List<DeveloperOnboardingStep>有一个 add方法仅接受 DeveloperOnboardingStep 参数。

允许,比如说,List<DeveloperOnboardingStep>参数,使用这个:

private final List<? extends OnboardingStep<? super T>> onboardingSteps;

protected OnboardingProcess(List<? extends OnboardingStep<? super T>> onboardingSteps) {
    this.onboardingSteps = onboardingSteps;
}

关于接受类及其接口(interface)的 Java 类型(逆变),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77375515/

相关文章:

java - JPA:无法反序列化

c++ - 这段 C++ 代码的安全性和独立于编译器的程度如何?

haskell - typeOf 带有类型构造函数 *->*/从程序中打印值的类型

c++ - 类型定义问题

java - org.openqa.selenium.ElementNotVisibleException : Element is not currently visible and so may not be interacted with Command duration or timeout:

Java 故障转移框架/库

java - MaterialDialog 表单不起作用

c++ - C++ 中的模板和继承

entity-framework - EF6 中是否修复了 TPT 继承的性能问题?

c++ - 在 C++ 中是否有一种优雅的方式来表示包含不同类型的映射?