在java中调用使用泛型的多态方法

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

我身处 Java 泛型地狱!正确的做法是什么:

interface Validator<T extends ParentThing> {
  void validate(T item);
}

class ValidatorImplOne implements Validator<ChildThingOne> {
  @Override
  public void validate(ChildThingOne thing1) {
    // whatever
  }
}

class ValidatorImplTwo implements Validator<ChildThingTwo> {
  @Override
  public void validate(ChildThingTwo thing2) {
    // whatever
  }
}

// Initialize this with string to ValidatorImplOne or ValidatorImplTwo instances
Map<String, Validator<? extends ParentThing>> VALIDATORS = ... 

public static void validate(String s, ParentThing thing) {
  Validator<? extends ParentThing> validator = VALIDATORS.get(s);

  // Does not compile! Complains that thing is not the right type.
  validator.validate(thing);
}

即使 Eclipse 自动完成功能也告诉我验证应该采用 ParentThing 参数,但如果我传递 ParentThing,编译器仍然会抱怨。 :(

如果我强制转换或删除泛型,这将起作用,但我想知道如何在没有编译器警告的情况下以“正确”的方式执行此操作。

java generics polymorphism
1个回答
1
投票

这实际上是您希望编译器实现的行为。

您给出的代码不是类型安全的,因此编译器要求您进行类型转换是有道理的。

这是因为每个

validate
方法都采用
ParentThing
的特定子类。例如,在
ChildThingOne
验证器中,传递到 validate 方法的对象必须可从
ChildThingOne
进行分配。当您有
Validator<? extends ParentThing>
的实例时,编译器不知道
validate
的实际类型需要什么。

更一般地,编译器无法保证传递给

ParentThing
validate
可分配为
ParentThing
的特定子类型。

你会发现代码

validator.validate(new ChildThingOne())
有同样的编译错误。

这可以在基于您的简单示例中看到:

public static void validate(String s, ParentThing thing) {
    Validator<? extends ParentThing> validator = new ValidatorImplOne(); //? extends ParentThing means an unknown, but SPECIFIC, implementation of ParentThing
    
    validator.validate(new ChildThingOne()); //cannot compile
    //The compiler doesn't know if ChildThingOne is the actual type validator wants
}

要使用泛型执行此操作,您必须使用扩展

Validator<ParentThing>
的类。正如您所指出的,另一种选择是使用类型转换。

以下是如何修改初始代码以进行编译和工作的示例:

public static <T extends ParentThing> void validate(String s, T thing) {
    Validator<T> validator = (Validator<T>) VALIDATORS.get(s);
    
    validator.validate(thing);
}
© www.soinside.com 2019 - 2024. All rights reserved.