【发布时间】:2011-07-18 16:55:24
【问题描述】:
我在这里遇到了一个非常棘手的泛型和方法重载案例。查看这个示例类:
public class Test {
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public void test() {
// This works perfectly. <T> is bound to String
// ambiguity between setValue(.., String) and setValue(.., Field)
// is impossible as String and Field are incompatible
Parameter<String> p1 = getP1();
Field<String> f1 = getF1();
setValue(p1, f1);
// This causes issues. <T> is bound to Object
// ambiguity between setValue(.., Object) and setValue(.., Field)
// is possible as Object and Field are compatible
Parameter<Object> p2 = getP2();
Field<Object> f2 = getF2();
setValue(p2, f2);
}
private Parameter<String> getP1() {...}
private Parameter<Object> getP2() {...}
private Field<String> getF1() {...}
private Field<Object> getF2() {...}
}
上面的示例在 Eclipse (Java 1.6) 中完美编译,但不能使用 Ant javac 命令(或使用 JDK 的 javac 命令),我在第二次调用 setValue 时收到这种错误消息:
对 setValue 的引用不明确, 两种方法 setValue(org.jooq.Parameter,T) 在测试和方法 setValue(org.jooq.Parameter,org.jooq.Field) 在测试比赛中
根据规范和我对 Java 编译器工作原理的理解,应始终选择最具体的方法:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448
在任何情况下,即使<T> 绑定到Object,这使得setValue 方法都可以接受调用,但带有Field 参数的方法似乎总是更具体。它可以在 Eclipse 中工作,只是不适用于 JDK 的编译器。
更新:
像这样,它可以在 Eclipse 和 JDK 编译器中工作(当然,带有 rawtypes 警告)。我知道,当涉及泛型时,the specs 中指定的规则非常特殊。但我觉得这很令人困惑:
public <T> void setValue(Parameter<T> parameter, Object value) {
}
// Here, it's easy to see that this method is more specific
public <T> void setValue(Parameter<T> parameter, Field value) {
}
更新 2:
即使使用泛型,我也可以创建这个解决方法,通过添加一个名为 setValue0 的附加明确间接寻址,避免在 setValue 调用时将类型 <T> 绑定到 Object。这让我觉得 T 到 Object 的绑定确实是造成所有麻烦的原因:
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public <T> void setValue0(Parameter<T> parameter, Field<T> value) {
// This call wasn't ambiguous in Java 7
// It is now ambiguous in Java 8!
setValue(parameter, value);
}
public void test() {
Parameter<Object> p2 = p2();
Field<Object> f2 = f2();
setValue0(p2, f2);
}
我在这里误解了什么吗?是否存在与此相关的已知编译器错误?或者是否有解决方法/编译器设置可以帮助我?
跟进:
对于那些感兴趣的人,我已经向 Oracle 和 Eclipse 提交了错误报告。 Oracle 已经接受了这个 bug,到目前为止,Eclipse 已经分析并拒绝了它!看来我的直觉是对的,这是javac中的一个错误
【问题讨论】:
-
我认为,ant 指向的是不同的编译器,它不是候选版本。
-
@John:ant 使用 JDK 的
javac编译器。 Eclipse 可能有它自己的...
标签: java eclipse generics javac overloading