Reputation: 4972
I have an interface
interface x {
A getValue();
}
and the implementation
class y implements x {
public B getValue() { return new B();}
}
B is a subclass of A. This works because of covariant overriding, I guess.
But if I rewrite the interface as
interface x{
<T extends A> T getValue();
}
I get a warning in the implementation that
Warning needs a unchecked cast to conform to A.getValue()
What is the difference between 2 versions of the interface? I was thinking they are the same.
Upvotes: 5
Views: 1081
Reputation: 13114
What the compiler is telling you is that there is no way to resolve the generic. T is not defined anywhere except as output - which T are you talking about? If the interface was generified to be a type T:
interface x <T extends A> {
T getValue()
}
then this would work, or if the method took a value that would define what type of return you wanted:
interface x {
<T extends A> T getValue(T someArgument)
}
or
interface x {
<T extends A> T getValue(Class<T> someArgument)
}
Then there would be no warning.
edit: See waxwing's post for an explanation as to why you should NOT be using generics for this particular problem. I am simply showing how generics would be appropriate.
Upvotes: 1
Reputation: 91871
Basically when you are doing a <T extends A>
you are saying that you want a specific subclass of A, not any A, because then you could just do:
A getValue();
The compiler is warning you that it can't ensure that a specific defined subclass of A is returned, only A itself.
EDIT: To try to explain this better, B is a subclass of A, but doesn't need to be the only subclass of A. Consider the following hierarchy.
B extends A C extends A but not B
Now I have a method:
public void someMethod(x value) {
C c = x.getValue();
}
Following the generics, that should compile and guarantee no runtime class cast exception (there may be other issues with interfaces here but there are certainly cases that could be used to demonstrate this properly - I'm keeping with your example).
But what if you pass in an instance of y to this method?
Well, now I'm getting an B instead of a C. The compiler is warning you this could happen.
Upvotes: 3
Reputation: 4900
So, to build on the two answers from AlbertoPL and Yishai, try this:
class y implements x {
A getValue(){ return new B();}
}
B extends A, so that's fine. The caller doesn't need to know what subclass of A is returned, only that it extends A. So there we go :)
Upvotes: 0
Reputation: 18743
The second version of the interface is wrong. It says that the getValue
will return any subclass you ask for - the return type will be inferred based on the expression on your left hand.
So, if you obtain a reference to an x
(let's call it obj
), you can legally make the following call without compiler warnings:
x obj = ...;
B b = obj.getValue();
Which is probably incorrect in your example, because if you add another class C
that also extends A
, you can also legally make the call:
C c = obj.getValue();
This is because T
is not a type variable belonging to the interface, only to the method itself.
Upvotes: 4