考虑这个小测试类:
import java.util.List;
public abstract class Test {
// CAN modify this constructor interface
public <T extends Runnable & Comparable<T>> Test(List<T> l) {
setList((List<Runnable>)l); // <-- (a) warning
setList(l); // <-- (b) error
}
// CANNOT modify this interface
public abstract void setList(List<Runnable> l);
}
这简洁地代表了我的问题,因为我想使用通用方法来获取类型为T
的对象(Runnable
和Comparable<T>
),如Test
'的构造函数,但我被限制使用其他类似setList
的接口的方法来获取T
的集合。
(a)当List<Runnable>
是l
的{{1}}实例时,编译器为什么会警告未经检查的转换为List<T>
,并且具有类型擦除,T
(根据JLS SE7 §4.6)?
(b)编译器引发以下错误:
Runnable
我的理解是method invocation conversion无法将error: method setList in class Test cannot be applied to given types;
setList(l); // <-- compiler error
^
required: List<Runnable>
found: List<T> reason: actual argument List<T> cannot be converted to
List<Runnable> by method invocation conversion
where T is a type-variable:
T extends Runnable,Comparable<T> declared in constructor <T>Test(List<T>)
转换为T
,因为这可能会被视为缩小操作,但这是违反直觉的,正如我所预期的那样Runnable
与T
和Runnable
相交。
在这种情况下,我是否必须采用未经检查的转化(a)Comparable<T>
到T
的实例?
修改
答案结果是肯定的,正如Bhesh在下面指出的那样,泛型类型在Java中是不变的。如果我可以使用以下内容,则不会发生错误(b):
List<Runnable>
有关详细信息,请参阅this excellent tutorial以及JLS SE7 §5.1.10中有关捕获转化的此部分。
答案 0 :(得分:1)
a)T
是 - Runnable
但List<T>
不是List<Runnable>
。 通用类型在Java中是不变的。
b)原因与上述相同。 方法参数在Java中也是不变的。(注意:方法参数是协变的。)
setList((List<Runnable>)l);
中的广告素材应该是安全的,因为我们知道T
总是会实现Runnable
。这是注释@SuppressWarnings("unchecked")
存在的情况类型。
仍然存在一个问题(取决于您的情况),您正在从构造函数中调用可覆盖的方法。