繁体   English   中英

Java通用方法类型参数

[英]Java generic method type argument

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

Foo.<Bar>function();

假设有一个

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

在Foo类中起作用。 确切的问题是:

  • 我想下载一些内容(带有Ion的 Android)

  • 这些内容相似(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。

您能建议我一个通用的解决方案吗?

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

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

如果您自己编写上述声明,则会观察到类文件ArticleToken.class在所谓的Signature属性(请参阅JVMS )中跟踪泛型超类型。 因此,此技巧使您以后可以通过调用Class.getGenericSupertype来访问此类通用超类型。 换句话说,这是假冒伪造的泛型的惯用法。

如果将代码转换为通用方法,并用类型变量T替换Article,则会发生以下情况:您创建的类型令牌如下所示:

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

因此,有关T的信息将按原样存储在类文件中,如果reflectiopn要求提供类型令牌的泛型超类,则只需TypeToken<List<T>>而不是TypeToken<List<Article>> d期望这会导致您遇到的问题。 完成这项工作所需的是真正的泛型泛型,其中在方法调用站点将T绑定到Article会影响new TypeToken<List<T>>的运行时行为-但是令人遗憾的是,使用擦除泛型的Java并非如此。

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

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>>() {...});

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

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

那使用呢

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

the ContentItem interface, they do not the interface 由于这些类了ContentItem接口,因此它们不会该接口

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM