在 Android 中将嵌套类<MyInterface<T>> 作为参数传递

2022-09-03 16:07:06

我正在尝试创建一个包装器来抽象我的服务实现。到目前为止,我已经让编译器成功编译: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 <T> void performGet(String url, final Class<Get<T>> clazz, com.example.spark.testapp.services.utils.Callback<T> callback) {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("").build();
        Get<T> service = retrofit.create(clazz);
        //Pass authentication token here
        Call<T> t = service.get(url, "");
        executeCallback(callback,t);
    }

    public <T> void performPost(String url, final Class<Post<T>> clazz,com.example.spark.testapp.services.utils.Callback<T> callback) {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("").build();
        Post<T> service = retrofit.create(clazz);

        //Pass authentication token here
        Call<T> t = service.post(url, "");
        executeCallback(callback,t);
    }

    public <T> void executeCallback( final com.example.spark.testapp.services.utils.Callback<T> callback , Call<T> call) {
        call.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
                callback.onSuccess(response.body());
            }


            @Override
            public void onFailure(Call<T> 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<String>.class,this); //Cannot select from parameterised type

    }

我用谷歌搜索了一下,发现由于类型擦除,这是不可能的。好。

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

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

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

编辑

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


答案 1

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

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

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

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

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

list.add(new Integer(1));

它不会,因为在编译时只接受 的实例。因此,泛型方法定义得很好。listT

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

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

通过这个强制转换链,编译器现在可以推断出,因为泛型类型只在编译时被检查。在运行时,将始终为 。TClass<Get<T>>Get.class

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

在泛型列表的java中传递Class<T>?

泛型类型作为 Java 方法中的参数


答案 2

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

看看这个例子:

 class Get<T> {
    }

class Callback<T> {
    }
class Clazz<T> {
    }

static class ServiceLayer  {

        public <T> void performGet(String url, final Clazz<Get<T>> clazz,
                Callback<T> callback) {
        }
    }

现在,如果您尝试致电

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

你想有任何问题。因此,如您所见,该语法没有问题,但特殊对象没有问题。


推荐