Java泛型方法类型参数

时间:2014-07-01 09:49:41

标签: java android generics ion

我对泛型方法的显式类型参数有疑问。我知道我可以这样做:

Foo.<Bar>function();

假设有

void <T> function() {...}

在Foo类中的函数。确切的问题是:

  • 我想下载一些内容(Android Ion

  • 这些内容类似(文章,BlogArticle,...),都实现了ContentItem接口

  • 目前下载的内容如下:

新闻例如

private void downloadNews() {
    Ion.with(this)
    .load(URL_NEWS)
    .as(new TypeToken<List<Article>>(){})
    .setCallback(new FutureCallback<List<Article>>() {
        @Override
        public void onCompleted(Exception e, List<Article> result) {
            // do something with result
        }
    });
}

如果我想下载博客文章,我必须更改网址和文章类(对于BlogArticle)。

我尝试制作这样的通用函数:

private <T extends ContentItem> void download(String url) {
    Ion.with(this)
    .load(url)
    .as(new TypeToken<List<T>>(){})
    .setCallback(new FutureCallback<List<T>>() {
        @Override
        public void onCompleted(Exception e, List<T> result) {
            // do something with result
        }
    });
}

并调用该函数

this.<Article>download(url);

没关系,编译好。跑完后我得到了

  

java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap无法强制转换为com.my.packagename.model.ContentItem

问题在于它没有使用显式类将Json映射到pojo。

你能给我一个通用的解决方案吗?

4 个答案:

答案 0 :(得分:1)

我认为使用TypeToken方法无法以通用方式实现您想要的内容。实际上,请注意,要使用类型标记,您需要创建一个匿名内部类。通过这样做,您可以有效地创建一个新的类文件,其超类型被定义为List<Article>。换句话说,就像你有以下声明一样:

class ArticleToken extends TypeToken<List<Article>> { ... }

如果您自己编写上述声明,您会发现类文件ArticleToken.class会跟踪所谓的Signature属性中的泛型超类型(请参阅JVMS)。因此,这个技巧允许您稍后通过调用Class.getGenericSupertype来访问此类通用超类型。换句话说,它是假冒具体化仿制药的成语。

如果您将代码转换为泛型方法并将Article替换为类型变量T,那么您创建的类型标记就是这样:

class GenericToken extends TypeToken<List<T>> { ... }

因此,关于T的信息按原样存储在类文件中,如果reflectiopn请求类型令牌的通用超类型,则只需返回TypeToken<List<T>>而不是TypeToken<List<Article>>,因为你&#39 ; d期望然后导致你看到的问题。你需要做的是真正的具体化泛型,在方法调用站点将T绑定到Article会影响new TypeToken<List<T>>的运行时行为 - 但遗憾的是,Java使用已删除的泛型不是这种情况

答案 1 :(得分:1)

多年以后,但我认为这对某人有用。我最终得到了一个更简单的解决方案。它只是一个简单的截断版本,但你可以得到这个想法:

public static <T> void asList(Context context, String url, Class<T[]> clazz, final FutureCallback<List<T>> callback) {
    Ion.with(context)
        .load(url)
        .as(clazz)
        .setCallback(new FutureCallback<T[]>() {
            @Override
                public void onCompleted(Exception e, T[] result) {
                    callback.onCompleted(e, Arrays.asList(result));
                }
        });
}

并使用如下:

asList(context, url, YourObject[].class, new FutureCallback<List<YourObject>>() {...});

答案 2 :(得分:0)

要反序列化为实现ContentItem的不同类,我认为您需要使用具有TypeAdapter的自定义GSON实例。

http://www.javacreed.com/gson-typeadapter-example/

答案 3 :(得分:-1)

使用

怎么样?
private <T implements ContentItem> void download(String url) {
....

由于类实现了 ContentItem接口,它们不会扩展接口