编译器对泛型类型的自动绑定(类型推断)

osh*_*hai 1 java generics binding type-inference

以下代码在t3行中有编译错误:

public <E> List<E> getList()
{
    return new ArrayList<E>();
}
public <T> void first()
{
    List<T> ret = new ArrayList<T>();
    List<T> list = getList();
    T t1 = ret.get(0);
    T t2 = list.get(0);
    T t3 = getList().get(0);
}
Run Code Online (Sandbox Code Playgroud)

错误消息是: 类型不匹配:无法从Object转换为T.

我知道我可以使用转换或手动绑定来解决问题,我的问题是:编译器是否很难进行自动绑定,是否会出现故障?

编辑:添加了错误消息.

编辑:添加另一个示例如何不发生错误.

编辑:删除了第二个例子,因为它令人困惑,使问题更加清晰.

axt*_*avt 5

在第一种情况下,您有两个名为类型参数的通用方法T,但这些类型参数不同,所以让我们为它们分配不同的名称:

public <E> List<E> getList() { ... }
public <T> void first() { ... }
Run Code Online (Sandbox Code Playgroud)

然后它的工作原理如下:

  1. List<T>(类型的对象T)的元素被分配给类型的变量T,所以一切正常:

     List<T> ret = new ArrayList<T>();   
     T t1 = ret.get(0);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 首先,List<E>分配类型的对象List<T>.此语句正常工作,因为类型参数E是从赋值左侧的类型推断出来的,所以T= E.然后它像前面的情况一样工作:

     List<T> list = getList();          
     T t2 = list.get(0);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在这种情况下,您尝试将类型的对象分配给类型E的变量T,但E不能推断并因此假定为Object,因此赋值失败:

      T t3 = getList().get(0);         
    
    Run Code Online (Sandbox Code Playgroud)

    您可以通过手动绑定E来修复此行为T:

      T t3 = this.<T>getList().get(0);
    
    Run Code Online (Sandbox Code Playgroud)

在泛型类的情况下,TestGenerics<T>您没有两个独立的类型参数,因此T在两种方法中都指向相同的类型.

  • @ohadshai:仅推断结果类型"如果方法结果发生在将要进行赋值转换的上下文中"(JLS§15.12.2.8),即结果是立即分配或用作方法调用中的参数. (2认同)