首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么指定Map的初始容量会导致随后的序列化产生不同的结果?

为什么指定Map的初始容量会导致随后的序列化产生不同的结果?
EN

Stack Overflow用户
提问于 2016-07-28 11:43:24
回答 1查看 50关注 0票数 3

我试图比较两个byte[],它们是同一个对象序列化的结果:

  • 1 byte[]是通过序列化对象来创建的。
  • 另一个方法是反序列化第一个byte[],然后再序列化它。

我不明白这两个数组是如何不同的。反序列化第一个byte[]应该重构原始对象,而序列化该对象与序列化原始对象相同。因此,2 byte[]应该是相同的。然而,在某些情况下,它们显然是不同的。

我正在序列化的对象(State)包含另一个对象(MapWrapper)的列表,而该对象又包含一个集合。根据集合的不同,我从比较代码中得到不同的结果。

这是MCVE:

代码语言:javascript
复制
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {

    public static void main(String[] args) {

        State state = new State();
        state.maps.add(new MapWrapper());

        byte[] pBA = stateToByteArray(state);
        State pC = byteArrayToState(pBA);
        byte[] zero = stateToByteArray(pC);
        System.out.println(Arrays.equals(pBA, zero)); // see output below
        State pC2 = byteArrayToState(pBA);
        byte[] zero2 = stateToByteArray(pC2);
        System.out.println(Arrays.equals(zero2, zero)); // always true
    }

    public static byte[] stateToByteArray(State s) {

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(s);
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static State byteArrayToState(byte[] bytes) {

        ObjectInputStream ois;
        try {
            ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
            return (State) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

class State implements Serializable {

    private static final long serialVersionUID = 1L;

    List<MapWrapper> maps = new ArrayList<>();
}

class MapWrapper implements Serializable {

    private static final long serialVersionUID = 1L;

    // Different options, choose one!
//  List<Integer> ints = new ArrayList<>();       true
//  List<Integer> ints = new ArrayList<>(3);      true
//  Map<String, Integer> map = new HashMap<>();   true
//  Map<String, Integer> map = new HashMap<>(2);  false
}

由于某些原因,如果MapWrapper包含一个HashMap (或LinkedHashMap),并且是用初始容量初始化的,那么序列化会给出一个与序列化反序列化不同的结果。

我添加了反序列化的第二次迭代,并与第一次进行了比较。他们总是平等的。这种差异仅在第一次迭代之后才会显示出来。

请注意,我必须创建一个MapWrapper并将其添加到State中的列表中,就像在main开始时所做的那样,从而导致这种情况。

据我所知,初始容量只是一个性能参数。使用默认的或指定的不应更改行为或功能。

我正在使用jdk1.8.0_25和Windows7。

这一切为什么要发生?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-28 11:57:18

readObject中的以下行和注释解释了两者之间的区别:

代码语言:javascript
复制
s.readInt();                // Read and ignore number of buckets

实际上,查看字节的十六进制,差别在于数字2(配置的桶数)和数字16 (默认的桶数)。我没有检查过这个特定字节的意思,但是如果它是其他的东西,那将是一个巧合,因为这是唯一的区别。

代码语言:javascript
复制
<snip> 08 00 00 00 02 00 00 00 00 78 78   // Original
<snip> 08 00 00 00 10 00 00 00 00 78 78   // Deserialized+serialized.
                   ^
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38635375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档