3

please help me to understand why this cast is unchecked:

 List<? extends String> t= ...;
 List<String> t2=(List<String>)t;

It should be totally safe... I think this has probably already been asked, but I can't find it... too many questions about generics! I use regularly generics, but this doubt has always been there... Thank you in advance.

Edit: As pointed out, I should have used a non final class. So:

List<? extends ConfigurationAdapter> t= new ArrayList<DATASOURCE_ConfigurationAdapter>();
List<ConfigurationAdapter> t2=(List<ConfigurationAdapter>)t;

This works. I can't understand why it's unchecked.

CptWasp
  • 459
  • 2
  • 13

2 Answers2

4

I suppose an example can explain the reason of the warning.

But let's use other type, since strings cannot actually have subtypes in Java.

List<Integer> integers = new ArrayList<>(asList(1,2,3,4,5));
List<? extends Number> anyNumbers = integers;

Now, suppose we force the cast that you are doing, imagine that you could even do it without a warning

List<Number> numbers = (List<Number>) anyNumbers;

Now, you could do this:

numbers.add(3.5);

And later, in some other place in your code, somebody is trying to use the original collection like this:

for(Integer myInt: integers) { //ClassCastException

}

You get a ClassCastException because you have now broken the expectations of the type system. The original collection should accept Integers only, but you have managed to fool Java to make it accept any kind of numbers, in this case a double. Of course, when you iterate over the original collection, expecting integers, when you find one that is not actually an integer, your code will fail.

That's why it is logical that the compiler throws a warning, and that's why it is dangerous not to listen to it. And the fact that the String is a final class in Java is the reason why in your particular case you won't probably find any scenarios that finish in this problem I just described. But for other cases, this is a likely possibility.

Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205
2

For String it is totally safe and you can ignore the warning. The same would go for any type bound where the type is a final class type.

For any other type, the type of the value assigned to t might be a List<SubtypeOfTheBound>. In which case, it could not be assigned to a List<Bound>.

More reading:

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Thank you; but this code works: `List extends ConfigurationAdapter> t= new ArrayList(); List t2=(List)t;` and DATASOURCE_ConfigurationAdapter IS a subtype of the bound... Being t well defined, the cast always works... or not? – CptWasp Feb 19 '15 at 16:50
  • @CptWasp It works because you're casting it, telling the compiler you know what you're doing. It will fail later when you add a different subtype of `DATASOURCE_ConfigurationAdapter ` through `t` and try to read it as a `ConfigurationAdapter` from `t2`. You'll get a `ClassCastException` at that point. – Sotirios Delimanolis Feb 19 '15 at 16:52