接口中的协变返回类型不通过Javac进行编译
我有以下结构:
public interface BarReturn {} public interface FooReturn {} public interface FooBarReturn extends FooReturn, BarReturn {} public interface Foo { FooReturn fooBar( ); } public interface Bar { BarReturn fooBar(); } public interface FooBar extends Foo, Bar { FooBarReturn fooBar(); }
Javac失败并显示以下消息:
FooBar.java:2: types Bar and Foo are incompatible; both define fooBar(), but with unrelated return types public interface FooBar extends Foo, Bar { ^ 1 error
但是,Eclipse可以编译得很好,据我所知它应该编译–FooBar的fooBar()方法通过使用协变返回来满足Foo和Bar的fooBar()方法的约定。
这是Eclipse编译或javac中的错误吗? 或者有没有办法说服javac编译它? 作为参考,我的javac选项如下所示:
javac -d /tmp/covariant/target/classes -sourcepath /tmp/covariant/src/main/java: /tmp/covariant/src/main/java/Foo.java /tmp/covariant/src/main/java/BarReturn.java /tmp/covariant/src/main/java/FooBarReturn.java /tmp/covariant/src/main/java/Bar.java /tmp/covariant/src/main/java/FooReturn.java /tmp/covariant/src/main/java/FooBar.java -g -nowarn -target 1.6 -source 1.6
您正在FooBar界面中扩展Foo和Bar。 因此,您inheritance了两种具有不兼容返回类型的方法。 只有当它跟随Liskov替换时才允许Java协方差。 Aka,重写的候选类型必须几乎是重写的返回类型的子类。
在上面的例子中,这样的东西应该编译:
public interface BarReturn {} public interface FooReturn {} public interface FooBarReturn extends FooReturn, BarReturn {} public interface Foo { FooReturn fooBar( ); } public interface FooBar extends Foo{ FooBarReturn fooBar(); }
JLS(§9.4.1)说:
接口可以使用覆盖等效签名(第8.4.2节)inheritance多个方法。 这种情况本身并不会导致编译时错误。 该接口被认为是inheritance所有方法。 但是,其中一个inheritance的方法必须是可替换任何其他inheritance方法的返回类型; 否则,发生编译时错误(在这种情况下throws子句不会导致错误。)
所以我会说javac是对的。 但这对我来说就像是律师行话,所以我可能错了。
这个javaranch讨论中的答案似乎表明它是一个javac错误。 但是,引用的bug url似乎不起作用。
我遇到了同样的问题,使用Oracle的JDK 7似乎没问题。
作为一种解决方法,你可以做到
interface Foo1 extends Foo { FooBarReturn fooBar(); } interface Bar1 extends Bar { FooBarReturn fooBar(); } public interface FooBar extends Foo1, Bar1 { }
不漂亮,但应该做的伎俩。
这是Sun的Java 6编译器中的一个错误 。