简体   繁体   English

为什么Java中的void不协变?

[英]Why is void not covariant in Java?

If I have this interface: 如果我有这个界面:

public interface Foo {
    void bar();
}

Why can't I implement it like this? 为什么我不能像这样实现呢?

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

It seems like void should be covariant with everything. 似乎无效应该与一切协变。 Am I missing something? 我错过了什么吗?

Edit: I should have been clearer that I'm looking for the design justification, not the technical reason that it won't compile. 编辑:我应该更清楚我正在寻找设计理由,而不是它不会编译的技术原因。 Are there negative consequences to making void covariant to everything? 对所有事物进行空洞协变是否会产生负面影响?

void is only covariant with void because the JLS says so : void只与void协变,因为JLS这样说

A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold: 返回类型为R1的方法声明d1是返回类型 - 可替代另一个返回类型为R2的方法d2,当且仅当以下条件成立时:

  • If R1 is void then R2 is void . 如果R1 void则R2 void

  • If R1 is a primitive type, then R2 is identical to R1. 如果R1是基本类型,则R2与R1相同。

  • If R1 is a reference type then: 如果R1是引用类型,则:

    • R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or R1是R2的子类型,或者R1可以通过未经检查的转换(第5.1.9节)转换为R2的子类型,或者

    • R1 = |R2| R1 = | R2 |

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

void effectively means that it returns nothing. void有效意味着它什么都不返回。 You may be getting confused with a void * in C/C++. 您可能会对C / C ++中的void *感到困惑。 If you change the interface to be 如果您将界面更改为

public interface Foo {
    Object bar();
}

it will work fine because all objects in Java inherit Object . 它会正常工作,因为Java中的所有对象都继承了Object

So, you could do something like this: 所以,你可以这样做:

public class FooImpl implements Foo {

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

}

SpecialObject obj = (SpecialObject) new FooImpl().bar();

Return types must match for overridden methods. 返回类型必须与重写方法匹配。

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

Unless all implementations comply with the interface and return the same object (or nothing at all) how do I know what that will return? 除非所有实现都符合接口并返回相同的对象(或根本没有),我怎么知道它会返回什么?

void is not part of the java file system. void不是java文件系统的一部分。

If we do make it a type, it's more like an empty type, so it should be a subtype of every other type, ie it is contra-variant with other types. 如果我们确实使它成为一个类型,它更像是一个空类型,因此它应该是所有其他类型的子类型,即它与其他类型相反。

In your example, the super class dictates that nothing should be returned, yet the subclass returns something, therefore the subclass violates the superclass's contract. 在您的示例中,超类规定不应返回任何内容,但子类返回一些内容,因此子类违反了超类的合同。

Object is covariant with other types, if that's what you want. Object与其他类型协变,如果这是你想要的。

Technically void cannot be a covariant return type as the caller needs to know the stack layout. 技术上void不能是协变返回类型,因为调用者需要知道堆栈布局。 Calling a function that returns an object would result of an object-ref on the top of the stack after the INVOKEVIRTUAL/INTERFACE. 在INVOKEVIRTUAL / INTERFACE之后调用返回对象的函数将导致堆栈顶部的对象引用。 Void return type leaves nothing on the top of the stack, hence the functions are binary incompatible. Void返回类型不会在堆栈顶部留下任何内容,因此函数是二进制不兼容的。

So the JLS rightfully says it's not possible. 所以JLS理所当然地说这是不可能的。

A covariant return type usually means the one that can be replaced by a narrower type. 协变返回类型通常意味着可以用较窄类型替换的类型。 In Java , there is no such relation (supertype-subtype) between void and Object or anything else. JavavoidObject之间没有这种关系(supertype-subtype)或其他任何东西。

If this were allowed, there would be no way to determine if this should compile or not. 如果允许这样做,将无法确定是否应该编译。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM