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

问题描述 投票:0回答:1

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

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
。 (“应该有效”我的意思是:“我希望它有效”)。

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

java inheritance types polymorphism
1个回答
0
投票

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

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

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

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

但是,您不能做的一件事就是通过

List<DeveloperOnboardingStep>
List<DeveloperOnboardingStep>
not 相当于
List<OnboardingStep<Developer>>
List<OnboardingStep<Employee>>
,因为后者有一个
add
(和 addAll 等)方法,该方法允许 OnboardingStep、DeveloperOnboardinStep 或 OnboardingStep 的任何其他未来子类,而
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;
}
© www.soinside.com 2019 - 2024. All rights reserved.