我在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
验证程序中,传递给验证方法的对象必须可从ChildThingOne
分配。当你有一个 Validator<? extends ParentThing>
的实例时,编译器不知道validate
期望的实际类型。
更一般地说,编译器无法保证传递给validate
的ParentThing
实际上可分配为 ParentThing
的特定子类型。
由于这个原因,您实际上会发现代码validator.validate(new ChildThingOne())
具有相同的编译器错误。
这可以在一个基于您的简单示例中看到:
static class ParentThing {
}
static class ChildThingOne extends ParentThing{
}
interface Validator<T extends ParentThing> {
void validate(T item);
}
static class ValidatorImplOne implements Validator<ChildThingOne> {
@Override
public void validate(ChildThingOne thing1) {
// whatever
}
}
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>
的类。 正如您所指出的,另一种选择是使用类型转换。