Общие Фабрики и Значения Карты - PullRequest
1 голос
/ 21 сентября 2009

У меня есть класс с Map с от K с до Set<V> с, для нескольких разных V с. Я хотел бы использовать общий заводской ала:

protected static <T> Set<T> SetFactory(int size) {
        return new HashSet<T>(size);
}

сделать что-то вроде

for (K key : keySet) map.put(key, SetFactory());

и работают с общей частью (я получаю ошибку компиляции, несоответствие типов между Set<Object> и Set<V>), как это происходит с Set<V> x = SetFactory();

Существуют ли альтернативы для передачи аргумента Class<V> в SetFactory()?

Ответы [ 5 ]

2 голосов
/ 21 сентября 2009

Я не очень понимаю вашу проблему. Это то, что вы ищете?

class MyClass {

  protected static <T> Set<T> SetFactory(int size)
  {
    return new HashSet<T>(size);
  }

  protected static <K, V> Map<K, Set<V>> mapFactory(Collection<K> keys)
  {
    Map<K, Set<V>> result = new HashMap<K, Set<V>>(keys.size());
    for (K key : keys)
      result.put(key, MyClass.<V>SetFactory(20));
    return result;
  }

}

Обратите внимание на явный параметр типа (<V>) при вызове универсального метода.


Обновление:

Я, наверное, ошибаюсь, но констатирую не актерский состав кажется мне семантикой - необходимость поставить MyClass. на фронте кажется довольно близко к необходимости бросать. Можете ли вы объяснить разницу?

Приведение было бы (Set<V>) SetFactory(20), и оно генерировало бы предупреждение компилятора о безопасности типов, потому что при стирании типов нет способа проверить, что тип времени выполнения результата функции SetFactory имеет тип V.

Использование параметра типа в вызове метода очень похоже на выражение new HashSet<V>(). Когда вы вызываете конструктор универсального класса, вы должны указать аргументы типа для конструктора. Всякий раз, когда вы вызываете универсальный метод, должны быть указаны параметры типа. Зачастую они могут быть получены из присвоения результата метода или из параметров метода, но не всегда.

Однако это не актерский состав. Приведение всегда выполняет проверку типа во время выполнения. Указание универсального типа, как я показываю здесь, работает во время компиляции.

0 голосов
/ 21 сентября 2009

Хм, на самом деле это, кажется, работает:

protected static <K,V> Map<K,Set<V>> mapFactory(Collection<K> keys) {
    Set<V> holder;
    Map<K,Set<V>> result = new HashMap<K,Set<V>>(keys.size());
    for (K key : keys) result.put(key, holder = SetFactory());
    return result;
}

и даже выводит меня из себя из-за того, что мне пришлось изначально выделять карту. Я полагаю, мне нужно добавить фабрику в список аргументов, если я действительно хочу переопределить класс.

0 голосов
/ 21 сентября 2009

Коллекции Apache Commons предоставляют LazyMap , в котором вы предоставляете объект Factory , который создает значения карты. Вы можете предоставить Фабрику, которая создает ваши значения Set.

Теперь, Commons Collections не использует дженерики, но есть универсальный порт для этого здесь .

Надеюсь, я правильно истолковал ваш вопрос - он был довольно запутанным.

0 голосов
/ 21 сентября 2009

Если вам абсолютно необходимо, чтобы это было в одной строке, вы можете поместить в пут бинарное задание:

 Set<V> s = null;
 for (K key : keySet) map.put(key, s = setFactory());

Но этот ответ больше для того, чтобы показать другой способ сделать это, но не предполагать, что это лучший способ.

0 голосов
/ 21 сентября 2009

Вам нужно явное назначение:

for (K key : keySet) {
  Set<V> mySet = setFactory(20);
  map.put(key, mySet);
}

Без этого компилятор не сможет узнать тип <V>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...