Сериализация и десериализация карты с ключом как строка

Я намереваюсь сериализировать и десериализовать hashmap, ключ которого является строкой.

От Эффективного Java Josh Bloch я понимаю следующее. P.222

Например, рассмотрите случай хеш-таблицы. Физическое представление является последовательностью блоков хеша, содержащих записи значения ключа. То, которые объединяют запись в блок, помещается в, функция хэш-кода ключа, который не является, в целом гарантирован быть тем же от реализации JVM до реализации JVM. На самом деле это, как даже гарантируют, не будет тем же от выполненного для работы той же реализации JVM. Поэтому принятие сериализированной формы значения по умолчанию для хеш-таблицы составит серьезную ошибку. Сериализация и десериализация хеш-таблицы могли привести к объекту, инварианты которого были серьезно повреждены.

Мои вопросы: 1) В целом, был бы, переопределяя равняться, и хэш-код ключевого класса карты решают этот вопрос, и карта может быть правильно восстановлена?

2) Если моим ключом является Строка, и Строковый класс уже переопределяет хэш-код () метод, был бы я все еще описывать проблему выше. (Я вижу ошибку, которая заставляет меня думать, что это - вероятно, все еще проблема даже при том, что ключ является Строкой с переопределением хэш-кода.)

3) Ранее, я обошел эту проблему путем сериализации массива записей (ключ, значение), и при десериализации я восстановлю карту. Я задаюсь вопросом, существует ли лучший подход.

4) Если ответы на вопрос 1 и 2 - то, что он все еще не может быть гарантирован, кто-то мог объяснить почему? Если бы хэш-коды являются тем же, они перешли бы к тем же блокам через JVMs?

Спасибо, изящество

19
задан Neel 17 April 2012 в 22:31
поделиться

4 ответа

Форма сериализации java.util.HashMap не сериализует сами сегменты, и хэш-код не является частью постоянного состояния. Из javadocs:

Последовательные данные: Емкость HashMap (длина массива сегментов) выдается (int), за которым следует размер HashMap (количество сопоставлений "ключ-значение" ), за которым следуют ключ (объект) и значение (объект) для каждого сопоставления "ключ-значение" , представленного {{1 }} HashMap Сопоставления "ключ-значение" генерируются в том порядке, в котором они возвращаются entrySet (). Iterator () .

из http://java.sun.com/j2se/1.5.0/docs/api/serialized-form.html#java.util.HashMap

Постоянное состояние в основном состоит из ключей и значений. и немного домашнего хозяйства. При десериализации хэш-карта полностью перестраивается; ключи перефразируются и помещаются в соответствующие корзины.

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

РЕДАКТИРОВАТЬ: Вот тестовый пример junit 4, который сериализует и десериализует карту, а виртуальные машины minics меняют хэш-коды. Тест проходит, несмотря на то, что после десериализации хэш-коды отличаются.

import org.junit.Assert;
import org.junit.Test;

import java.io.*;
import java.util.HashMap;

public class HashMapTest
{
    @Test
    public void testHashMapSerialization() throws IOException, ClassNotFoundException
    {
        HashMap map = new HashMap();
        map.put(new Key("abc"), 1);
        map.put(new Key("def"), 2);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(out);
        objOut.writeObject(map);
        objOut.close();
        Key.xor = 0x7555AAAA; // make the hashcodes different
        ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
        HashMap actual = (HashMap) objIn.readObject();
        // now try to get a value
        Assert.assertEquals(2, actual.get(new Key("def")));
    }

    static class Key implements Serializable
    {
        private String  keyString;
        static int xor = 0;

        Key(String keyString)
        {
            this.keyString = keyString;
        }

        @Override
        public int hashCode()
        {
            return keyString.hashCode()^xor;
        }

        @Override
        public boolean equals(Object obj)
        {
            Key otherKey = (Key) obj;
            return keyString.equals(otherKey.keyString);
        }
    }

}
23
ответ дан 30 November 2019 в 03:28
поделиться

Если ничего не помогает, можете ли вы сериализовать свою карту с помощью JSON, YAML, XML или чего-то еще?

1
ответ дан 30 November 2019 в 03:28
поделиться

Я на 99% уверен, что реализация JVM HashMap и HashSet справится с этой проблемой. У них есть собственный обработчик сериализации и десериализации. У меня сейчас нет книги Блоха, но я считаю, что он объясняет проблему, не говоря, что вы не можете надежно сериализовать java.util.HashMap на практике.

6
ответ дан 30 November 2019 в 03:28
поделиться

При использовании правильно реализованной хеш-таблицы (например, java.util.HashMap ) вам не нужно беспокоиться о hashCode () ваших ключей. Техника, упомянутая в пункте 3 исходного сообщения, фактически встроена в хорошую реализацию хеш-таблицы.

Механизм сериализации по умолчанию отменен. Вместо этого сохраняется простой список пар записей (ключ – значение). При десериализации хэш-таблицы метод таблицы put () используется для повторного добавления каждой записи по отдельности. Это поддерживает согласованность нового десериализованного экземпляра хэш-таблицы. Не имеет значения, изменились ли хэш-коды ключей; ведро выбирается на основе хэш-кода ключа во время десериализации.

1
ответ дан 30 November 2019 в 03:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: