8

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

Foo.<Bar>function();

假设有一个

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

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

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

  • 这些内容都是类似的(Article, 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
        }
    });
}

如果我想下载博客文章,我只需要更改 url 和 Article 类(对于 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

4 回答 4

2

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

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>>() {...});
于 2017-09-29T07:26:08.377 回答
1

我认为没有办法使用 TypeToken 方法以通用方式实现您想要的东西。实际上,请注意,要使类型标记起作用,您需要创建一个匿名内部类。通过这样做,您有效地创建了一个新的类文件,其超类型被具体化为List<Article>. 换句话说,就像您有以下声明:

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

Signature如果您自己编写上述声明,您会观察到类文件 ArticleToken.class 在所谓的属性中跟踪通用超类型(请参阅JVMS)。因此,此技巧允许您稍后通过调用Class.getGenericSupertype. 换句话说,伪造物化泛型是一种习惯用法。

如果您将代码转换为泛型方法并将 Article 替换为类型变量 T,则会发生您创建的类型标记如下所示:

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

因此,关于 T 的信息按原样存储在类文件中,如果反射请求类型标记的通用超类型,您只需TypeToken<List<T>>返回而不是TypeToken<List<Article>>您期望的那样,这会导致您看到的问题。完成这项工作所需的是真正的具体化泛型,在方法调用站点将 T 绑定到 Article 会影响运行时行为new TypeToken<List<T>>- 但遗憾的是,使用擦除泛型的 Java 并非如此。

于 2016-10-06T17:50:43.157 回答
0

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

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

于 2014-07-14T08:06:06.080 回答
-1

怎么用

private <T implements ContentItem> void download(String url) {
....

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

于 2014-07-07T13:50:26.683 回答