9

私は警告を受けています:

[未チェック] パラメータ化された vararg 型クラスからのヒープ汚染の可能性

しかし、それが実際に汚染するかどうかはわかりません:

public void register(EventListener listener, Class<? extends Event>... eventTypes) {}

必要な場合の完全な実装は次のとおりです。

public class EventDispatcher {

    public static ConcurrentLinkedQueue<Event> eventQueue;
    public static ConcurrentHashMap<Class<? extends Event>, CopyOnWriteArrayList<EventListener>> eventsListenerMap =
            new ConcurrentHashMap<>();

    public static void register(EventListener listener, Class<? extends Event>... eventTypes) {
        for (Class<? extends Event> eventType : eventTypes) {
            if (eventsListenerMap.containsKey(eventType)) {
                eventsListenerMap.get(eventType).addIfAbsent(listener);
            } else {
                CopyOnWriteArrayList<EventListener> initializingListeners =
                        new CopyOnWriteArrayList<>();
                initializingListeners.add(listener);
                eventsListenerMap.put(eventType, initializingListeners);
            }
        }
    }
}

これを改善するための OT の提案もお待ちしていますが、このクラスは未完成であることを覚えておいてください。

4

3 に答える 3

8

ジェネリック可変引数に関する警告は、ジェネリック配列の危険性に関連しています。理論的には、このメソッドは、渡された配列で配列の共分散を悪用して、ヒープ汚染を引き起こす可能性があります。次に例を示します。

Class<?>[] eventTypesWithWidenedType = eventTypes;
eventTypesWithWidenedType[0] = String.class;
Class<? extends Event> eventType = eventTypes[0]; // liar!

しかし、メソッドの実装がそのような愚かなことをしない限り、それは問題ありません。いくつかの基本的な予防措置は次のとおりです。

  • への割り当てを行わないでくださいeventTypes
  • eventTypesメソッドの外部で返さないか、または公開しないでください。

Java 7 では、 @SafeVarargsでメソッドにアノテーションを付けることができました。これは、基本的に、ジェネリック配列が問題ないことをコンパイラーに約束します (つまり、呼び出し元が警告を抑制しなくなったことを意味します)。

于 2013-06-30T17:35:05.877 に答える
2

ジェネリック化された varargs (ジェネリック化されたリストなど) がある場合は常に、ヒープ汚染の可能性があります。例えば:

public void doSomethingWithStrings(List<String>... strings) {
    Object[] objectArray = strings; //Valid because Object is a valid supertype 
    objectArray[0] = Arrays.asList(new Integer(42)); //Heap pollution

    String string = strings[0].get(0); //Oops! ClassCastException!
}

あなたの例ではClass<? extends Event> eventTypes...、同じ問題の餌食になります:

public static void register(EventListener listener, Class<? extends Event>... eventTypes) {
    Object[] objectArray = eventTypes;
    objectArray[0] = String.class; //Heap pollution

    ...
    ...
}

Java は、潜在的なヒープ汚染ソリューションがあることを警告しているだけです。Java 7 では、警告はメソッドの宣言でも生成されますが、以前のバージョンでは呼び出しサイトでのみ生成されていました。

ヒープ汚染が発生しないことが確実な場合は、@SafeVarargs注釈を使用して警告を抑制することができます。

于 2013-06-30T17:50:28.097 に答える
0

register メソッドの本体が、不正な引数のために実行時に ClassCastException をスローしないように注意する必要があります。処理されていることが確実な場合は、警告を安全に無視または抑制できます。

于 2013-06-30T17:22:37.877 に答える