我正在尝试创建一个如下方法:
public <T> T getInstance(String key) {
Type type = new TypeToken<T>(){}.getType();
return deserialize(key, type); }
就我不在return
语句中强制转换(T)
而言,我希望编译器从外部上下文推断类型,或者至少从下面这样的类型见证推断类型:
Integer i = container.<Integer>getInstance(mKey);
但在某些情况下,getInstance()
方法返回从未提及的Double
(更准确地说,序列化和反序列化使用谷歌的Gson库,初始对象是Integer
的实例(。因此,我得到了ClassCastException
。
那么,在这种情况下,类型推断究竟是如何起作用的?为什么类型证人不起作用?是否可以在不指定Class<T>.class
作为参数的情况下从外部上下文推断类型?
细化:
经过一些研究,这个常见问题解答帮助我更好地理解了这个话题。
这里的一般问题是没有任何东西可以约束输出与输入相关。
因此,这是有效的:
Integer i = container.<Integer>getInstance(mKey); // I doubt you even need the <Integer>
但这也有效:
String s = container.<String>getInstance(mKey);
getInstance
方法所看到的只是mKey
的值:它对<Integer>
或<String>
一无所知;因此在这两种情况下都必须返回相同的结果,但其中至少有一个是错误的(或者它们都返回null
(。
因为getInstance
只接收mKey
的值,所以类型令牌在两种情况下都是相同的。您可以通过实现自己的类型令牌类来看到这一点:
abstract static class TypeToken<T> {
Type getType() {
return getClass().getGenericSuperclass();
}
}
static <T> TypeToken<T> getTypeToken() {
return new TypeToken<T>() {};
}
public static void main (String[] args) throws java.lang.Exception
{
TypeToken<String> stringTypeToken = getTypeToken();
TypeToken<Integer> integerTypeToken = getTypeToken();
System.out.println(stringTypeToken.getType());
System.out.println(integerTypeToken.getType());
System.out.println(stringTypeToken.getType().equals(integerTypeToken.getType()));
}
输出:
Ideone$TypeToken<T>
Ideone$TypeToken<T>
true
在您的代码中,Type type = new TypeToken<T>(){}.getType();
并没有得到呼叫站点类型的TypeToken
,它只是得到T
。所以你没有得到TypeToken<Integer>
。
从编译的意义上说,这是有效的,但从没有做你想让它做的事情的意义上来说,这是无效的
正确执行此操作的方法是注入TypeToken<T>
作为方法参数。它在呼叫站点变得非常麻烦;但这是你为使用一种类型被擦除的语言所付出的代价。