2013-07-05 3 views
7

직접 this 자바 문서에서 :값으로 containig 자체를 매핑하십시오.

이 금지 특별한 경우가 지도가 그것 자신을 키로서 가지지 못하는 것을들 수 있습니다. 에 대한지도 자체가 값으로 포함될 수는 있지만 극단적 인주의를 권고합니다. equals 및 hashCode 메소드는 더 이상 그러한지도에서 잘 정의되지 않습니다.

왜 해시 코드와 같음이 더 이상 그러한지도에 잘 정의되어 있지 않습니까?

미리 감사드립니다.

+2

맵의 내용 같다. 이는 내용의 equals 메소드, 즉지도 자체를 사용하여 수행됩니다. 나는 우리가 StackOverflowError로 끝날 것이라고 확신한다. –

+0

지도가 함수 같아 보이는가? 어쩌면 무한 루프가 생길지 모릅니다. 그냥 생각해 보렴 – Kevin

+0

@MarcoForberg 만약 내가 올바르게 기억하고 있다면, 비교 대상이 실제로 자신인지 그리고 만약 그렇다면 즉시 반환 하는지를 확인하는 것이 가장 좋은 방법이다. –

답변

2

자바 문서에서 단락의 전체 인용은 다음과 같습니다

주 : 가변 객체가 맵의 키로서 사용하는 경우 큰주의를 기울여야한다 . 오브젝트가 맵의 키인 동안 equals 비교에 영향을주는 방식으로 오브젝트의 값이 변경되면 맵의 작동은 지정되지 않습니다.이 금지 사항의 특수한 경우는 맵이 자체를 키로 포함하는 것이 허용되지 않는다는 것입니다.맵 자체를 값으로 포함하는 것은 허용되지만 극도의주의를 권고합니다. equals 및 hashCode 메소드는 더 이상 그러한 맵에서 잘 정의되지 않습니다.

AbstractMap.hashCode() 메소드는지도에서 키 값 쌍의 해시 코드를 사용하여 해시 코드를 계산합니다. 따라서이 메소드에서 생성 된 해시 코드는 맵이 수정 될 때마다 변경됩니다.

해시 코드는 버킷을 계산하여 새 항목을 배치하는 데 사용됩니다. 맵이 그 자체의 키로 사용 되었다면 계산 된 버킷은 새로운 엔트리가 업데이트/제거/수정 될 때마다 다를 것입니다. 따라서지도를 키로 사용하여 향후 조회하는 경우 해시 코드에서 differnt 버킷을 계산하기 때문에 실패 할 가능성이 큽니다. 미래 puts는 키가 이미 맵에 존재하는지 감지하지 못하고 동일한 키 (그러나 버킷이 다른)가 여러 개인 항목을 허용하지 않을 수 있습니다.

1

같은 키가 동일한 값을 매핑하면 두 개의 맵이 동일합니다. (일부 구현에서는) 그렇기 때문에 평등을 확인하기 위해 모든 구성원의 평등을 확인해야합니다.

따라서지도에 자체가 포함되어 있으면 무한대의 동일성 검사 재귀가 발생합니다.

맵의 요소 해시에 따라 계산할 수 있기 때문에 해시도 마찬가지입니다.

예 : 인간으로

Map<Int, Object> ma; 
Map<Int, Object> mb; 
Map<Int, Object> mc; 

ma.put(1, ma); 
ma.put(2, mb); 
mc.put(1, ma); 
mc.put(2, mb); 

, 우리 mamc이 정의에서 동일하다 볼 수있다. 컴퓨터는 두 맵에서 mb (빈 맵)에 2 개의 맵을 볼 수 있습니다. mc와 ma 모두에서 다른지도에 1 개의지도가 표시됩니다. 이 맵이 동일한 지 확인합니다. 이를 판별하기 위해 1의 두 값이 같으면 다시 검사합니다. 그리고 다시.

모든 구현에 해당하지 않습니다. 어떤 구현은 객체가 저장된 메모리의 위치에서 평등을 검사 할 수 있습니다 ... 그러나 모든 반복 검사는 무한 반복됩니다. 가장 맵 구현으로 사용된다

5

관련 부분 폼 AbstractMap.equals :

  Iterator<Entry<K,V>> i = entrySet().iterator(); 
      while (i.hasNext()) { 
       Entry<K,V> e = i.next(); 
       K key = e.getKey(); 
       V value = e.getValue(); 
       if (value == null) { 
        if (!(m.get(key)==null && m.containsKey(key))) 
         return false; 
       } else { 
        if (!value.equals(m.get(key))) // would call equals on itself. 
         return false; 
       } 
      } 

값으로 맵을 추가 무한 루프가 발생할 것이다.

+1

equals() 메소드의 첫 번째 명령문은 ** if (o == this)가 true를 리턴한다 ** 나는 이것이 즉시 반환하고 당신이 강조한 코드를 실행하지 않기 때문에 이것이 무한 루프를 막을 것이라고 생각한다. –

+0

젠장, 네 말이 맞아. 답변에 표시가되어 있지 않아야합니다. 어쩌면 그것이 구현에 의존적이기 때문에 그것이 그것을 권장하지 않는다고 정의하지 않았기 때문일 수도 있습니다. – ssindelar

+0

두 맵을 작성하고 하나의 맵을 다른 맵에 넣고 다른 맵을 매개 변수로 사용하여 하나의 맵에서 equals를 호출하여 문제점을 작성할 수 있습니다. 또는 하나의 맵을 그 자체에 넣고 hashcode()를 호출하면됩니다. –

0

을 설명하려고합니다 :

이 방법을 통해지도 모두를 반복하고지도의 각 키와 값의 equals 메소드를 호출합니다 같습니다. 따라서지도 자체가 포함되어 있으면 equals 메서드를 계속 무기로 호출합니다.

동일한 문제가 해시 코드에서 발생합니다.

출처 : 클래스의 소스 코드를 AbstractMap

관련 문제