如何使用带有通配符的集合和泛型?

时间:2012-11-11 18:15:51

标签: java generics collections wildcard

首先,我将尝试解释此代码背后的想法。 我有一堆类(处理器)可以处理某种类型的其他类(Processables)。我有一个处理器列表以按特定顺序执行它们。我有一个Map,它将检索我要为某个处理器处理的数据(Processables)。 它看起来像这样。

public abstract class AbstractProcessable {
    ...
}

public class DummyProcessable extends AbstractProcessable {
   ...
}

public abstract class AbstractProcessor<T extends AbstractProcessable> {
    public abstract void process(List<T> listOfProcessables);
}

public class DummyProcessor extends AbstractProcessor<DummyProcessable> {

    @Override
    public void process(List<DummyProcessable> listToProcess) {
        ...
    }
}

到目前为止这似乎工作正常。没有编译错误。但现在我有一个类如下的课程:

public class RandomClass {

    private List<AbstractProcessor<? extends AbstractProcessable>> processors;

    private Map<Class<? extends AbstractProcessor>, List<? extends AbstractProcessable>> data;

    public RandomClass() {
        processors = new ArrayList<>();
        processors.add(new DummyProcessor());

        data = new HashMap<>();
        data.put(DummyProcessor.class, new ArrayList<DummyProcessable>());

        processAll();
    }

    private void processAll() {
        for (AbstractProcessor<? extends AbstractProcessable> processor : processors) {
            List<? extends AbstractProcessable> dataToProcess;
            dataToProcess = data.get(processor);
            processor.process(dataToProcess); // compile error
        }
    }
}

编译错误:

    The method process(List<capture#4-of ? extends AbstractProcessable>) in the type AbstractProcessor<capture#4-of ? extends AbstractProcessable> is not applicable for the arguments (List<capture#5-of ? extends AbstractProcessable>)

我知道这可能有点难以阅读,但我试图尽可能地简化它。我对泛型也不是那么好,所以也许我用了一些通配符错了? 任何人都可以帮我解决这个问题吗?

提前多多感谢!

3 个答案:

答案 0 :(得分:1)

如果我理解你的问题,我前一段时间问a similar one。简短的回答是你不能以你想要的方式使用这样的地图。好消息是你不需要它;)

问题是Java泛型是编译时的事情(正如您可能已经知道的那样),并且它们仅在编译时存在,当您实际填充{{1}时, }。你无法找到用Java表达你的想法的方法,即使它看起来是完全合法的。

您可能会发现Super Type Tokens对于在某些情况下提取参数很有用,并且如果合适,请避免用户提供显式参数(不过请注意the limitations并考虑它们是否真的可以添加一些值)。 / p>

简而言之,你最终会得到像

这样的字段
List

(或者你可以使用Guava's Multimap实现),使用一些强制转换并喊出一些警告,并依靠你的程序逻辑使客户端代码是类型安全的。我在我的代码中使用了这种方法,到目前为止它从未失败过。

这是我的代码。我认为这正是您的情况,只需将private Map<Class<?>, List<?>> data; Subscriber<T>替换为MessageProcessor<T>

Processable

答案 1 :(得分:1)

我怀疑这里的问题是:

    来自? extends AbstractProcessable和的
  1. private List<AbstractProcessor<? extends AbstractProcessable>> processors; 来自? extends AbstractProcessable
  2. List<? extends AbstractProcessable> dataToProcess;

    不是同一类型。 ? extends AbstractProcessable表示AbstractProcessable的未知子类,没有任何力量可以证明两个未知应该是相同的(这就是为什么你得到错误,因为未知:capture#4-of ?与未知的不同: capture#5-of ?)。 不确定RandomClass的目的但我会将其更改为<T extends AbstractProcessable>并使用T来定义列表和地图。这样列表和地图将具有相同的类型。

答案 2 :(得分:0)

对我来说,听起来你在这些中导入了2个不同的List类。检查导入部分并确保

import java.util.List

同时包含(或您需要的任何列表类型)

就像第一次猜测一样,没有详细检查你的代码:)