Java HashMap не может найти ключ из события ListDataListener - PullRequest
0 голосов
/ 13 марта 2011

Может кто-нибудь объяснить, почему HashMap действует так, как в этом примере:
Простой тест, который проверяет хеш-карту на ключ.Один раз в конструкторе и один раз в методе ListDataListener intervallAdded.

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

import com.jgoodies.common.collect.ArrayListModel;

public class Test1 {

  private final Listener listener = new Listener();
  private final Map<List<?>, Object> parentByCollection = new HashMap<List<?>, Object>();

  public Test1(){
    ArrayListModel<Object> list = new ArrayListModel<Object>();

    list.addListDataListener(listener);

    parentByCollection.put(list, new Integer(10));

    // Test containsKey locally
    System.out.println("Item exists (locally):" + parentByCollection.containsKey(list));

    // Test containsKey via ListDataListener
    list.add(new Integer(20));
  }

  /**
   * @param args
   */
  public static void main(String[] args) {
    new Test1();
  }

  public class Listener implements ListDataListener{

    @Override
    public void intervalAdded(ListDataEvent e) {
      List<?> itemSource = (List<?>)e.getSource();

      System.out.println("Item exists (listener):" + parentByCollection.containsKey(itemSource));      
    }

    @Override
    public void intervalRemoved(ListDataEvent e) {
    }

    @Override
    public void contentsChanged(ListDataEvent e) {
    }
  }
}

Почему hashmap возвращает false из события, но true из конструктора при использовании containsKey?Есть ли какая-нибудь "магия" java-generics, о которой я не знаю?

Редактировать:

Только что обнаружили, что метод hashCode ArrayList (который расширяет ArrayListModel) собирает свой хеш-код из всех своих элементов.Это означает, что hashCode изменяется с элементами в списке.Поэтому хранить ArrayList в HashMap не очень хорошая идея.

Как я могу решить эту проблему?Вместо этого сохраните коллекции в объекте-держателе / ​​контейнере?

Ответы [ 2 ]

2 голосов
/ 13 марта 2011

Я знаю, что вы понимаете проблему сейчас, но вот объяснение для других людей:

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

Глядя на javadoc метода хеширования List, объясняется, что хеш-код списка зависит от содержащихся элементов, чтобы соблюдать договор между хеш-кодом и равенством.

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

Решение в этом случае заключается в использовании ссылки, этоне изменяется при добавлении или удалении элементов из списка.Но клон списка (равный ему) не будет работать!

0 голосов
/ 13 марта 2011

Проблема была совершенно очевидна, когда я просматривал источники. Решение для хранения коллекций на карте - НЕ использовать HashMap, а вместо этого использовать карту, основанную на ссылках, таких как Apache Commons ReferenceIdentityMap или java.util.IdentityHashMap.

...