使用键作为字符串序列化和反序列化映射

Gra*_*e K 19 java serialization

我打算序列化和反序列化其键是字符串的hashmap.

从Josh Bloch的Effective Java,我理解以下内容.第222页

例如,考虑哈希表的情况.物理表示是包含键值条目的一系列散列桶.放入条目的哪个桶是密钥的哈希码的函数,通常保证从JVM实现到JVM实现不相同.事实上,从运行到同一JVM实现运行甚至不保证是相同的.因此,接受哈希表的默认序列化表单将构成严重错误.序列化和反序列化哈希表可能会产生一个不变量严重损坏的对象.

我的问题是:1)一般来说,覆盖地图的关键类的等于和哈希码会解决这个问题并且地图可以正确恢复吗?

2)如果我的键是一个String并且String类已经覆盖了hashCode()方法,我是否还会遇到上述问题.(我看到一个错误,让我觉得这可能仍然是一个问题,即使键是重写hashCode的String.)

3)以前,我通过序列化一系列条目(键,值)解决了这个问题,并且在反序列化时我会重建地图.我想知道是否有更好的方法.

4)如果问题1和2的答案仍然无法保证,有人可以解释原因吗?如果hashCodes是相同的,他们会跨JVM转到相同的存储区吗?

谢谢,格雷斯

mdm*_*dma 23

序列化形式java.util.HashMap不会自动序列化桶,并且哈希码不是持久状态的一部分.来自javadocs:

串行数据:HashMap中(桶阵列的长度)的容量被发射(INT),随后的HashMap(键-值映射关系数)的大小,接着通过键(对象)和值(对象)对于由HashMap表示的每个键值映射,键值映射按它们返回的顺序发出entrySet().iterator().

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

持久状态基本上包括键和值以及一些内务处理.反序列化时,完全重建了hashmap; 将密钥重新放置并放置在适当的桶中.

因此,添加String键应该可以正常工作.我猜你的错误在其他地方.

编辑:这是一个junit 4测试用例,用于序列化和反序列化一个映射,以及minics VMs更改哈希码.尽管反序列化后的哈希码不同,但测试仍然通过.

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

}
Run Code Online (Sandbox Code Playgroud)


Yis*_*hai 6

我99%确定HashMap和HashSet的JVM实现处理这个问题.他们有自定义序列化和反序列化处理程序.我现在面前没有Bloch的书,但我相信他正在解释这个挑战,而不是说你无法在实践中可靠地序列化java.util.HashMap.


小智 6

要序列化hashmap:

我试过这个并在我的应用程序中使用它工作正常.根据您的需要制作此代码的功能.

public static void main(String arr[])
{
    Map<String,String> hashmap=new HashMap<String,String>();
    hashmap.put("key1","value1");
    hashmap.put("key2","value2");
    hashmap.put("key3","value3");
    hashmap.put("key4","value4");

    FileOutputStream fos;
    try {
        fos = new FileOutputStream("c://list.ser");

        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(hashmap);
        oos.close();

        FileInputStream fis = new FileInputStream("c://list.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Map<String,String> anotherList = (Map<String,String>) ois.readObject();

        ois.close();

        System.out.println(anotherList);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}
Run Code Online (Sandbox Code Playgroud)