java 中的类型推断究竟是如何工作的?

How exactly type inference is working in 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()方法returnsDouble从未被提及(更准确地说,序列化和反序列化使用google的Gson 库,初始对象是 Integer 的实例)。因此,我得到 ClassCastException.

那么在这种情况下类型推断究竟是如何工作的,为什么类型见证不起作用?是否可以在不指定 Class<T>.class 作为参数的情况下从外部上下文推断类型?

阐述:

经过一些研究,this FAQ 帮助我更好地理解了这个主题。

你在这里遇到的一般问题是没有任何东西可以限制输出与输入相关。

所以,这是有效的:

Integer i = container.<Integer>getInstance(mKey);  // I doubt you even need the <Integer>

但这有效:

String s = container.<String>getInstance(mKey);

getInstance 方法只看到 mKey 的值:它不知道 <Integer><String> 的任何信息;所以在这两种情况下这必须 return 相同的结果 - 但至少其中一个是错误的(或者它们都是 returning null)。


因为getInstance只接收到mKey的值,所以这两种情况下的type token是一样的。你可以通过实现你自己的类型标记来看到这一点 class:

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