Reputation: 5183
Requirement:
Declared a method which returns a Generic List based on wildcards. Got the declaration part right, but method call fails.
class Z{/*TemplateClass*/}
public class A extends Z{}
public class B extends Z{}
Test Class:
public List<? extends Z> getGenericList(boolean test){
if(test){
List<A> aList = new ArrayList<A>();
aList.add(new A());
return aList;
}
else{
List<B> bList = new ArrayList<B>();
bList.add(new B());
return bList;
}
}
Here's my requirement. I need something like the below code.
List<A> testAList = getGenericList(true);
List<B> testBList = getGenericList(false);
Gives me a compiler error.
Type mismatch: cannot convert from List< capture#1-of ? extends Z > to List< A > Type mismatch: cannot convert from List< capture#2-of ? extends Z > to List< B >
I understand the logic behind this. What if we pass a false and store the returned List of B's as a List of A's which is wrong. But when I use the below code:
List<? extends Z> testList = getGenericList(true);
It compiles fine. But it beats my purpose. I'm not able to access the methods in A or B as the testList.get(index) returns Z type objects where I hope to get either A or B.
If my code is absolutely wrong, then any pointers in the right direction would be appreciated.
Upvotes: 2
Views: 503
Reputation: 5239
Not going to happen. You are asking for a type that simply cannot be expressed in the java type system, something like List<A> + List<B>
.
The closest thing to that is a form of continuation passing style; you create another abstract class like HomogeneousListAB
with a visitor interface and accept method. Then you can return one of those from getGenericList.
abstract class HomogeneousListAB {
interface Visitor {
void ifListA( List< A > la );
void ifListB( List< B > la );
}
abstract public accept( Visitor v );
}
// inside getGenericList true branch
final List< A > laOut = // whatever
return new HomogeneousListAB() {
public accept( Visitor v ) {
v.ifListA( laOut );
}
};
Upvotes: 1
Reputation: 8245
You can cast the result which would make the compiler errors go away but you'd have an unsafe cast which seems like a code smell:
List<A> testAList = (List<A>) getGenericList(true);
List<B> testBList = (List<B>)getGenericList(false);
Also if the boolean input is not a strict requirement you can do something like this as well:
public <T extends Z> List<T> getGenericList(Class<T> klass) {
List<T> list = new ArrayList<T>();
try {
list.add(klass.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return list;
}
Upvotes: 3