为什么Java中的void不协变?

如果我有这个界面:

public interface Foo { void bar(); } 

为什么我不能这样实现呢?

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

似乎无效应该与一切协变。 我错过了什么吗?

编辑:我应该更清楚我正在寻找设计理由,而不是它不会编译的技术原因。 对所有事物进行空洞协变是否会产生负面影响?

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

所以JLS理所当然地说这是不可能的。

void只与void协变,因为JLS这样说 :

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

  • 如果R1 void则R2 void

  • 如果R1是基本类型,则R2与R1相同。

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

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

    • R1 = | R2 |

协方差意味着如果你的方法return type是一个Supertype object你可以在运行时返回sub-type Objectvoid不是super type of java.lang.Objectsuper type of java.lang.Object (或者除了它之外的任何对象,如MR NPE所回答)

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

 public interface Foo { Object bar(); } 

它会正常工作,因为Java中的所有对象都inheritance了Object

所以,你可以这样做:

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

返回类型必须与重写方法匹配。

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

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

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

如果我们确实使它成为一个类型,它更像是一个空类型,因此它应该是所有其他类型的子类型,即它与其他类型相反。

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

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

协变返回类型通常意味着可以用较窄类型替换的类型。 在JavavoidObject之间没有这种关系(supertype-subtype)或其他任何东西。

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

  Foo foo = ... Object o = foo.bar(); // is it void or an Object ?