Unexpected compiler warning for return type <T extends ...> "
When I compile the following Java code (using Oracle JDK 1.7.0_25):
public class StackOverflowQuestion {
interface Example {
<T extends Example> T init();
}
static class ExampleImpl implements Example {
@Override
public ExampleImpl init() {
return this;
}
}
}
I am getting a warning:
StackOverflowQuestion.java:11: warning: [unchecked] init()
in ExampleImpl implements <T>init() in Example
public ExampleImpl init() {
^
return type requires unchecked conversion from ExampleImpl to T
where T is a type-variable:
T extends Example declared in method <T>init()
I can't figure out why it says "The return type requires an unchecked conversion" as the class implements Example
, as far as I can see, its actual return type.
Can someone explain to me what happened?
Generic method is assumed to Example
work where it T
can be any type that extends Example
, but you tried to implement it in ExampleImpl
such a way that it always returns.It ExampleImpl
may be ok if ExampleImpl
is the only class that implements Example
, but if there are others, you can get ClassCastException
at runtime.
In the following example, we create a new one ExampleImpl
, refer it to the base interface, and then call the generic method init()
with T
equal ExampleImpl2
. He is supposed to return ExampleImpl2
, but since you did this
, he chose ClassCastException
. This is why your code must generate a warning.
public class StackOverflowQuestion {
interface Example {
<T extends Example> T init();
}
static class ExampleImpl implements Example {
@Override
public ExampleImpl init() {
return this;
}
}
static class ExampleImpl2 implements Example {
@Override
public <T extends Example> T init() {
return null;
}
}
public static void main(String[] args) {
ExampleImpl2 e2 = ((Example) new ExampleImpl()).<ExampleImpl2>init();
}
}
My java is a little rusty, but can you get the derived class back in an overridden method?
public class StackOverflowQuestion {
interface Example {
Example init();
}
static class ExampleImpl implements Example {
@Override
public ExampleImpl init() {
return this;
}
}
}