16

In Java I can cast:

List<?> j = null;
List<Integer> j2 = (List<Integer>)j;

So why does the following fail?

List<List<?>> i = null;
List<List<Integer>> i2 = (List<List<Integer>>)i;
arshajii
  • 127,459
  • 24
  • 238
  • 287
JRR
  • 6,014
  • 6
  • 39
  • 59

3 Answers3

6

In your 1st snippet:

List<?> j = null;
List<Integer> j2 = (List<Integer>)j;

The compiler won't give you error, because List<?> is a super type of List<Integer>, because the family of types denoted by the wildcard "?" is a superset of Integer. So you can perform the cast from List<?> to List<Integer> (A downcast, you can say), but the compiler will show you an Unchecked Warning, to save you against a cast from say - List<Date> to List<Integer>. The warning is shown, because the cast would otherwise succeed at runtime, due to type erasure.


In the 2nd case:

List<List<?>> i = null;
List<List<Integer>> i2 = (List<List<Integer>>)i;

Here you are casting from List<List<?>> (referred to by FIRST from hereon) to List<List<Integer>>(referred to by SECOND from hereon).

Since, FIRST is not a super type of SECOND, clearly because the family of types denoted by List<?> (it can be List<Long>, List<Date>, List<String> or anything) is not a super set of List<Integer>. Hence a Compiler Error.

Suggested Reading:

Community
  • 1
  • 1
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • *"[...] the family of types denoted by `List>` [...] is not a super set of `List`.* It actually is! Any object of type `List` matches the more general type `List>`. – Cedric Reichenbach Jul 25 '18 at 13:41
4

Try:

List<? extends List<?>> i = null;

List<List<Integer>> i2 = (List<List<Integer>>)i;

Source (this source will reference to other great sources):

https://stackoverflow.com/a/3575895/2498729

Community
  • 1
  • 1
1

I'm guessing you need to do a wildcard cast to cast it to what you want.

List<?> j = null;
List<Integer> j2 = (List<Integer>)j;

List<List<?>> i = null;
List<List<Integer>> i2 = (List<List<Integer>>) (List<?>) i;

That compiles fine. You just needed to do an additional cast just to add a little buffer.

See here: http://ideone.com/xh88lX

If you want to know why, check here

Basically, here's the relevant info Here's another way to look at it:

  • Java generics is type invariant
  • There's a conversion from Integer to Number, but a List<Integer> is not a List<Number>
  • Similarly, a List<Integer> can be capture-converted by a List<?>, but a List<List<Integer>> is not a List<List<?>>
  • Using bounded wildcard, a List<? extends Number> can capture-convert a List<Integer>
  • Similarly, a List<? extends List<?>> can capture-convert a List<List<Integer>>
Community
  • 1
  • 1
JGibbers
  • 248
  • 3
  • 13