将嵌套的Class <MyInterface >作为Android中的parameter passing

我试图在Retrofit上创建一个包装器来抽象我的服务实现。 到目前为止,我已经使编译器成功编译:

 package com.example.spark.testapp.services; import com.example.spark.testapp.services.apis.Get; import com.example.spark.testapp.services.apis.Post; import com.example.spark.testapp.services.utils.*; import com.example.spark.testapp.services.utils.Error; import java.util.List; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; public class ServiceLayer { public  void performGet(String url, final Class<Get> clazz, com.example.spark.testapp.services.utils.Callback callback) { Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); Get service = retrofit.create(clazz); //Pass authentication token here Call t = service.get(url, ""); executeCallback(callback,t); } public  void performPost(String url, final Class<Post> clazz,com.example.spark.testapp.services.utils.Callback callback) { Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); Post service = retrofit.create(clazz); //Pass authentication token here Call t = service.post(url, ""); executeCallback(callback,t); } public  void executeCallback( final com.example.spark.testapp.services.utils.Callback callback , Call call) { call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { callback.onSuccess(response.body()); } @Override public void onFailure(Call call, Throwable t) { ///Find out what exactly went wrong. Populate Error. and then... com.example.spark.testapp.services.utils.Error e = new Error(); callback.onFailure(e); } }); } } 

在编译时,问题在于调用方法:

 private void getString() { ServiceLayer s = new ServiceLayer(); s.performGet("",Get.class,this); //Cannot select from parameterised type } 

我用Google搜索了一下,发现由于types擦除,这是不可能的。 精细。

但我的问题是,编译器不应该在这里引发错误吗? 在这条线? :

 public  void performGet(String url, final Class<Get> clazz, com.example.spark.testapp.services.utils.Callback callback) 

我的服务层是如何编译的?

编辑

这个问题似乎被误解了。 我不是在寻找一种让这种设计发挥作用的方法。 我理解其中的缺陷,我们find了更好的方法来分层我们的服务。 问题是关于语言本身的有趣/奇怪的行为。

但我的问题是,编译器不应该在这里引发错误吗?

方法签名在Java中是完全正确的。 通用方法签名由与常规方法相同的规则控制。

在通用方法中,您可以在代码中执行的操作取决于参数types。 例如,如果您有此方法:

 public static  void test(List list, Class clazz) throws InstantiationException, IllegalAccessException { list.add(clazz.newInstance()); } 

它编译,但如果我们添加下一行:

 list.add(new Integer(1)); 

它不会因为在编译时list只接受T实例。 因此,通用方法定义明确。

当您尝试调用generics方法时,编译器无法从参数中推断出T 主要问题显然是Class>构造,它在方法签名中有效但不推荐。 虽然,你可以做一个不安全和怪异的强制转换来使方法调用编译和工作:

 s.performGet("",(Class>)(Class) Get.class,this); 

执行此转换链,编译器现在可以推断T ,因为genericstypes仅在编译时检查。 在运行时, Class>将始终为Get.class

有关此主题的一些相关问题:

在通用列表的java中传递Class

通用types作为Java方法中的参数

首先,您的语法是有效的,因此编译器不会在给定行中显示错误。 您遇到的错误可能与该类有关,该类是由VM创建的特殊类,并且在检查错误期间编译器将其视为普通类。

看看这个例子:

  class Get { } class Callback { } class Clazz { } static class ServiceLayer { public  void performGet(String url, final Clazz> clazz, Callback callback) { } } 

现在,如果你试着打电话

  ServiceLayer a = new ServiceLayer(); Clazz> clazz = new Clazz>(); Callback callback = new Callback(); a.performGet("someurl", clazz, callback); 

你想要有任何问题。 因此,您看到该语法没有问题,但有特殊对象。

做了一些测试并find了一些解决方案,希望它会有所帮助。

由于此代码返回true(其中A是一些不执行任何操作的generics类):

 A a = new A(); System.out.println(A.class == a.getClass()); 

这意味着您不需要获取“Get ”类,而只需要“获取”您的Retrofit

你需要的是发送T作为另一个参数,以便知道这个T的function,例如:

 public  void performGet(String url, final Class clazz, final Class t, com.example.spark.testapp.services.utils.Callback callback) { Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); Get service = retrofit.create(clazz); ... 

如果要在方法中保持通用类参数(T)信息可访问,则必须提供类信息。 例:

 public class SomeClass { Class xClass; Class tClass; Class cClass; public SomeClass(Class a, Class b, Class c){ tClass = a; xClass = b; cClass = c; } } 

这样,您可以使用“consumer”类中的类信息,用于访问常用签名,序列化/反序列化过程,对象创建,调用generics方法等。

现在,如果您只想在方法中使用generics类参数的信息,您应该:

 public  void performGet(String url, final Class clazz, com.example.spark.testapp.services.utils.Callback callback) { Retrofit retrofit = new Retrofit.Builder().baseUrl("").build(); Get service = retrofit.create(clazz); //Pass authentication token here Call t = service.get(url, ""); executeCallback(callback,t); } 

这允许您将通用类信息保存到包含该方法的类中; 您可以在方法中访问它,并将其用作其他generics方法和其他所有方法的参数。

如果您需要更多示例,请查看此内容。 它也是一个包装器,但围绕着Spring的RestTemplate-Android,所以也许你可以从中获得一些想法。 (免责声明 – 我是开发人员)

https://github.com/fcopardo/EasyRest/blob/master/src/main/java/com/grizzly/rest/GenericRestCall.java