Consider the following two classes:
public interface Foo<T>
{
public T moo();
}
public class IntFoo implements Foo<Integer>
{
public int moo()
{
return 0;
}
}
This code will produce an error at public
int
moo
, saying that int
is incompatible with the overridden method's return type Integer
. Strictly speaking, this is true, since int
does not directly equal Integer
. However, we all know that they can be implicitly converted to each other using auto(un)boxing. What is less know is the fact that the compiler generates a bridge method in this example:
public class IntFoo implements Foo<Integer>
{
public <synthetic> <bridge> Object moo()
{
return this.moo(); // upcast
}
public Integer moo() {
return 0;
}
}
This has to be done because the JVM differentiates between return types when resolving methods, and since the erased return type of Foo.moo
is Object
, the compiler generated a bridge method with the same signature as the method.
I am wondering why this wouldn't work with primitive polymorphic return types as well:
public class IntFoo implements Foo<Integer>
{
public <synthetic> <bridge> Object moo()
{
return Integer.valueOf(this.moo());
}
public int moo()
{
return 0;
}
}
There doesn't seem to be any reason not to have this feature:
IntFoo intFoo = new IntFoo();
Foo<Integer> foo = intFoo;
Integer i = foo.moo(); // calls the synthetic method, which boxes the result of the actual implementation
In fact, this screenshot of a REPL session shows that I was even able to implement this in my custom programming language (which compiles down to Java bytecode):
As always with these questions, the answer is that you'd have to ask the language designers. I can't see any reason why this couldn't be done. However in my opinion this feature would be fairly pointless. As you point out in the question it's only when moo
is invoked on a variable of static type IntFoo
that a primitive would get returned; on a variable of type Foo<Integer>
, an Integer
would get returned anyway. So you can achieve essentially the same thing by doing this.
public class IntFoo implements Foo<Integer> {
@Override
public Integer moo() { return mooAsInt(); }
public int mooAsInt() { return 0; }
}
Personally I think this is better because it's much more obvious when boxing does / does not take place. In your proposal, moo()
could return an int
or an Integer
depending on the static type of the variable, which would be extremely confusing.
In my humble opinion, the reason is purely syntactic. As you have demonstrated in the question, it is possible to generate a method returning int
and a method implementing the Foo
interface method returning Object
in the bytecode.
However, if you look at the problem from the Java syntax point of view (i.e. not bytecode),
public class IntFoo implements Foo<Integer> {
public int moo() { return 0; }
}
is supposed to override a method Integer moo()
which it doesn't. As you said yourself, Java distinguishes return types and int moo()
is not the same as Integer moo()
.
The problem with primitives is that they need different amounts of space on the stack... As opposed to object references which all take the same amount of space on the stack. And you can't have a variable sized stackframe, because otherwise at runtime the stack wouldn't know where to go back to on method exit
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With