接口中的协变返回类型未通过 Javac 编译

发布于 2024-11-29 15:03:23 字数 1121 浏览 0 评论 0原文

我有以下结构:

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

I have the following structure:

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 fails with the following message:

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

However, Eclipse can compile it fine, and as far as I can see it should compile - FooBar's fooBar() method satisfies the contract of both Foo and Bar's fooBar() method by using covariant returns.

Is this a bug in the Eclipse compile or in javac? Or is there a way to persuade javac to compile it? For reference my javac options look like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

り繁华旳梦境 2024-12-06 15:03:24

JLS (§9.4.1) 说:

一个接口可以继承多个方法
覆盖等效签名(第 8.4.2 节)。这样的情况并不在
本身会导致编译时错误。该接口被认为是
继承所有方法。然而,继承的方法之一必须
返回类型必须可替代任何其他继承的方法;
否则,会发生编译时错误(抛出子句不会
在这种情况下会导致错误。)

所以我想说 javac 是正确的。但这对我来说看起来像是律师行话,所以我可能是错的。

The JLS (§9.4.1) says :

It is possible for an interface to inherit several methods with
override-equivalent signatures (§8.4.2). Such a situation does not in
itself cause a compile-time error. The interface is considered to
inherit all the methods. However, one of the inherited methods must
must be return type substitutable for any other inherited method;
otherwise, a compile-time error occurs (The throws clauses do not
cause errors in this case.)

So I would say that javac is right. But this looks like lawyer jargon to me, so I could be wrong.

不顾 2024-12-06 15:03:24

这个 javaranch 讨论 中的答案似乎是表明这是一个 javac bug。但是,引用的 bug url 似乎不起作用。

An answer in this javaranch discussion seems to suggest that it's a javac bug. However, the referenced bug url doesn't seem to work.

浮光之海 2024-12-06 15:03:24

我也遇到了同样的问题,使用 Oracle 的 JDK 7 似乎没问题。

I had the same problem and it seems to be fine by using the JDK 7 from Oracle.

屌丝范 2024-12-06 15:03:24

作为一种解决方法,你可以做得

interface Foo1 extends Foo {
  FooBarReturn fooBar();
}
interface Bar1 extends Bar {
  FooBarReturn fooBar();
}
public interface FooBar extends Foo1, Bar1 { }

不漂亮,但应该能达到目的。

As a workaround, you could do

interface Foo1 extends Foo {
  FooBarReturn fooBar();
}
interface Bar1 extends Bar {
  FooBarReturn fooBar();
}
public interface FooBar extends Foo1, Bar1 { }

Not pretty but should do the trick.

吹梦到西洲 2024-12-06 15:03:23

您正在 FooBar 界面中扩展 Foo 和 Bar。因此,您继承了两个返回类型不兼容的方法。 Java 协方差仅在遵循 Liskov 替换时才被允许。也就是说,重写的候选类型几乎必须是重写的返回类型的子类。

在上面的示例中,类似这样的内容应该编译:

public interface BarReturn {}
public interface FooReturn {}
public interface FooBarReturn extends FooReturn, BarReturn {}

public interface Foo {  
  FooReturn fooBar( );
}

public interface FooBar extends Foo{
  FooBarReturn fooBar();
}

You are extending both Foo and Bar in your FooBar interface. As such you are inheriting two methods with incompatible return types. Java co-variance is only allowed when it follows Liskov substitution. Aka, the overriding candidate types must pretty much be a subclass of the overridden return type.

In your example above something like this should compile:

public interface BarReturn {}
public interface FooReturn {}
public interface FooBarReturn extends FooReturn, BarReturn {}

public interface Foo {  
  FooReturn fooBar( );
}

public interface FooBar extends Foo{
  FooBarReturn fooBar();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文