以下示例虽然看似正确,但无法编译(Eclipse Neon 3,Java 1.8):
class Test {
public static class SomeForm<IF extends SomeForm<IF>> {
}
public static class BaseFF<IF extends SomeForm<IF>> {
}
public static class AuxFF<IF extends SomeForm<IF>>
extends BaseFF<IF> {
}
public interface Interface<IF extends SomeForm<IF>, FF extends BaseFF<IF>> {
FF getFF1();
}
public static class ZBaseUnit<IF extends SomeForm<IF>, FF extends BaseFF<IF>>
implements Interface<IF, FF> {
@Override
public FF getFF1() {
return null;
}
}
public static class ZMyUnit<IF extends SomeForm<IF>, FF extends AuxFF<IF>>
extends ZBaseUnit<IF, FF> {
}
public static class ZMyCheck<IF extends SomeForm<IF>, U extends ZMyUnit<IF, ?>> {
U unit;
void f() {
BaseFF<IF> ff1 = unit.getFF1();
}
}
}
Eclipse说(在f()方法内的行上):
“类型不匹配:无法从?的Capture#2转换为Test.BaseFF”。
但是,如果我从接口Interface(以及类ZBaseUnit中的@Override批注)中删除方法getFF1,它将进行编译。这背后有逻辑吗?从直觉上看,传递给Interface的FF与传递给ZBaseUnit的FF相同,因此应该没有区别...
此外,如果我在ZMyUnit中添加方法,也不会出错:
void f() {
BaseFF<IF> ff1 = getFF1();
}
任何帮助将不胜感激!
答案 0 :(得分:2)
如果您将此验证码添加到您的课程中
public static class GF extends SomeForm<GF> {
}
public static void main(String[] args) {
ZMyCheck<GF, ZMyUnit<GF, AuxFF<GF>>> z = new ZMyCheck<>();
z.unit = new ZMyUnit<>();
z.f();
System.out.println("OK");
}
并使用标准的JDK命令行工具(javac
和java
),则代码将编译并成功运行。如果您使用NetBeans,也是如此(我无意以任何方式升级NetBeans)。
因此,问题是特定于Eclipse的。 Eclipse有自己的内置编译器,您似乎已经发现了它的弱点之一(也许您需要提交错误报告)。实际上,无法确定通配符?
是指扩展AuxFF<IF>
的类型(因此也就是BaseFF<IF>
)。您需要明确指出:
public static class ZMyCheck<IF extends SomeForm<IF>,
U extends ZMyUnit<IF, ? extends AuxFF<IF>>> {...}
然后所有程序都将进行编译和运行。
答案 1 :(得分:1)
关于类ZMyCheck
和...中的变量初始化...
public static class ZMyCheck<IF extends SomeForm<IF>, U extends ZMyUnit<IF, ?>> { U unit; void f() { BaseFF<IF> ff1 = unit.getFF1(); } }
...正确性最终取决于表达式unit.getFF1()
的类型,以及该类型是否为BaseFF<IF>
的子类型。该表达式的类型是实例变量unit
类型的函数,由于类型擦除,该变量被解释为类型变量U
的上限,即{{1 }}。
关于ZMyUnit<IF, ?>
的类型,则JLS指定
[类型]的字段,方法和构造函数的类型是[该类型]的捕获转换中的字段,方法和构造函数的类型。
因此,我们需要确定section 5.1.10中指定的unit.getFF1()
类型的捕获转换。规范在这里变得相当技术性,但是最重要的是,ZMyUnit<IF, ?>
的第二种类型参数的上限已计入,因此存在对类型ZMyUnit
的捕获转换。根据该类型的解释,方法ZMyUnit<IF, AuxFF<IF>>
返回类型getFF1()
,这需要经过扩展引用转换为类型AuxFF<IF>
,这是需要的。
因此,正如@JohnMcClane也回答的那样,Eclipse的编译器在拒绝显示的代码方面是不正确的。在通配符上添加适当的上限似乎可以解决此问题,而无需更改有关JLS的代码语义。