我在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自动完成告诉我,validate应该采用ParentThing参数,但是如果我传递ParentThing,编译器仍会抱怨。 :(
如果我投射或删除泛型,这将有效,但我想知道如何做到这一点&#34;对&#34;没有编译器警告的方式。
答案 0 :(得分:1)
这实际上是您希望从编译器中获得的行为。
您提供的代码实际上并不是类型安全的,因此编译器需要您进行类型转换才有意义。
这是因为您的每个validate
方法实际上都采用ParentThing
的特定子类。例如,在ChildThingOne
验证程序中,传递给validate方法的对象必须可以从ChildThingOne
分配。当您拥有Validator<? extends ParentThing>
的实例时,编译器不知道实际类型validate
期望的是什么。
更一般地说,编译器无法保证传递给ParentThing
的{{1}}实际上可以作为validate
的特定子类型进行分配。
由于这个原因,您实际上会发现代码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
}
的类。正如您所指出的,另一个选择是使用typcast。