Проблема с картами в Java - PullRequest
       31

Проблема с картами в Java

2 голосов
/ 06 августа 2011

У меня есть Hashmap с числом элементов X
Мне нужно переместить эту карту в другую карту
Вот как выглядит мой код

Map originMap = initialize();
Map destMap = new Hashmap ();  

int originMapSize = originMap.size(); 
Set<Map.Entry<K, V>> entries = originMap.entrySet();
for (Map.Entry<K, Y> mapEntry : entries) {
 K key = mapEntry.getKey();
 V value = mapEntry.getValue();
 destMap.put (key,value);
}  

// Shouldnt this be equal to originMapSize ????
int destMapSize = destMap.size();

То, что я наблюдаю, - originMapSize НЕ равно destMapSize

Кажется, когда мы помещаем элементы в destMap, некоторые элементы переопределяются

Мы переопределили метод hashCode и equals, и это подозрительная реализация.
Однако, если originMap разрешает добавление элементов, почему destinationMap не добавляет новые элементы и не переопределяет существующий элемент?

Ответы [ 6 ]

8 голосов
/ 06 августа 2011

Это может произойти, если метод equals был асимметричным.Предположим, есть два ключа a и b, такие что:

  • a.hashCode() == b.hashCode()
  • a.equals(b) возвращает false
  • b.equals(a) возвращает true

Затем предположим, что реализация HashMap ищет существующий ключ, вызывая existingKey.equals(newKey) для каждого существующего ключа с таким же хеш-кодом, что и у нового ключа.

Теперь предположим, что мы первоначально добавили их вorder {a, b}.

Первый ключ (a), очевидно, входит без проблем.Вставка второго ключа (b) в итоге вызывает a.equals(b) - это ложь, поэтому мы получаем два ключа.

Теперь, создав второй HashMap, мы можем получить записи в заказе{b, a}.

На этот раз мы сначала добавляем b, что нормально ... но когда мы вставляем второй ключ (a), мы в итоге вызываем b.equals(a), который возвращает trueтаким образом, мы перезаписываем запись.

Возможно, это не то, что происходит, но это может объяснить вещи - и показывает опасности асимметричного equals метода.

РЕДАКТИРОВАТЬ: Вот короткая, но полная программа, демонстрирующая эту ситуацию.(Точные данные a и b могут не совпадать, но асимметрия такая.)

import java.util.*;

public class Test {

    private final String name;

    public Test(String name)
    {
        this.name = name;
    }

    public static void main(String[] args)
    {
        Map<Test, String> firstMap = new HashMap<Test, String>();

        Test a = new Test("a");
        Test b = new Test("b");

        firstMap.put(b, "b");
        firstMap.put(a, "a");

        Map<Test, String> secondMap = new HashMap<Test, String>();
        for (Map.Entry<Test, String> entry : firstMap.entrySet())
        {
            System.out.println("Adding " + entry.getKey().name);
            secondMap.put(entry.getKey(), entry.getValue());
        }
        System.out.println(secondMap.size());
    }

    @Override public int hashCode()
    {
        return 0;
    }

    @Override public boolean equals(Object other)
    {
        return this.name.equals("b");
    }
}

Вывод на мою машину:

Adding a
Adding b
1

Вы не можетеполучить результат в обратном порядке - это зависит от:

  • Способ, которым вызывается equals (candidateKey.equals(newKey) или наоборот)
  • Порядок, в котором записи возвращаются изнабор

Может даже работать по-разному на разных прогонах.

0 голосов
/ 06 августа 2011

Зависит от того, как инициализируется первая HashMap. Также каждый раз, когда вы добавляете объект в HashMap, после того, как он проходит коэффициент загрузки 75%, он выделяет в два раза больше размера по умолчанию для размещения новых значений. Карты обычно имеют размер по умолчанию = 16: при превышении коэффициента загрузки 75% он увеличивается до 32.

0 голосов
/ 06 августа 2011

Карта имеет метод putAll .Попробуйте что-то вроде этого:

    Map<String, String> destination = new HashMap<String, String>();
    Map<String, String> original = new HashMap<String, String>();

    destination.putAll(original);
0 голосов
/ 06 августа 2011

Почему бы вам не использовать destMap.putAll (originMap)?

0 голосов
/ 06 августа 2011

Я подозреваю, что порядок элементов, добавляемых к первому hashmap, не совпадает с порядком, добавленным ко второму.В сочетании с методом sketchy hashCode это приводит к добавлению дубликатов к первому.

Попробуйте изменить hashCode так, чтобы он всегда возвращал одно и то же значение, чтобы увидеть, исчезнет ли ваша проблема.

0 голосов
/ 06 августа 2011

Эти значения должны быть равны, но проблема в том, что вы перебираете другой объект Map.

for (Map.Entry mapEntry : entries)

не совпадает с

for (Map.Entry mapEntry : originMap)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...