Можно ли связать вложенные дженерики? - PullRequest
3 голосов
/ 06 апреля 2010

Можно ли связать вложенные генерики / захваты вместе?

У меня часто возникает проблема с поиском класса Map для обобщенного элемента указанного класса.В конкретных терминах я хочу что-то вроде этого (нет, T нигде не объявлен).

private Map<Class<T>, ServiceLoader<T>> loaders = Maps.newHashMap();

Короче говоря, я хочу, чтобы loaders.put / get имел семантику примерно такую:

<T> ServiceLoader<T> get(Class<T> klass) {...}
<T> void put(Class<T> klass, ServiceLoader<T> loader) {...}

Это лучшее, что я могу сделать?Должен ли я жить с неизбежным @SuppressWarnings("unchecked") где-нибудь в будущем?

private Map<Class<?>, ServiceLoader<?>> loaders = Maps.newHashMap();

Ответы [ 2 ]

6 голосов
/ 06 апреля 2010

Дайте мне посмотреть, если у вас есть намерение: вам нужна карта, в которой хранятся пары Class / ServiceLoader, где каждая пара параметризована одинаковыми T, но T может отличаться для разных пар? 1005 *

Если это так, то лучшим решением будет объявить свой собственный класс, который будет иметь такой интерфейс. Внутренне он будет хранить эти пары в общей карте Map<Class<?>,ServiceLoader<?>>.

public class MyMap {
   private Map<Class<?>, ServiceLoader<?>> loaders 
      = new HashMaps<Class<?>, ServiceLoader<?>>();

   public<T> void put(Class<T> key, ServiceLoader<T> value) {
      loaders.put(key, value);
   }

   @SuppressWarnings("unchecked")
   public<T> T get(Class<T> key) { return (ServiceLoader<T>) loaders.get(key); }
}

@SuppressWarnings("unchecked") аннотации не являются чистым злом. Вы должны стараться избегать их, но есть определенные случаи, когда вы можете выяснить, что приведение правильное, несмотря на тот факт, что компилятор этого не видит.

0 голосов
/ 06 апреля 2010

Мое предложение - создать новый объект для такого случая. Я вижу, вы использовали Maps.newHashMap(), так что я понял, что вы использовали Google Guava, поэтому я буду использовать ForwardingMap.

public class Loader<T> extends ForwardingMap<Class<T>, ServiceLoader<T>> {

   private Map<Class<T>, ServiceLoader<T>> delegate = Maps.newHashMap();

}

Простой тест подтвердил, что мое предложение работает:

public class Loader<T> extends ForwardingMap<Class<T>, Class<T>> {

   private Map<Class<T>, Class<T>> delegate = Maps.newHashMap();

   @Override protected Map<Class<T>, Class<T>> delegate() {
      return delegate;
   }

   public static void main(String[] args) {
      Loader<Integer> l = new Loader<Integer>();

      l.put(Integer.class, Integer.class);

      // error
      l.put(Integer.class, String.class);
   }

}
...