如何为泛型对象调用静态类方法?

时间:2013-01-19 21:53:00

标签: java class generics robospice

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

类似乎需要将泛型类传递给contstructor,这可能是从泛型类本身访问的,在本例中是RESULT.class,但也许我错了。无论如何,我不打算更改库的代码,而是需要使用通用类型SpiceRequestMap<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 个答案:

答案 0 :(得分:5)

具体参数化类型或通配符参数化类型没有类文字。来自Angelika Langer's generics tutorial

  

通配符参数化类型会丢失它们的类型参数   在名为 type erasure 的进程中转换为字节代码。作为一方   类型擦除的效果,泛型类型共享的所有实例化   相同的运行时表示,即相应的 raw的表示   输入的。换句话说,参数化类型没有类型   他们自己的代表。因此,没有意义   形成类文字,例如List<?>.classList<? extends Number>.classList<Long>.class,因为没有这样的Class个对象   存在。只有原始类型List具有代表其的Class对象   运行时类型。它被称为List.class

由于相同的原因,具体参数化类型没有类文字,简而言之是type erasure

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

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

请注意,必须通过Class<?>进行双重投放,因为从Class<Map>Class<Map<String, ?>>的直接转换是非法的。

答案 1 :(得分: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类,您必须明确地将其保留为模糊处理。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

请看这个robospice-sample-reform的示例:

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> {
    }
}