Java Generics and unchecked cast
generics, java
Solution
In the posted snippet you need the cast because `BaseRequest<? extends BaseObj>` is not a subtype of `BaseRequest<BaseObj>`, and the cast can't be checked at runtime because of type erasure, and that's why the compiler warns you. But if you change the declaration of `mRequests`:
public class Executor {
List<BaseRequest<? extends BaseObj>> mRequests = new ArrayList<>();
public Executor() {
}
public <T extends BaseObj> void add(final BaseRequest<T> request) {
mRequests.add(request);
}
public void execute() {
for (BaseRequest<? extends BaseObj> r : mRequests) {
// DO SOMETHING WITH r
}
}
}
class BaseRequest<T> {}
class BaseObj {}
Let's resolve the problem step-by-step. You want to be able to call
req.add(new BaseRequest<ExtObj1>());
req.add(new BaseRequest<ExtObj2>());
req.add(new BaseRequest<ExtObj3>());
where `ExtObj[1|2|3] extends BaseObj`. Given the List interface:
List<T> {
void add(T el);
}
we need to find a common supertype for `BaseRequest<ExtObj1>`, `BaseRequest<ExtObj2>` and `BaseRequest<ExtObj3>`. One supertype is `BaseRequest<?>` and another one is `BaseRequest<? extends BaseObj>`. I picked the second one because it's the most restrictive possible. You should know that in Java `BaseRequest<ExtObj1>` is not a subtype of `BaseRequest<BaseObj>` because generics are invariant.
Now that we have the right declaration for mRequests, finding the API for `Executor.add()` is straightforward. BTW, if the method body you need is really that simple, you don't even need the type parameter:
public void add(BaseRequest<? extends BaseObj> request) {
mRequests.add(request);
}
Problem
I'm struggling with this aspect of Generics in Java. Hopefully someone can help me see the ways. I have a class that holds a List of objects. This code works, but I want to get rid of the cast. How can I make this more generic? ``` public class Executor { List<BaseRequest<BaseObj>> mRequests = new ArrayList<BaseRequest<BaseObj>>(); public Executor() { } @SuppressWarnings("unchecked") public <T extends BaseObj> void add(final BaseRequest<T> request) { mRequests.add((BaseRequest<BaseObj>) request); } public void execute() { for (BaseRequest<BaseObj> r : mRequests) { // DO SOMETHING WITH r } } } ```