类型推理在java中究竟是如何工作的



我正在尝试创建一个如下方法:

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>作为方法参数。它在呼叫站点变得非常麻烦;但这是你为使用一种类型被擦除的语言所付出的代价。

最新更新