1

次のように使用するのに役立つユーティリティメソッドがありますConcurrentMap.putIfAbsent

public static <K, V> V putIfAbsent(
        ConcurrentMap<K, V> map, K key, Callable<V> task) {
    try {
        V result = map.get(key);
        if (result == null) {
            V value = task.call();
            result = map.putIfAbsent(key, value);
            if (result == null) {
                result = value;
            }
        }
        return result;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

今、私はそのような異質なマップに対処しなければなりません:

private ConcurrentMap<Class<?>, List<ClassHandler<?>>> handlerMap;

それにハンドラを追加するメソッド:

public <T> void addHandler(Class<T> c, ClassHandler<? super T> handler) {
    putIfAbsent(handlerMap, c, new Callable<List<ClassHandler<?>>>() {
        @Override
        public List<ClassHandler<?>> call() throws Exception {
            return new CopyOnWriteArrayList<>();
        }
    }).add(handler);
}

これまでのところは問題ありませんが、クラスを処理しようとすると問題が発生します。たとえば、次のようになります。

Class<String> c = String.class;
List<ClassHandler<?>> handlers = handlerMap.get(c);
if (handlers != null) {
    for (ClassHandler<?> c : handlers) {
        handler.handle(c);
    }
}

ただし、次のコードはコンパイルされません。

error: method handle in class ClassHandler<T> cannot be applied to given types;
        handler.handle(c);
  required: Class<CAP#1>
  found: Class<String>
  reason: actual argument Class<String> cannot be converted to Class<CAP#1> by method invocation conversion
  where T is a type-variable:
    T extends Object declared in class ClassHandler
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error

を使用するとコードはコンパイルhandler.handle((Class) c)されますが、未チェックの警告が表示されます。注釈を追加することはできますが@SuppressWarnings("unchecked")、他に良い方法がなければこれが最後の選択肢になります。

この問題について何か考えはありますか?

4

1 に答える 1

1

右。マップ自体のタイプは、クラスのタイプパラメーターと対応するクラスハンドラーが同じであることを保証するものではありません。(とにかくそれを表すタイプはありません。)ただし、独自のaddメソッドを正しく使用して、それらを挿入するときにそれらが一致することを確認しました。したがって、それらが同じであると信頼できますその場合は、ハンドラーを適切にパラメーター化されたタイプにキャストするだけです(警告を抑制する必要があります)。

for (ClassHandler<?> handler : handlers) {
    ((ClassHandler<String>)handler).handle(c);
}
于 2012-08-16T18:34:36.223 に答える