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);
No, it is unsafe.
After that cast it would be legit to add to the list that is supposed to contain only ChildClassA
typed elements, element of the other child type ChildClassB
type and vice-versa.
We can simply your code a bit to make it more obvious why this should not be allowed:
List<ChildClassA> aList = new ArrayList<ChildClassA>();
aList.add(a1);
aList.add(a2);
//...
List<IData> iDataList = (List<IData>) aList;
iDataList.add(b1);
iDataList.add(b2);
//...
for (ChildClassA a : aList) {
// a some point a is going to be assigned b1 or b2 and they results in cast
// exception.
}
Note that iDataList
makes reference to the very same list object as aList
.
If that cast was allowed then you would be able to add elements to aList
that are not ChildClassA
instances.
The best solution is on the details.
If the problem is that a third-party library requires a List<IData>
typed reference and as long as it is only for reading you can use a unmodifiable proxy as returned by Collections.unmodifiableList
:
import java.util.Collections;
//...
final List<ChildClassA> aList = new ArrayList<>();
//... add stuff to aList
final List<IData> readOnlyIDataList = Collections.unmodifiableList(aList);
//... read only access operations readOnlyIDataList
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With