以下代码在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);
}
错误消息是: 类型不匹配:无法从Object转换为T
我知道我可以使用强制转换或手动绑定来解决问题,我的问题是:编译器是否很难进行自动绑定,是否会出现故障? < / p>
编辑:添加了错误消息。
编辑:添加了另一个例子,说明错误是如何发生的。
编辑:删除了第二个例子,因为它令人困惑,使问题更清晰。
答案 0 :(得分:5)
在第一种情况下,您有两个类型参数名为T
的泛型方法,但这些类型参数不同,所以让我们为它们指定不同的名称:
public <E> List<E> getList() { ... }
public <T> void first() { ... }
然后它的工作原理如下:
List<T>
的元素(类型为T
的对象)被分配给T
类型的变量,所以一切正常:
List<T> ret = new ArrayList<T>();
T t1 = ret.get(0);
首先,将List<E>
类型的对象分配给List<T>
。此语句正常工作,因为类型参数E
是从赋值左侧的类型推断出来的,因此T
= E
。然后它像前面的情况一样工作:
List<T> list = getList();
T t2 = list.get(0);
在这种情况下,您尝试将类型E
的对象分配给T
类型的变量,但无法推断E
,因此假定为{{1所以赋值失败:
Object
您可以通过手动将 T t3 = getList().get(0);
绑定到E
来解决此问题:
T
对于泛型类 T t3 = this.<T>getList().get(0);
,您没有两个独立的类型参数,因此两个方法中的TestGenerics<T>
指的是相同的类型。
答案 1 :(得分:4)
您正在使用泛型方法调用泛型方法。您需要将泛型参数从第一个方法传递给getList方法。
List<T> list = this.<T>getList();
和
T t3 = this.<T>getList().get(0);
从这两个编译中,第一个编译也没有给出泛型参数,因为编译器可以从列表类型中获取类型(从赋值的左侧)。在第二种情况下,它不是直接赋值,因此编译器不知道getList()调用的类型。
对于不同的编译器,这些行为可能会有所不同。
答案 2 :(得分:1)
我相信axtavt的答案比我自己更正确。由于我的内容包含了我的一些猜测,而另一个答案解释了所有观察到的行为,引用相关的来源并且一般意义上我请求您阅读axtavts答案。
为了完整起见,我会在这里留下原来的答案。只是不要把它当作绝对真理。
java.util.List.get
的签名如下:
public abstract java.lang.Object get(int arg0);
无论类型的参数化如何, get()
都会返回Object。这就是您无法将get(0)
分配给T
类型的变量的原因。即使您(实际上)可以保证列表中始终存在T
,但接口也没有做出承诺,编译器也无法接受您的承诺。
问题似乎与类型擦除有关。编译此代码时,它可以正常工作:
public <T> void someMethod(java.util.List<T> list) {
T s = list.get(0);
}
编译器知道它正在处理List<T>
,并且在编译时可以使用List<T>
的签名。它知道get()
将返回T
,并且非常高兴。如果您将代码更改为此代码则不再有效:
public <T> List<T> getList() {
return new ArrayList<T>();
}
public <T> void someMethod() {
T s = getList().get(0);
}
这可能是因为在编译getList()
方法时,类型会被删除,现在它将返回非通用java.util.List
类型。 get()
上的List
返回Object
,编译器将不再知道它曾经是List<T>
并会抱怨。
答案 3 :(得分:0)
尝试将其强制转换为T类型。
public <T> List<T> getList()
{
return new ArrayList<T>();
}
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 = (T) getList().get(0);
}
答案 4 :(得分:0)
getList()方法似乎每次返回一个最初为空的新列表。从空列表中获取(0)将抛出IllegalArgumentException。这是一个运行时错误,但它可能不会导致编译错误。