如何使用非通用输入列表调用通用方法

How to invoke generic method with a list of non-generic inputs

我有以下 class:

public class RemoteService {

  private static class QueryEntry<T> {
    public final IQueryInput<T> input;
    public final FutureCallback<T> callback;
    // constructor not shown here
  }

  private final List<QueryEntry<?>> mQueries;

  public <T> Result doStuff(IQueryInput<T> input, FutureCallback<T> callback) {
    // Simplified code here
    if(mIsServiceAlive) {
      return actuallyMakeQuery(input, callback);
    } else {
      // will make it happen later
      mQueries.add(new QueryEntry(input, callback));
    }
  }

  private <T> Result actuallyMakeQuery(IQueryInput<T> input, FutureCallback<T> callback) {
    // ... magic
    return result;
  }

  //.. other code
  
  private void onServiceAlive() {
    //This method is called when this service is connected to dependencies 
    //and is now live. Here we want to actually make the queries ...
    for(final QueryEntry<?> entry : mQueries) {
      // Compile error here because I can't reference entry<T>.input
      // as T is now lost .... is there any where I can make this happen?
      actuallyMakeQuery(entry.input, entry.callback);
    }
    mQueries.clear();
  }

}

这里的问题很简单 -> 我可以用 mQueries 调用 actuallyMakeQuery 吗?我不这么认为,因为当我缓存所有输入时,我丢失了 T,因为 mQueries 正在使用 QueryEntry<?>。我也无法更改 doStuff 签名,因为它被定义为其他地方的接口。我可以在这里做什么?

您可以通过引入额外的间接级别来捕获通配符:

private <T> Result actuallyMakeQuery(IQueryInput<T> input, FutureCallback<T> callback) {
    // ... magic
    return new Result();
}

private <T> Result actuallyMakeQuery(QueryEntry<T> entry) {
    // no wildcards anymore
    return actuallyMakeQuery(entry.input, entry.callback);
}

此外,您在

中省略了<>
mQueries.add(new QueryEntry<>(input, callback));

不必要地把它变成原始类型。

然后您可以使用该新方法:

private void onServiceAlive() {
    // This method is called when this service is connected to dependencies
    // and is now live. Here we want to actually make the queries ...
    for (final QueryEntry<?> entry : mQueries) {
        // no problem here anymore
        actuallyMakeQuery(entry);
    }
    mQueries.clear();
}