Java Generics和未选中的强制转换

时间:2013-12-18 15:09:32

标签: java generics

我正在努力解决Java中泛型的这个问题。希望有人可以帮我看看方法。

我有一个包含对象列表的类。这段代码有效,但我想摆脱演员表。我怎样才能使这更通用?

public class Executor {
    List<BaseRequest<BaseObj>> mRequests = new ArrayList<BaseRequest<BaseObj>>();

    public Executor() {
    }

    @SuppressWarnings("unchecked")
    public <T extends BaseObj> void add(final BaseRequest<T> request) {
        mRequests.add((BaseRequest<BaseObj>) request);
    }

    public void execute() {
        for (BaseRequest<BaseObj> r : mRequests) {
            // DO SOMETHING WITH r
        }
    }
}

2 个答案:

答案 0 :(得分:6)

在发布的片段中,您需要强制转换,因为BaseRequest<? extends BaseObj>不是BaseRequest<BaseObj>的子类型,并且由于类型擦除而无法在运行时检查强制转换,这就是编译器警告您的原因。但是,如果您更改mRequests的声明:

public class Executor  {

    List<BaseRequest<? extends BaseObj>> mRequests = new ArrayList<>();

    public Executor() {
    }

    public <T extends BaseObj> void add(final BaseRequest<T> request) {
        mRequests.add(request);
    }

    public void execute() {
        for (BaseRequest<? extends BaseObj> r : mRequests) {
            // DO SOMETHING WITH r
        }
    }
}

class BaseRequest<T> {}

class BaseObj {}

让我们一步一步解决问题。你希望能够打电话

req.add(new BaseRequest<ExtObj1>());
req.add(new BaseRequest<ExtObj2>());
req.add(new BaseRequest<ExtObj3>());

其中ExtObj[1|2|3] extends BaseObj。鉴于List接口:

List<T> {
  void add(T el);
}

我们需要找到BaseRequest<ExtObj1>BaseRequest<ExtObj2>BaseRequest<ExtObj3>的常见超类型。一个超类型为BaseRequest<?>,另一个超级类型为BaseRequest<? extends BaseObj>。我选择了第二个,因为它是最可能限制的。你应该知道在Java BaseRequest<ExtObj1>中不是BaseRequest<BaseObj>的子类型,因为泛型是不变的。

现在我们有了mRequests的正确声明,找到Executor.add()的API非常简单。顺便说一句,如果您需要的方法体非常简单,那么您甚至不需要类型参数:

public void add(BaseRequest<? extends BaseObj> request) {
  mRequests.add(request);
}

答案 1 :(得分:0)

警告不是错误。有警告,所以你检查是否有错误,因为它可能不会被自动检查。您应该检查它,然后使用注释注意已经检查过警告。

在您的情况下,警告BaseRequest<T>不等同于BaseRequest<BaseObj>

示例:

public class NumberWrapper<N extends Number> {
    private N value;
    public void setValue(N value) {
        this.value = value;
    }
}

public class MainClazz {
    private NumberWrapper<Integer> wrappedNumber = new NumberWrapper<Integer>();
    public void run() {
        Number n = externalSource.getNumber();
        wrappedNumber.setValue(n); // <-- Error. What if getNumber returns a double?
    }
}

您可以出现此错误,具体取决于您完成/整合所显示代码的方式。