考虑这个小测试类:
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>
whenl
是List<T>
whereT
扩展的实例,并且具有类型擦除Runnable
(根据JLS SE7 §4.6)?
(b)编译器引发以下错误:
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
Comparable<T>
在这种情况下,我必须求助于T
to实例的未经检查的转换 (a)吗?List<Runnable>
编辑
答案是肯定的,正如 Bhesh 在下面指出的那样,泛型类型在 Java 中是不变的。如果我可以使用以下内容,则不会发生错误(b):
public abstract void setList(List<? extends Runnable> l);
有关更多信息,请参阅此出色的教程和JLS SE7 §5.1.10中有关捕获转换的本节。