为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

繁花不似锦 2023-12-13 15:11:00
以HashSetJava 为例。把一根绳子放进去。将其序列化。你最终会得到一些字节 - bytesA。将bytesA其反序列化为Object- fromBytes。现在重新序列化fromBytes,你就得到了另一个字节数组 - bytesB。奇怪的是,这两个字节数组不相等。一个字节不一样!为什么?有趣的是,这并不影响TreeSet或HashMap。但它确实会影响LinkedHashSet.Set<String> stringSet = new HashSet<>();stringSet.add("aaaaaaaaaa");//Serialize itbyte[] bytesA;try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {  ObjectOutputStream out = new ObjectOutputStream(bos);  out.writeObject(stringSet);  out.flush();  bytesA = bos.toByteArray();}// Deserialize itObject 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十六进制转储bytesA00000000: aced 0005 7372 0011 6a61 7661 2e75 7469  ....sr..java.uti00000010: 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..aaaaaaaaa00000040: 6178                                     axxxd十六进制转储bytesB00000000: aced 0005 7372 0011 6a61 7661 2e75 7469  ....sr..java.uti00000010: 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..aaaaaaaaa00000040: 6178                                     ax第三行第六列是差异。我使用的是 Java 11.0.3。(解决)根据 Alex R 的回应 - HashSet 的 writeObject 存储了backing 的capacity、loadFactor和,但它重新计算了容量:sizeHashMapreadObjectcapacity = (int)Math.min((float)size * Math.min(1.0F / loadFactor, 4.0F), 1.07374182E9F);除了健全性检查之外,它实际上忽略了capacity最初存储的值!
查看完整描述

1 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

HashSet如果使用构造函数创建 a,它会创建HashMap默认大小为 16 的 a。

如果您反序列化它,并且您的集合包含的条目较少,则大小可能会初始化为小于 16。这就是本例中发生的情况。

看一下readObject的实现,HashSet看看大小是如何计算的。

打印两个字节数组会提示您这确实发生了:

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


查看完整回答
反对 回复 2023-12-13
  • 1 回答
  • 0 关注
  • 101 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信