[英]Java Generics: Who is right, javac or Eclipse compile?
调用此方法:
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 <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编译器在分配行上发出错误。 这是一段利用这种风险将整数存储在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
}
我不明白为什么javac没有推断出正确的类型,
但是您可以通过提供如下所示的类型来帮助编译器
public @Nonnull Maybe<Foo> visit() {
return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo());
}
两条评论:
一种。 正如您在评论中提到的那样,根本没有必要在something()签名中使用TG类型参数,因为在该方法中对子类TG没有特定的定义。
湾 最简单的解决方案是通过将新创建的对象显式分配给变量来帮助编译器了解您正在使用的类型(无论如何通常都是很好的做法)。 现在,对于编译器和普通读者来说,您如何调用该方法都更加清楚:
public @Nonnull Maybe<Foo> visit() {
final Foo bar = new BarExtendsFoo();
return Maybe.something(bar);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.