having
class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;
since cannot do
List<BaseClass> aList = new ArrayList<ChildClassA>()
so there is a
List<? extends IData> aList
for pointint to either
ArrayList<ChildClassA>(),
or
ArrayList<ChildClassB>()
the aList
is built by other routing at runtime, and that part of code has a function to take a List<IData>
from the the aList
the question is if the List<? extends IData> aList
is point to ArrayList<ChildClassA>()
or ArrayList<ChildClassB>()
,
can it do ListData<IData> outputList = (List<IData>) aList
? something like below:
(seems it is working, but not sure if there is better way to assign the generics array other than casting.)
Edit: the output of the List<IData> outputList
is for read only use (immutable), no insert/delete on it, it will only iterate the IData to react on what the IData really is.
List<? extends IData> aList = new ArrayList<ChildClassA>();
ListData<IData> outputList = (List<IData>)aList
List<? extends IData> aList = new ArrayList<ChildClassB>();
ListData<IData> outputList = (List<IData>)aList
tl;dr Use Collections#unmodifiableList
:
List<IData> outputList = Collections.unmodifiableList(aList);
For more information on this topic, you might want to get familiar with the PECS principle.
It's not possible, because the two types are incompatible.
A List<BaseClass>
is just what it is declared, a list of BaseClass
objects. More precisely, it makes two guarantees:
BaseClass
BaseClass
can be added to it (and no other)A List<? extends BaseClass>
is a more loose declaration. Precisely, it simply does not make the second guarantee. However, not only the guarantee is gone, but it is now impossible to add items to it, since the exact generic type of the list is undefined. It might even change for the same list declaration (not the same list object) at runtime.
As a consequence, a List<? extends BaseClass>
is not assignable to a List<BaseClass>
, since the latter makes a guarantee the first is unable to fulfill.
Practically speaking, consider the following method:
public List<BaseClass> makeList() {
// TODO implement method
return null;
}
If someone implements this method, returning a List<? extends BaseClass>
, a client using this method would be unable to add items to it, although its declaration indicates otherwise.
Because of that, such an assignment results in a compilation error.
To fix the example problem the loose declaration can be added to the method:
public List<? extends BaseClass> makeList() {
// TODO implement method
return null;
}
This will signal every client, that the list returned from this method is not meant for adding items to it.
Now let's get back to your use case. In my opinion the most appropriate fix is to the rephrase the function that
take[s] a List from the the aList.
As it seems it is currently declared as
public void useList(List<BaseClass> list);
but since it does not add items to the list, it should be declared as
public void useList(List<? extends BaseClass> list);
However, if that method is part of a currently unchangeable API, you can still do:
List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);