Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么void在Java中不是协变的?_Java_Polymorphism_Covariance - Fatal编程技术网

为什么void在Java中不是协变的?

为什么void在Java中不是协变的?,java,polymorphism,covariance,Java,Polymorphism,Covariance,如果我有这个界面: public interface Foo { void bar(); } 为什么我不能像这样实现它 public class FooImpl implements Foo { @Override public Object bar() { return new Object(); } } 似乎虚空与一切都是协变的。我错过什么了吗 编辑: 我应该更清楚,我在寻找设计的理由,而不是它无法编译的技术原因。使void对所有事物都协

如果我有这个界面:

public interface Foo {
    void bar();
}
为什么我不能像这样实现它

public class FooImpl implements Foo {
    @Override
    public Object bar() {
         return new Object();
    }
}
似乎虚空与一切都是协变的。我错过什么了吗

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

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

协方差意味着如果你的方法
返回类型
是一个
超类型对象
你可以在运行时返回
子类型对象
void不是java.lang.object的
超类型
(或者任何与此相关的对象,除了NPE先生回答的对象本身)返回类型必须与重写的方法匹配

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

除非所有实现都符合接口并返回相同的对象(或者根本不返回任何对象),否则我怎么知道它将返回什么?

协变返回类型通常指可以被更窄的类型替换的类型。在
Java
中,
void
Object
或其他任何东西之间没有这种关系(超类型子类型)。
void
只与
void
协变,因为:

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

  • 如果R1为
    void
    ,则R2为
    void

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

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

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

    • R1=| R2|


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

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

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

如果我们把它变成一个类型,它更像是一个空类型,所以它应该是其他类型的子类型,也就是说,它与其他类型相反

在您的示例中,超类规定不应返回任何内容,而子类返回某些内容,因此子类违反了超类的约定


对象
与其他类型是协变的,如果您需要的话。

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


因此,JLS正确地说这是不可能的。

JLS对此非常清楚,但也许有人可以提供一个技术原因,说明为什么它可以这样设计。我猜
void
可能是
对象的超类型,没有定义的方法。至少可以让这个例子起作用。我不知道它是否值得增加复杂性。@atamanroman,因为
void
明确表示没有任何意义;这是一份声明该方法没有返回值的合同。能够返回某些内容将违反该约定——这只是它的设计方式。@DaveNewton在Java类型系统的其余部分中,没有为返回设置上限的例子。你说的是一个反对协变回报类型的论点。“
Object
明确地表示Object;它是一个契约,声明该方法必须返回一个对象,仅此而已”。所以我的问题仍然是——有没有一个很好的理由不考虑<代码>空洞每个类型的超类型(至少为了返回协方差的目的)?@ MatthalaCE怎么说“空洞明确地意味着什么”,这是什么意思,除了那个以外的其他东西?!你说的不是JLS说的,我说的是。但是是的,有一个很好的理由允许定义一个显式不返回任何内容的方法。如果void是一个超类型,您如何指示一个方法永远不会返回某些内容?当然它不会编译,因为您是通过
Foo
访问它的。就像
newfooimpl(){publicstringbar(){returnsuper.bar();}}返回此.bar()
也不会编译。