繁体   English   中英

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

[英]How to use collections and generics with wildcards?

首先,我将尝试解释此代码背后的想法。 我有一堆类(处理器)可以处理某种类型的其他类(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>)

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

非常感谢提前!

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

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

您可能会发现超级类型标记在某些情况下可用于提取参数,并避免用户在适当时提供显式参数(但请注意限制并考虑它们是否可以真正添加某些值)。

简而言之,你最终会得到像这样的领域

private Map<Class<?>, List<?>> data;

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

这是我的代码。 我认为这正是您的情况,只需将Subscriber<T>Message替换为您的Processor<T>Processable

public class MessageBus {

    public enum Action {
        CREATE, REMOVE, UPDATE, DELETE;
    }

    private static Map<Class<?>, Set<Subscriber<?>>> subscriptions;

    static {
        subscriptions = new HashMap<Class<?>, Set<Subscriber<?>>>();
    }

    @SuppressWarnings("unchecked")
    public static <T> void publish(T message, Action action) {
        Set<Subscriber<?>> set = getSubscribersFor(message.getClass());

        if (set == null)
            return;

        for (Subscriber<?> subscriber: set) {
            ((Subscriber<T>) subscriber).onMessage(message, action);
        }
    }

    public static <T> void subscribe(Class<T> type, Subscriber<T> subscriber) {
        Set<Subscriber<?>> set = getSubscribersFor(type);

        if (set == null) {
            set = new HashSet<Subscriber<?>>();
            subscriptions.put(type, set);
        }

        set.add(subscriber);
    }

    public static <T> void unsuscribe(Class<T> type, Subscriber<T> subscriber) {
        Set<Subscriber<?>> set = getSubscribersFor(type);
        set.remove(subscriber);
    }

    private static Set<Subscriber<?>> getSubscribersFor(Class<?> topic) {
        return subscriptions.get(topic);
    }
}

我怀疑这里的问题是:

  1. ? extends AbstractProcessable private List<AbstractProcessor<? extends AbstractProcessable>> processors; ? extends AbstractProcessable private List<AbstractProcessor<? extends AbstractProcessable>> processors;
  2. ? extends AbstractProcessable List<? extends AbstractProcessable> dataToProcess; ? extends AbstractProcessable List<? extends AbstractProcessable> dataToProcess;

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

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

import java.util.List

是两个(或你需要的任何列表类型)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM