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 } } } ```

Original source