我对泛型方法的显式类型参数有疑问。我知道我可以这样做:
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。
你能给我一个通用的解决方案吗?
答案 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实例。
答案 3 :(得分:-1)
使用
怎么样?private <T implements ContentItem> void download(String url) {
....
由于类实现了 ContentItem接口,它们不会扩展接口