2013-07-05 2 views
7

Непосредственно из this Java документ:Карта содержит в себе значение;

Особый случай этого запрета является то, что это не допустимо для карты содержат себя в качестве ключа. Хотя допустимо, чтобы карта содержала себя в качестве значения, следует проявлять особую осторожность: равные и методы hashCode более не определены на такой карте.

Почему хэш-код и не будет более точно определен на такой карте?

Заранее спасибо.

+2

Если я правильно помню, метод equals проверяет, содержит ли содержимое карт равны. и это делается с использованием метода equals содержимого, то есть самого отображения. Я уверен, что мы закончили с StackOverflowError –

+0

Можете ли вы выглядеть так, как выглядит карта? возможно, это вызовет бесконечный цикл? Просто мысль – Kevin

+0

@MarcoForberg Если я правильно помню, лучше всего проверить, действительно ли объект, с которым вы сравниваете, на самом деле, и сразу же верните истину, если это так. –

ответ

2

Полная цитата абзац из Java Документов:

Примечание: большого внимания должно быть осуществлено, если изменяемые объекты используются в качестве ключей карты , Поведение карты не указывается, если значение объекта изменяется таким образом, который влияет на равные сравнения, пока объект является ключом на карте. Особый случай этого запрета заключается в том, что карта не может содержать себя как ключ.Хотя допустимо, чтобы карта содержала себя как значение, рекомендуется проявлять особую осторожность: методы 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); 

Как человек, мы можем видеть ma и mc равны по определению. На обеих картах компьютер увидит две карты на mb (пустую карту), что хорошо. Он увидит 1 карту на другой карте как в mc, так и в ma. Он проверяет, равны ли эти карты. Чтобы определить это, он проверяет снова, если два значения для 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) return true; ** Я думаю, что это предотвратит цикл infinate, поскольку он немедленно вернется и никогда не выполнит выделенный вами код. –

+0

Черт возьми, вы правы. Ответ должен быть немаркирован. Может быть, это потому, что это так зависит от реализации, что они не определили его, не рекомендую. – ssindelar

+0

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

0

Чтобы попытаться объяснить:

Равных метод перебрать и карты и вызвать метод Equals каждого ключа и значения карты. Итак, если карта содержит себя, вы будете бесконечно называть метод equals.

То же самое происходит с хеш-кодом.

Источник: исходный код класса AbstractMap

Смежные вопросы