I have a class A and a class B extends A
In another class C I have a field
private List<B> 开发者_运维知识库listB;
Now, for some unusual reason, I have to implement this method in C
public List<A> getList();
I tried to do so by forcing an upcast of listB field to List<A>
via a List<?>
cast:
public List<A> getList(){
return (List<A>)(List<?>)listB;
}
Clients should do
List<A> list = getList();
for(A a:list){
//do something with a
}
I did some test and it seems work correctly, but honestly I am not sure of the all possible implications.
Is this solution correct? And Is it the best solution?
Thanks for your answers.
No, this isn't generally type-safe. The client shouldn't be able to do
List<A> list = getList();
because otherwise they could write
list.add(new C()); // Where C extends A
Then the original code which knows about the list as a List<B>
will have problems when it tries to use it, assuming that every element is compatible with B
.
You could either wrap the original list to make it read-only, effectively - or make getList
return a List<? extends A>
, which means that clients won't be able to add items to it anyway.
If the list implementation you're using is unmodifiable, then it won't actually cause problems - but I'd still personally avoid it where possible.
The problem with this is that clients can, unwittingly, insert A
objects in what is actually a list of more specific B
objects only:
c.getList().add(new A());
This will cause all kinds of breakage when your code tries to take an object from the list assuming that it's a B
, but it isn't.
If your only goal is to let the client iterate over the list, it is better to hand out an Iterable<A>
instead:
public Iterable<A> getAs() { return this.theListOfAs; }
Through this Iterable
, one can only inspect and remove elements, but not add them.
If you want to disable removal as well, wrap the List
's Iterable
in your own implementation, throwing UnsupportedOperationException
when remove()
is called.
精彩评论