9

如果我有这个界面:

public interface Foo {
    void bar();
}

为什么我不能像这样实现它?

public class FooImpl implements Foo {
    @Override
    public Object bar() {
         return new Object();
    }
}

似乎 void 应该与一切都是协变的。我错过了什么吗?

编辑:我应该更清楚我正在寻找设计理由,而不是它无法编译的技术原因。使 void 对所有内容都协变会产生负面影响吗?

4

8 回答 8

13

void只是协变的,void因为JLS 这么说

当且仅当以下条件成立时,具有返回类型 R1 的方法声明 d1 可以返回类型替代具有返回类型 R2 的另一个方法 d2:

  • 如果 R1 是,void那么 R2 是void

  • 如果 R1 是原始类型,则 R2 与 R1 相同。

  • 如果 R1 是引用类型,则:

    • R1 是 R2 的子类型,或者 R1 可以通过未经检查的转换(第 5.1.9 节)转换为 R2 的子类型,或者

    • R1 = |R2|

于 2013-01-08T16:28:45.240 回答
5

协方差意味着如果您的方法return typeSupertype object可以sub-type Object在运行时返回的,则void不是super type of java.lang.Object(或任何对象,除了 MR NPE 回答的自身之外)

于 2013-01-08T16:26:53.560 回答
2

从技术上讲void,它不能是协变返回类型,因为调用者需要知道堆栈布局。调用返回对象的函数将导致在 INVOKEVIRTUAL/INTERFACE 之后堆栈顶部的对象引用。Void返回类型不会在堆栈顶部留下任何内容,因此这些函数是二进制不兼容的。

所以 JLS 正确地说这是不可能的。

于 2013-01-10T16:00:48.593 回答
1

void实际上意味着它什么也不返回。您可能会对void *C/C++ 中的 a 感到困惑。如果您将界面更改为

public interface Foo {
    Object bar();
}

它会正常工作,因为 Java 中的所有对象都继承Object.

所以,你可以这样做:

public class FooImpl implements Foo {

    @Override
    public Object bar() {
         return new SpecialObject();
    }

}

SpecialObject obj = (SpecialObject) new FooImpl().bar();
于 2013-01-08T16:26:17.553 回答
1

返回类型必须匹配被覆盖的方法。

Foo foo = new FooImpl();
foo.bar();

除非所有实现都符合接口并返回相同的对象(或什么都没有),否则我怎么知道会返回什么?

于 2013-01-08T16:27:36.197 回答
1

void不是java文件系统的一部分。

如果我们把它变成一个类型,它更像是一个空类型,所以它应该是所有其他类型的子类型,即它与其他类型是逆变的。

在您的示例中,超类规定不应返回任何内容,但子类会返回某些内容,因此子类违反了超类的合同。

Object与其他类型协变,如果这是你想要的。

于 2013-01-08T17:33:45.390 回答
0

协变返回类型通常意味着可以被更窄的类型替换。在中,和或其他任何事物Java之间没有这种关系(超类型-子类型) 。voidObject

于 2013-01-08T16:28:17.063 回答
0

如果允许这样做,将无法确定是否应该编译。

 Foo foo = ...
 Object o = foo.bar(); // is it void or an Object ?
于 2013-01-08T16:49:27.513 回答