Why is void not covariant in Java?

可紊 提交于 2019-12-21 09:14:55

问题


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?


回答1:


Technically void cannot be a covariant return type as the caller needs to know the stack layout. Calling a function that returns an object would result of an object-ref on the top of the stack after the INVOKEVIRTUAL/INTERFACE. Void return type leaves nothing on the top of the stack, hence the functions are binary incompatible.

So the JLS rightfully says it's not possible.




回答2:


void is only covariant with void because the JLS says so:

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:

  • If R1 is void then R2 is void.

  • If R1 is a primitive type, then R2 is identical to R1.

  • If R1 is a reference type then:

    • 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|




回答3:


covariance means that if your methods return type is a Supertype object you can return sub-type Object at runtime, void is not the super type of java.lang.Object(or any Object for that matter except itself as answered by MR NPE)




回答4:


void effectively means that it returns nothing. You may be getting confused with a void * in C/C++. If you change the interface to be

public interface Foo {
    Object bar();
}

it will work fine because all objects in Java inherit 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();



回答5:


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?




回答6:


void is not part of the java file system.

If we do make it a type, it's more like an empty type, so it should be a subtype of every other type, i.e. 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.




回答7:


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.




回答8:


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 ?


来源:https://stackoverflow.com/questions/14219529/why-is-void-not-covariant-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!