7

我需要将泛型类型的类传递给类的构造函数。该类是来自 RoboSpice Android 库的SpiceRequest,用于对构造函数的引用

在这种情况下,当可以从泛型类型本身访问它时,类需要将泛型的类传递给构造函数,这似乎很奇怪RESULT.class,但也许我错了。无论如何,我不想更改库的代码,而是需要为 , 的泛型类型使用泛型SpiceRequest类型Map<String, ? extends Object>。这是我的代码:

SpiceRequest<Map<String, ? extends Object>> request =
        new SpiceRequest<Map<String, ? extends Object>>(???) {
            ...
        };

以及构造函数的签名SpiceRequest

public SpiceRequest(final Class<RESULT> clazz) {
    ...
}

为了 ???我尝试Map.class过编译器错误:The constructor SpiceRequest<Map<String,? extends Object>>(Class<Map>) is undefined.

Map<String, ? extends Object>.class给出错误:Syntax error on tokens, PrimitiveType expected instead,特别是下划线? extends Object。它也给出与 相同的错误Map.class

Map.<String, ? extends Object>class给出相同的编译器错误。

获取泛型类的正确方法是什么Class<Map<String, ? extends Object>>

4

4 回答 4

5

具体参数化类型或通配符参数化类型没有类文字。来自Angelika Langer 的泛型教程

通配符参数化类型在称为类型擦除的过程中转换为字节码时会丢失其类型参数。作为类型擦除的副作用,泛型类型的所有实例共享相同的运行时表示,即相应原始类型的表示。换句话说,参数化类型没有自己的类型表示。因此,没有必要形成诸如List<?>.classList<? extends Number>.class和之类的类文字List<Long>.class,因为不Class存在这样的对象。只有原始类型List具有Class表示其运行时类型的对象。它被称为List.class

出于同样的原因,具体参数化类型没有类文字,简而言之就是类型擦除

出于您的目的,您只需要对类文字进行未经检查的强制转换:

Class<Map<String, ?>> c = (Class<Map<String, ?>>)(Class<?>)Map.class;

请注意,双重转换是必要的,因为从toClass<?>的直接转换是非法的。Class<Map>Class<Map<String, ?>>

于 2013-01-19T22:50:55.633 回答
4

这个问题与 RoboSpice 本身并不真正相关,而是与 Java 语法的限制有关:在 Java 中没有可用于获取参数化泛型类型的类/类型的文字。

如果你想做类似的事情

public class ListTweetRequest extends SpiceRequest<List<Tweet>> {

   public ListTweetRequest(Object cacheKey ) {
       super( <Here is the problem>, cacheKey );
   }
}

那么你不能将类传递List<Tweet>.class给你的父构造函数。这确实是 Java 的限制,因为泛型是使用类型擦除实现的,并且List<Tweet>.class在 Java 中没有真正的意义。

最好和最干净的解决方法是使用中间类型,例如:

public class ListTweet extends List<Tweet> {
}

public class ListTweetRequest extends SpiceRequest<ListTweet> {

   public ListTweetRequest(Object cacheKey ) {
       super( ListTweet.class, cacheKey );
   }
}

这样做的好处是为您提供了一个可以传递给SpiceRequest的构造函数的真实类型。但要小心混淆。在这些情况下,proguard 将尝试删除 ListTweet 类,您必须明确保护它免受混淆。

于 2013-01-20T07:37:09.003 回答
0

我总是用擦除来猜测,但你有没有试过用 Map.class 来调用它?

于 2013-01-19T21:59:08.550 回答
0

我也遇到了这个问题,我找到了@Snicolas 所说的解决方案。

看看这个 robospice-sample-retrofit 的例子:

https://github.com/octo-online/RoboSpice-samples/blob/release/robospice-sample-retrofit/src/com/octo/android/robospice/sample/retrofit/network/SampleRetrofitSpiceRequest.java

实际上最好不要从原始 List 接口继承,而是从任何子类(如 ArrayList 等)继承,否则您将必须实现所有接口方法。

import java.util.ArrayList;

public class Contributor {
    public String login;
    public int contributions;

    @SuppressWarnings("serial")
    public static class List extends ArrayList<Contributor> {
    }
}
于 2014-08-17T13:45:22.197 回答