简体   繁体   English

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

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

First I will try to explain the idea behind this code. 首先,我将尝试解释此代码背后的想法。 I have a bunch of classes (Processors) that can process a certain type of other classes (Processables). 我有一堆类(处理器)可以处理某种类型的其他类(Processables)。 I have a List of Processors to execute them in a certain order. 我有一个处理器列表以按特定顺序执行它们。 I have a Map that will retrieve me the data to process (Processables) for a certain Processor. 我有一个Map,它将检索我要为某个处理器处理的数据(Processables)。 It looks somehow like this. 它看起来像这样。

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) {
        ...
    }
}

This seems to work fine so far. 到目前为止,这似乎工作正常。 There are no compilation errors. 没有编译错误。 But now I have a class like the following: 但现在我有一个类如下:

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
        }
    }
}

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>)

I know it might be a bit difficult to read, but I tried to simplify it as much as possible. 我知道这可能有点难以阅读,但我试图尽可能地简化它。 I'm also not that good with generics so maybe I used some wildcards wrong? 我对泛型也不是那么好,所以也许我用了一些通配符错了? Can anyone help me to solve that problem? 任何人都可以帮我解决这个问题吗?

Thanks a lot in advance! 非常感谢提前!

If I understand your question correctly, I asked a similar one some time ago. 如果我正确地理解你的问题,我前一段时间就问过类似的问题。 Short answer is that you can't use such a map in the way you intend to. 简短的回答是你不能以你想要的方式使用这样的地图。 The good news is that you don't need it ;) 好消息是你不需要它;)

The problem is that Java generics are a compile-time thing (as you may already know), and they solely exist at compile time, which is not when you actually fill your List . 问题是Java泛型是编译时的事情(正如您可能已经知道的那样),并且它们仅在编译时存在,而不是在您实际填充List You cannot find a way to express your idea in Java, even if it seems a perfectly legitimate one. 你无法找到用Java表达你的想法的方法,即使它看起来是完全合法的。

You may find Super Type Tokens useful to extract parameters in certain cases and avoid the user to supply an explicit parameter if it's suitable (however mind the limitations and consider if they can really add some value). 您可能会发现超级类型标记在某些情况下可用于提取参数,并避免用户在适当时提供显式参数(但请注意限制并考虑它们是否可以真正添加某些值)。

In short, you'll end up with a field like 简而言之,你最终会得到像这样的领域

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

(or you can use Guava's Multimap implementation for this), using some casts and shouting some warnings out, and relying on your program logic for the client code to be type safe. (或者你可以使用Guava的Multimap实现),使用一些强制转换并喊出一些警告,并依靠你的程序逻辑使客户端代码是类型安全的。 I used that approach in my code and it never failed so far. 我在我的代码中使用了这种方法,到目前为止它从未失败过。

This is my code. 这是我的代码。 I think it's exactly your case, just replace Subscriber<T> and Message with your Processor<T> and Processable 我认为这正是您的情况,只需将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);
    }
}

I suspect that the issue here is that: 我怀疑这里的问题是:

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

are not of the same type. 不是同一类型。 ? extends AbstractProcessable ? extends AbstractProcessable represents an unknown subclass of AbstractProcessable , nothing forces that the two unknown should be the same (that is why you get the error, since the unknown: capture#4-of ? is different then the unknown: capture#5-of ? ). ? extends AbstractProcessable代表一个未知的子类AbstractProcessable ,没什么力量,这两个未知的应该是相同的(这就是为什么你的错误,因为未知的: capture#4-of ?是不同的,则未知: capture#5-of ? )。 Not sure about the purpose of your RandomClass but I would change it to be of a <T extends AbstractProcessable> and use T to define the list and the map. 不确定您的RandomClass的目的,但我会将其更改为<T extends AbstractProcessable>并使用T来定义列表和地图。 This way the list and the map will have the same type. 这样列表和地图将具有相同的类型。

to me it sounds like you imported 2 different List classes in these. 对我来说,听起来你在这些中导入了2个不同的List类。 Check import section and make sure 检查导入部分并确保

import java.util.List

is in both (or whatever List type you need) 是两个(或你需要的任何列表类型)

Just as the first guess, without checking your code in detail :) 就像第一次猜测一样,没有详细检查你的代码:)

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

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