使用键作为字符串对地图进行序列化和反序列化 [英] Serializing and deserializing a map with key as string

查看:83
本文介绍了使用键作为字符串对地图进行序列化和反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我打算序列化和反序列化键为字符串的哈希映射.

I am intending to serialize and deserialize a hashmap whose key is a string.

根据Josh Bloch的Effective Java,我了解以下内容. P.222

From Josh Bloch's Effective Java, I understand the following. P.222

例如,考虑哈希表的情况.物理的 表示形式是包含键值的哈希桶序列 条目.条目放置在哪个存储桶中是哈希的函数 密钥的密码(通常不保证相同) 从JVM实施到JVM实施.实际上,甚至没有 确保在同一JVM上运行时是相同的 执行.因此,接受默认的序列化形式 哈希表将构成一个严重的错误.序列化和 将哈希表反序列化可能会产生一个对象,该对象的不变量 严重腐败.

For example, consider the case of a hash table. The physical representation is a sequence of hash buckets containing key-value entries. Which bucket an entry is placed in is a function of the hash code of the key, which is not, in general guaranteed to be the same from JVM implementation to JVM implementation. In fact, it isn't even guaranteed to be the same from run to run on the same JVM implementation. Therefore accepting the default serialized form for a hash table would constitute a serious bug. Serializing and deserializing the hash table could yield an object whose invariants were seriously corrupt.

我的问题是: 1)通常,映射的键类的重载equals和哈希码可以解决此问题,并且可以正确还原映射吗?

My questions are: 1) In general, would overriding equals and hashcode of the key class of the map resolve this issue and the map can be correctly restored?

2)如果我的键是一个String,并且String类已经覆盖了hashCode()方法,我仍然会遇到上述问题. (我看到一个错误,使我认为这可能仍然是一个问题,即使键是具有覆盖hashCode的String.)

2) If my key is a String and the String class is already overriding the hashCode() method, would I still have problem described above. (I am seeing a bug which makes me think this is probably still a problem even though the key is String with overriding hashCode.)

3)以前,我是通过序列化一系列条目(键,值)来解决此问题的,当反序列化时,我将重建映射.我想知道是否有更好的方法.

3)Previously, I got around this issue by serializing an array of entries (key, value) and when deserializing I would reconstruct the map. I am wondering if there is a better approach.

4)如果对问题1和2的回答仍然不能保证,有人可以解释为什么吗?如果hashCode相同,它们是否会跨JVM进入相同的存储桶?

4) If the answers to question 1 and 2 are that it still can't be guaranteed, could someone explain why? If the hashCodes are the same would they go to the same buckets across JVMs?

谢谢,恩典

推荐答案

java.util.HashMap的序列化形式不会序列化存储桶本身,并且哈希码不属于持久状态.来自javadocs:

The serialization form of java.util.HashMap doesn't serialize the buckets themselves, and the hash code is not part of the persisted state. From the javadocs:

串行数据: 发出HashMap的容量(存储桶数组的长度) (int),然后是 HashMap(键值数量 映射),然后按键 (对象)和每个对象的值(对象) 由表示的键值映射 HashMap键值映射为 按照它们的顺序发出 由entrySet().iterator()返回.

Serial Data: The capacity of the HashMap (the length of the bucket array) is emitted (int), followed by the size of the HashMap (the number of key-value mappings), followed by the key (Object) and value (Object) for each key-value mapping represented by the HashMap The key-value mappings are emitted in the order that they are returned by entrySet().iterator().

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

持久状态基本上包括键和值以及一些内部管理.反序列化后,哈希图将完全重建;钥匙被重新整理并放置在适当的存储桶中.

The persisted state basically comprises the keys and values and some housekeeping. When deserialized, the hashmap is completely rebuilt; the keys are rehashed and placed in appropriate buckets.

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

So, adding String keys should work just fine. I would guess your bug lies elsewhere.

这是一个junit 4测试用例,用于对地图进行序列化和反序列化,并且minics VM更改哈希码.尽管哈希序列在反序列化后有所不同,但测试仍通过.

Here's a junit 4 test case that serializes and deserializes a map, and minics VMs changing hashcodes. The test passes, despite the hashcodes being different after deserialization.

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

}

这篇关于使用键作为字符串对地图进行序列化和反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆