Surya
Surya

Reputation: 4972

Java Generics: Warning needs a unchecked cast to conform to <InterfaceName>

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

Answers (4)

aperkins
aperkins

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

Yishai
Yishai

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

Brian Beckett
Brian Beckett

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

waxwing
waxwing

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

Related Questions