如何将类作为泛型传递?

时间:2015-06-21 17:35:37

标签: java android generics

我是java泛型的新手,下面的代码为我将泛型类作为参数传递给方法造成了混乱。 我创建了一个android项目,我用Volley库来处理服务器调用.Below是代码

Advanced Connection Util:此类返回JacksonRequest对象

public class AdvancedConnectionUtil<T> {

private String requestType;
private ServerListener listener;

public AdvancedConnectionUtil(String requestType , ServerListener<T> listener){

    this.listener = listener;
    this.requestType = requestType;
}

public JacksonRequest getRequest(){

             //This gives compile error while while passing DataList.class in the argument
            return new JacksonRequest<T>(Request.Method.GET, HttpRequestConstant.JACKSON_FETCH, null ,DataList.class, new Response.Listener<T>() {
                @Override
                public void onResponse(T response) {
                    listener.onDataReceived(response);

                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    listener.onErrorReceived(error.getMessage());
                }
            });
    }


public interface ServerListener<T> {

    public void onDataReceived(T data);

    public void onErrorReceived(String errorMsg);

}

}

自定义JacksonRequest类:此类处理服务器调用和成功回调

public class JacksonRequest<T> extends JsonRequest<T> {

private Class<T> responseType;

/**
 * Creates a new request.
 *  @param method        the HTTP method to use
 * @param url           URL to fetch the JSON from
 * @param requestData   A {@link Object} to post and convert into json as the request. Null is allowed and indicates no parameters will be posted along with request.
 * @param responseType
 * @param listener      Listener to receive the JSON response
 * @param errorListener Error listener, or null to ignore errors.
 */
public JacksonRequest(int method, String url, Object requestData, Class<T> responseType, Response.Listener<T> listener, Response.ErrorListener errorListener) {
    super(method, url, (requestData == null) ? null : Mapper.string(requestData), listener, errorListener);
    this.responseType = responseType;
}


@Override
public Map<String, String> getHeaders() throws AuthFailureError {
    return super.getHeaders();
}

@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {

    try {
        String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        return Response.success(Mapper.objectOrThrow(json, responseType), HttpHeaderParser.parseCacheHeaders(response));
    } catch (Exception e) {
        return Response.error(new ParseError(e));
    }
}

}

这是我的活动类,它创建一个请求并将其传递给其他方法以进行服务器调用

public class CustomJacksonRequestActivity extends SuperActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    showProgressBar();

  JacksonRequest jacksonRequest = new AdvancedConnectionUtil<DataList>(null, httpListener).getRequest();

    //This commented code works fine when i create a request this way
   /* JacksonRequest<DataList> jacksonRequest = new JacksonRequest<DataList>(Request.Method.GET, HttpRequestConstant.JACKSON_FETCH, null, DataList.class, new Response.Listener<DataList>() {
        @Override
        public void onResponse(DataList response) {
            hideProgressBar();
            Log.e("ANSH", "onResponse : " + response.getPicture());
           // fillListWithIndex(response);

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            hideProgressBar();
            Log.e("ANSH", "onErrorResponse : " + error.getLocalizedMessage());
        }
    });*/

    onExecute(jacksonRequest);
}

@Override
protected void internetAvailable() {

}


@Override
public void setTitle(CharSequence title) {
    super.setTitle("CustomJacksonActivity");
}
 private AdvancedConnectionUtil.ServerListener  httpListener = new AdvancedConnectionUtil.ServerListener<DataList>() {
    @Override
    public void onDataReceived(DataList data) {
        Log.e("ANSH", "onResponse : " + data.getPicture());
    }

    @Override
    public void onErrorReceived(String errorMsg) {
        Log.e("ANSH", "onResponse : " + errorMsg);
    }
};

现在的问题是我无法将DataList.class(这是响应模型类)作为一个参数传递给AdvancedConnectionUtil类的getRequest方法中的JacksonRequest类的构造函数,尽管我能够做到这一点当我是在活动中创建请求对象(请参阅活动中的注释代码)。 如何将DataList.class传递给JacsonRequest的构造函数?

更新后的代码现在位于git hub中 github link to the project

2 个答案:

答案 0 :(得分:0)

你的代码有点令人困惑(你可以用一个更简单的例子),但我会给它一个镜头......

JacksonRequest类采用一个泛型类型参数 <T>,第四个构造函数参数的类型引用此类型:, Class<T> responseType,。这意味着当实例化JacksonRequest的实例(T为实数类型)时,传递的第4个参数必须保证为T.class类型。

当你调用构造函数时......

return new JacksonRequest<T>(Request.Method.GET, blah, null ,DataList.class, ...

...您使用泛型类型参数 <T>调用它。编译器必须始终能够将泛型类型参数与泛型类型参数匹配,但是使用第4个参数,您要求它将TDataClass匹配。由于编译器不知道T是什么(或者更准确地说,它不能保证在实例化时T实际上是DataClass),它会产生错误。

一般来说,您不能混合泛型类型参数和实际类型值 - 您必须始终选择其中一个。有些选项允许您指定泛型类型参数将从类派生或实现接口(<T super DataClass><T extends DataClass>,但在此处解释有点多。

答案 1 :(得分:0)

您的代码存在的问题是: 您的JacksonRequest<T>被声明为listener 必须 参数设置与responseType

相同的类型

但是对于AdvancedConnectionUtil<T>.getRequest(...),无法保证创建的JacksonRequest符合上述要求。因为您总是可以编写如下代码:

new AdvancedConnectionUtil<String> (null, httpListener).getRequest();

因此,您传递到JacksonRequest构造函数的参数将是DataList.class(类型为Class<DataList>)和listener类型为Listener<String>

可悲的是,Java中没有办法T.class,尽管这确实感觉就像你需要的那样。通常在这种情况下,我们将AdvancedConnectionUtil声明为:

class AdvancedConnectionUtil<T> {
  private final Class<T> responseType;
  private final ServerListener<T> serverListener;
  private final String requestType;

  public AdvancedConnectionUtil (String requestType , Class<T> responseType, ServerListener<T> listener) {
    this.requestType = requestType;
    this.responseType = responseType;
    this.serverListener = listener;
  }

  public JacksonRequest<T> getRequest(){
      return new JacksonRequest<T>(0, "", null ,responseType, new Response.Listener<T>(){
      ...        
      }
  }

您需要将Class<T>的responseType传递给AdvancedConnectionUtil并将其保留为成员字段。这样,AdvancedConnectionUtil实例在创建时严格限制为提供与特定响应类型相关的JacksonRequest

理论上,您可以将getRequest方法声明为getRequest(Class<T> responseType)。但是你的AdvancedConnectionUtil似乎没有从中获得任何东西