-1

考虑这个小测试类:

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>whenlList<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相交。RunnableComparable<T>

在这种情况下,我必须求助于Tto实例的未经检查的转换 (a)吗?List<Runnable>

编辑

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

public abstract void setList(List<? extends Runnable> l);

有关更多信息,请参阅此出色的教程和JLS SE7 §5.1.10中有关捕获转换的本节。

4

1 回答 1

1

a) Tis-aRunnableList<T>is-not-a List<Runnable>泛型类型在 Java 中是不变的。

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


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


还有一个问题可能是(取决于您的情况)您正在从构造函数调用可覆盖的方法。

于 2012-11-01T04:18:11.157 回答