On Tue, 28 Jul 2009, Daniel Thoma wrote:
> I can't figure out, why casting to a subclass causes an unchecked cast
> warning, when a wildcard type is involved, but seems to work in any other
> case:
>
> Example:
> static class Base<T> { }
>
> static class Derived<T> extends Base<T> { }
>
> <T> void foo() {
> Base<? extends CharSequence> base = new Derived<String>();
> Derived<? extends CharSequence> derived
> = (Derived<? extends CharSequence>) base; // causes warning
>
> Base<T> base2 = new Derived<T>();
> Derived<T> derived2 = (Derived<T>) base2;
>
> Base<String> base3 = new Derived<String>();
> Derived<String> derived3 = (Derived<String>) base3;
> }
>
> Compiler warning:
> warning: [unchecked] unchecked cast
> found : test.Main.Base<capture#325 of ? extends java.lang.CharSequence>
> required: test.Main.Derived<? extends java.lang.CharSequence>
> Derived<? extends CharSequence> derived = (Derived<? extends CharSequence>)
> base;
>
> Is there an explanation for this behavior?
Yes - you can't cast from one question mark to the other, because they're
different question marks.
Seriously.
There's no explicit link between the "? extends CharSequence" on base and
the "? extends CharSequence" on derived. Thus, they're different
'captures' of the "? extends CharSequence" wildcard (as subtly hinted in
the error message). As far as the compiler is concerned, those ?s could
refer to quite different types (remember a ? means 'some specific type,
but one which isn't fixed at compile time'), and so that cast isn't
guaranteed to work (and can't be checked at runtime, because java's
generics aren't reified).
You can fix this by adding a type parameter to the method - declare <Q
extends CharSequence> and replace "? extends CharSequence" with Q.
Although in your example, this won't work, because you then try to assign
a Derived<String> to it, which is obviously no good, because there is no
static guarantee that Q includes String. If you change base to being a
method parameter rather than a local, thus magically ignoring the question
of its actual value, it compiles cleanly.
This is quite arcane stuff, which is why all the answers you've had up to
Alessio's have got it completely wrong!
tom
--
Teach us how to die well
|