Reputation: 5136
I am trying to automatically cast each element of a list of objects into its proper type in the for loop
class A {
}
class B {
void sampleMethod() {
List<?> l1 = //initialized somewhere;
/*
I do know perfectly l1 got elements of Class A
I just could not declare List<A> for other (generic types) reasons
*/
for (A el: l1) { // Type mismatch: cannot convert from element type capture#1-of ? to A
System.out.println(el);
}
}
}
As I posted in code, that "for statement" shows the error:
Type mismatch: cannot convert from element type capture#1-of ? to A
I have tried other solutions like:
for (A el: (List<A>)l1)
Which results now in a warning:
Type safety: Unchecked cast from List to List
And finally I found a working (but not appropiate, in my opinion) solution, which is to cast inside the for:
for (Object el: l1) {
A listEl = (A) el;
System.out.println(el);
}
How come I can not do this kind of casting inside the for statement? Is there really no way to do it cleanly?
Upvotes: 1
Views: 693
Reputation: 131346
Is there really no way to do it cleanly?
If you declare a List
with a wildcard :
List<?> l1 = //initialized somewhere;
you would have never a way to cast its elements to a specific type without any warning.
What you try to do defeats the generics purpose.
You wrote in your comment :
I just could not declare
List<A>
for other (generic types) reasons
A generic variable without wildcard or bound such as List<A>
has some limitations. A known of it is you cannot assign to it a List<B>
where B
is a subclass of A
. But there is alternative to make it working as List<? extends A>
while it also have some other limitations.
In fact you don't describe the encountered problem as you declare List<A>
. So it is hard to provide a specific solution.
But I think that declaring a more specific type is the way that you should follow if you manipulate only A
instances in your List.
So if List<A>
causes an issue in your code, dig into this problem and if "not resolvable" why not ask a question about that.
Upvotes: 2
Reputation: 10082
If the following stands, "I do know perfectly l1 got elements of Class A", then try:
List<?> l1 = ...
@SuppressWarnings("unchecked")
List<A> l2 = (List<A>) l1;
for (A a: l2) { ... }
But a cleaner way would be to iterate over the original list, check type of elements and then cast without warnings:
for (Object generic: l1) {
if (generic instanceof A) {
A a = (A) generic; // without warnings
// do stuff
} else if (generic == null) { // if nulls possible
// do stuff
} else {
throw new IllegalArgumentException("item not of class A");
}
}
Upvotes: 1
Reputation: 1885
Your solution with casting elements inside the loop is completely appropriate. List<?>
is list of unknown, a collection whose element type matches anything. So the only thing you can be sure is that all items are objects, so you do. This is always safe, since whatever the actual type of the collection, it does contain objects. You can refer on similar case in Oracle Generics tutorial which is considered as good code examples.
Hope it helps!
Upvotes: 0