为什么Java中的void不协变?

时间:2013-01-08 16:25:03

标签: java polymorphism covariance

如果我有这个界面:

public interface Foo {
    void bar();
}

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

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

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

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

8 个答案:

答案 0 :(得分:13)

void仅与void协变,因为the JLS says so

  

返回类型为R1的方法声明d1   return-type-substitutable为另一个返回类型为R2的方法d2,   当且仅当满足以下条件时:

     
      
  • 如果R1为void,则R2为void

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

  •   
  • 如果R1是参考类型,则:

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

    •   
    • R1 = | R2 |

    •   
  •   

答案 1 :(得分:3)

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

答案 2 :(得分:1)

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

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();

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:1)

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

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

在你的例子中,超类规定不应返回任何内容,但子类返回一些东西,因此子类违反了超类的契约。

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

答案 5 :(得分:1)

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

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

答案 6 :(得分:0)

协变返回类型通常表示可以用较窄类型替换的类型。在Java中,voidObject或其他任何内容之间没有此类关系(超类型 - 子类型)。

答案 7 :(得分:0)

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

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