带有方法调用转换的类型的多个边界

时间:2012-11-01 03:53:27

标签: java generics type-erasure

考虑这个小测试类:

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的对象(RunnableComparable<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,因为这可能会被视为缩小操作,但这是违反直觉的,正如我所预期的那样RunnableTRunnable相交。

在这种情况下,我是否必须采用未经检查的转化(a)Comparable<T>T的实例?

修改

答案结果是肯定的,正如Bhesh在下面指出的那样,泛型类型在Java中是不变的。如果我可以使用以下内容,则不会发生错误(b):

List<Runnable>

有关详细信息,请参阅this excellent tutorial以及JLS SE7 §5.1.10中有关捕获转化的此部分。

1 个答案:

答案 0 :(得分:1)

a)T是 - RunnableList<T>不是List<Runnable>通用类型在Java中是不变的。

b)原因与上述相同。 方法参数在Java中也是不变的。(注意:方法参数是协变的。)


setList((List<Runnable>)l);中的广告素材应该是安全的,因为我们知道T总是会实现Runnable。这是注释@SuppressWarnings("unchecked")存在的情况类型。


仍然存在一个问题(取决于您的情况),您正在从构造函数中调用可覆盖的方法。