gpt4 book ai didi

java - 为什么 HashSet 没有稳定的序列化?

转载 作者:行者123 更新时间:2023-12-04 18:00:29 26 4
gpt4 key购买 nike

拿个 HashSet在 java 。在里面放一根绳子。序列化它。你最终得到了一些字节 - bytesA .

bytesA ,将其反序列化为 Object - fromBytes .

现在重新序列化 fromBytes你得到了另一个字节数组 - bytesB .

奇怪的是,这两个字节数组并不相等。一字节不一样!为什么?
有趣的是,这不会影响 TreeSetHashMap .但是它确实会影响 LinkedHashSet .

Set<String> stringSet = new HashSet<>();
stringSet.add("aaaaaaaaaa");

//Serialize it
byte[] bytesA;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(stringSet);
out.flush();
bytesA = bos.toByteArray();
}

// Deserialize it
Object fromBytes;
try (ByteArrayInputStream is = new ByteArrayInputStream(bytesA)) {
try(ObjectInputStream ois = new ObjectInputStream(is)) {
fromBytes = ois.readObject();
}
}

//Serialize it.
byte[] bytesB;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(fromBytes);
out.flush();
bytesB = bos.toByteArray();
}

assert Arrays.equals(bytesA, bytesB);

//array contents differ at index [43], expected: <16> but was: <2>

如果这些有帮助: xxd bytesA 的十六进制转储
00000000: aced 0005 7372 0011 6a61 7661 2e75 7469  ....sr..java.uti
00000010: 6c2e 4861 7368 5365 74ba 4485 9596 b8b7 l.HashSet.D.....
00000020: 3403 0000 7870 770c 0000 0010 3f40 0000 4...xpw.....?@..
00000030: 0000 0001 7400 0a61 6161 6161 6161 6161 ....t..aaaaaaaaa
00000040: 6178 ax
xxd bytesB 的十六进制转储
00000000: aced 0005 7372 0011 6a61 7661 2e75 7469  ....sr..java.uti
00000010: 6c2e 4861 7368 5365 74ba 4485 9596 b8b7 l.HashSet.D.....
00000020: 3403 0000 7870 770c 0000 0002 3f40 0000 4...xpw.....?@..
00000030: 0000 0001 7400 0a61 6161 6161 6161 6161 ....t..aaaaaaaaa
00000040: 6178 ax

第 3 行第 6 列是差异。

我在 Java 11.0.3 上。

(解决)

根据 Alex R 的回应 - 发生的情况是 HashSet 的 writeObject 存储了 capacity , loadFactor , 和 size靠背 HashMap ,但它的 readObject重新计算容量为:

capacity = (int)Math.min((float)size * Math.min(1.0F / loadFactor, 4.0F), 1.07374182E9F);

除了健全性检查之外,它实际上忽略了 capacity最初存储的值!

最佳答案

如果您创建一个 HashSet使用构造函数它创建一个 HashMap默认大小为 16。

如果您反序列化它,如果您的集合包含较少的条目,则大小可能会被初始化为小于 16。在这种情况下会发生这种情况。

看看readObject HashSet 的实现查看大小是如何计算的。

打印两个字节数组会给你一个提示,这确实发生了:

[..., 16, ...]
[..., 2,...]

关于java - 为什么 HashSet 没有稳定的序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58550197/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com