2011-03-13 7 views
0

HashMap이이 예제에서와 같이 작동하는 이유를 설명 할 수 있습니까?
해시 맵에서 키를 확인하는 간단한 테스트입니다. 한 번은 생성자에, 한 번은 ListDataListener intervallAdded 메서드에 있습니다.Java HashMap이 ListDataListener 이벤트에서 키를 찾을 수 없습니다.

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) { 
    } 
    } 
} 

왜 해시 맵은 이벤트에서 false를 반환하지만 containsKey를 사용할 때 생성자에서 true를 반환합니까? 일부 Java 제네릭 "마법"이 있습니까? 여기에 대해서는 모르겠습니까?

편집 :

그냥 ArrayList를의 (ArrayListModel의 연장) hashCode 메소드는 모든 요소에서의 해시 코드를 조립 것을 발견했다. 즉, 목록의 항목에 따라 hashCode가 변경됩니다. HashMap에 ArrayList를 저장하는 것은 좋은 생각이 아닙니다.

어떻게 해결할 수 있습니까? 컬렉션을 홀더/컨테이너 객체에 대신 저장 하시겠습니까?

+2

'com.jgoodies.common.collect.ArrayListModel'에 대해 hashCode() 메소드 구현을 제공하십시오. –

+1

소스는 http://www.jgoodies.com/downloads/libraries.html에서 찾을 수 있습니다. ArrayListModel은 ArrayList를 확장하며 hashCode를 재정의하지 않으므로 ArrayList의 hashCode가 사용 된 것입니다. 하지만 그게 어떻게 관련이 있는지 알 수는 없지만 containsKey에 대한 첫 번째 호출은 true를 반환합니다. – Marcus

답변

2

나는 당신이 지금 문제를 이해 알고 있지만, 여기에 다른 사람에 대한 설명입니다 :

해시 맵이 경우 목록의 해시 코드 인 키의 해시 코드를 사용합니다.

List의 hashcode 메소드의 javadoc을 보면 목록의 해시 코드는 해시 코드와 동등성 간의 계약을 존중하기 위해 포함 된 요소에 따라 달라진다는 것을 설명합니다.

등식 변경으로 인해 목록이 수정되면 해시 코드가 변경되어 Hashmap에서 초기 목록을 검색 할 수 없게됩니다.

이 경우 솔루션은 참조를 사용하는 것으로, 요소가 목록에 추가되거나 제거 될 때 변경되지 않습니다. 그러나 목록의 복제본 (하나의 복제본)은 작동하지 않습니다!

0

소스를 살펴볼 때 문제가 아주 분명했습니다. 지도에 콜렉션을 저장하는 솔루션은 HashMap을 사용하지 않고, 대신 아파치 공유 ReferenceIdentityMap 또는 java.util.IdentityHashMap과 같은 참조를 기반으로 한 맵을 사용하는 것입니다.

+0

또는 hashCode 메소드를 다시 구현하십시오. –

+0

물론 해결책이기도합니다. 그러나 키에 대한 참조 평등과 함께 작동하는 Map을 사용하는 것이 훨씬 더 깔끔한 솔루션입니다. – Marcus

+0

더 깨끗한 해결책은 목록을 키의 키로 사용하지 않는 것입니다. –

관련 문제