javac 和 Eclipse 之间显然存在一些差异。但是,这里的要点是 javac 在发出错误时是正确的。最终,您的代码会将 Maybe<BarExtendsFoo> 转换为可能有风险的 Maybe<Foo>。
这是 visit() 方法的重写:
public static <TV, TG extends TV> Maybe<TV> something(final TG value) {
return new Maybe<TV>(value);
}
public static class Foo { }
public static class BarExtendsFoo extends Foo { }
public Maybe<Foo> visit() {
Maybe<BarExtendsFoo> maybeBar = something(new BarExtendsFoo());
Maybe<Foo> maybeFoo = maybeBar; // <-- Compiler error here
return maybeFoo;
}
这种重写实际上与您的代码相同,但它明确显示了您尝试从 Maybe<BarExtendsFoo> 到 Maybe<Foo> 进行的分配。这是有风险的。事实上,我的 Eclipse 编译器在赋值行上发出错误。下面是利用这种风险将 Integer 存储在 Maybe<String> 对象中的一段代码:
public static void bomb() {
Maybe<String> maybeString = new Maybe<String>("");
// Use casts to make the compiler OK the assignment
Maybe<Object> maybeObject = (Maybe<Object>) ((Object) maybeString);
maybeObject.set(new Integer(5));
String s = maybeString.get(); // Runtime error (classCastException):
// java.lang.Integer incompatible with
// java.lang.String
}