我身处 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,编译器仍然会抱怨。 :(
如果我强制转换或删除泛型,这将起作用,但我想知道如何在没有编译器警告的情况下以“正确”的方式执行此操作。
这实际上是您希望编译器实现的行为。
您给出的代码不是类型安全的,因此编译器要求您进行类型转换是有道理的。
这是因为每个
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);
}