调用该方法:
public static @Nonnull <TV, TG extends TV> Maybe<TV> something(final @Nonnull TG value) {
return new Maybe<TV>(value);
}
像这样:
public @Nonnull Maybe<Foo> visit() {
return Maybe.something(new BarExtendsFoo());
}
在 Eclipse 中编译得很好,但 javac 给出了“不兼容的类型”警告:
found : BarExtendsFoo
必填:Foo
javac 和 Eclipse 之间显然存在一些差异。然而,这里的要点是 javac 发出错误是正确的。最终,您的代码将 Maybe
这是对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
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
}
我不明白为什么 javac 没有推断出正确的类型,
但您可以通过提供 中的类型来帮助
public @Nonnull Maybe<Foo> visit() {
return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo());
}
两条评论:
a.正如您在评论之一中提到的,something() 签名中的 TG 类型参数根本没有必要,因为您在方法中执行的子类 TG 没有任何特定内容。
b.最简单的解决方案是通过将新创建的对象显式分配给变量来帮助编译器了解您正在使用哪种类型(无论如何,这通常是很好的做法)。现在,编译器和人类读者都更清楚如何调用该方法:
public @Nonnull Maybe<Foo> visit() {
final Foo bar = new BarExtendsFoo();
return Maybe.something(bar);
}