问题
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 isvoid
.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