tags:

views:

78

answers:

5

I think the title should explain it all but just in case...

I want to know what risks and potential issues relating to casting can arise from the following snippet of Java code:

List<? extends MyObject> wildcardList = someAPI.getList();
List<MyObject> typedList = (List<MyObject>) wildcardList;

My thoughts are that all objects in the wildcardList should be an instance of MyObject (exact type or subclass) and so whenever objects are retrieved from typedList then there should never be a ClassCastException. Is this correct? If so why does the compiler generate a warning?

+2  A: 

You are correct about retrieving objects from typedList, this should work.

The problem is when you later add more objects to typedList. If, for instance, MyObject has two subclasses A and B, and wildcardList was of type A, then you can't add a B to it. But since typedList is of the parent type MyObject, this error will only be caught at runtime.

Thomas Kappler
yes. thomas is absolutely correct
nil
A: 

This is similar to

List<Object> obj = (List<Object>) new ArrayList<String>();

I hope the problem is evident. List of subtypes can't be cast to Lists of supertypes.

Rahul
This doesn't even compile. But what the OP is doing will compile but could fail at runtime.
Marimuthu Madasamy
Yes, that is correct. But i just wanted to demonstrate that there was something fundamentally incorrect.
Rahul
+5  A: 

There should be no problem as long as just you retrieve objects from the list. But it could result in runtime exception if you invoke some other methods on it like the following code demonstrate:

    List<Integer> intList = new ArrayList<Integer>();
    intList.add(2);

    List<? extends Number> numList = intList;
    List<Number> strictNumList = (List<Number>) numList;
    strictNumList.add(3.5f);

    int num = intList.get(1); //java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer
Marimuthu Madasamy
+1, good example. It's worth pointing out however, that as long as you only call "get"-type operations **you don't even need/benefit from the cast**. The *only* time you'd need to cast is if you want to do something "unsafe" (with a possible exception for calling library methods that aren't as flexible as they should be with their generic parameters).
Andrzej Doyle
+1  A: 

Consider you do something like:

List<ChildClassOne> childClassList = new ArrayList<ChildClassOne>();
childClassList.add(childClassOneInstanceOne);
childClassList.add(childClassOneInstanceTwo);

List<? extends MyObject> wildcardList = childClasslist; // works fine - imagine that you get this from a method that only returns List<ChildClassOne>
List<MyObject> typedList = (List<MyObject>) wildcardList; // warning

typedList.add(childClassTwoInstanceOne); // oops my childClassList now contains a childClassTwo instance
ChildClassOne a = childClassList.get(2); // ClassCastException - can't cast ChildClassTwo to ChildClassOne

This is the only major problem. But if you only read from your list it should be ok.

Andrei Fierbinteanu
A: 

In addition to the answers already posted, take a look at the following

The compiler generates a warning incase an element from the type is accessed later in your code and that is not the generic type defined previously. Also the type information at runtime is not available.

Zaki