5

まず、このコードの背後にある考え方を説明しようと思います。特定のタイプの他のクラス(Processables)を処理​​できるクラス(Processors)がたくさんあります。特定の順序で実行するプロセッサのリストがあります。特定のプロセッサの処理するデータ(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>)

少し読みづらいかもしれませんが、なるべく簡略化してみました。私もジェネリックが苦手なので、ワイルドカードを間違って使用したのではないでしょうか。誰かが私がその問題を解決するのを手伝ってくれる?

よろしくお願いします!

4

3 に答える 3

1

私があなたの質問を正しく理解していれば、私は以前に同様の質問をしました。簡単に言えば、そのようなマップは意図したとおりに使用できないということです。良いニュースは、あなたがそれを必要としないということです;)

問題は、Javaジェネリックはコンパイル時のものであり(すでにご存知かもしれません)、コンパイル時にのみ存在し、実際List. 完全に正当なものに思えても、Java でアイデアを表現する方法を見つけることはできません。

スーパー タイプ トークンは、特定のケースでパラメータを抽出し、適切な場合はユーザーが明示的なパラメータを指定するのを避けるのに役立つ場合があります (ただし、制限に注意し、実際に何らかの値を追加できるかどうかを検討してください)。

要するに、次のようなフィールドになります

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

(または、これにGuava のMultimap実装を使用できます)、いくつかのキャストを使用し、いくつかの警告を叫び、クライアント コードがタイプ セーフになるようにプログラム ロジックに依存します。私は自分のコードでそのアプローチを使用しましたが、これまでのところ失敗したことはありません。

これは私のコードです。まさにあなたのケースだと思います。 andをSubscriber<T>andに置き換え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);
    }
}
于 2012-11-11T18:35:33.167 に答える
1

ここでの問題は次のとおりだと思います。

  1. ? extends AbstractProcessableからとprivate List<AbstractProcessor<? extends AbstractProcessable>> processors;_
  2. ? extends AbstractProcessableからList<? extends AbstractProcessable> dataToProcess;

は同じタイプではありません。? extends AbstractProcessableの未知のサブクラスを表すためAbstractProcessable、2 つの unknown が同じであることを強制するものはありません (unknown: は unknown:capture#4-of ? とは異なるため、エラーが発生するのはそのためですcapture#5-of ?)。あなたの目的についてはわかりませんが、リストとマップを定義するために使用するRandomClassように変更します。このようにして、リストとマップは同じタイプになります。 <T extends AbstractProcessable>T

于 2012-11-11T19:30:28.570 に答える
0

私には、これらに 2 つの異なる List クラスをインポートしたように思えます。インポートセクションを確認してください

import java.util.List

両方(または必要なリストタイプ)にあります

コードを詳細にチェックせずに、最初の推測と同じように:)

于 2012-11-11T18:21:00.180 に答える