哈希码作为serialVersionUid

3

我在一篇文章中读到,默认的serialVersionUid是JVM提供的对象的哈希码。如果我们没有在类中重写哈希码方法,那么在反序列化期间哈希码将如何被计算呢?因为通常哈希码是对象的内存地址。


我想你是指文章"探索Java序列化API的秘密",其中提到: "您可以使用随JDK发行版一起提供的实用程序serialver,以查看默认情况下该代码会是什么(默认情况下只是对象的哈希码)。" - beatngu13
2个回答

3
我在一篇文章中读到,JVM提供的默认serialVersionUid是一个对象的哈希值。
这是不正确的。(要么是文章有误,要么是你读错了/误解了它。)
可序列化类的默认序列版本UID与hashCode完全无关。
生成默认序列版本UID的算法在这里描述: 基本上,它从类的名称、修饰符、接口名称和字段、构造函数和方法的签名创建一个SHA-1哈希。然后取哈希的前8个字节,并将它们组装成一个long

感谢分享提到生成SUID的方法的链接。然而,它也提到:“如果未为类声明SUID,则该值默认为该类的哈希值。” - Ketan
那个哈希是使用我链接的算法生成的。请再次阅读它。 - Stephen C
Ketan,也许他们应该写“该类的哈希结果”。 - Martin Andersson
@MartinAndersson - 这不是一个哈希结果。这是应用于特定输入集的特定哈希函数的结果。 - Stephen C
我理解了那么多 =) 但还是谢谢你的澄清。 - Martin Andersson

1
我认为你误解了。这不是hashcodeserialVersionUid是静态变量,而hashcode是实例方法,对象的hashcode值因对象而异。 serialVersionUid是根据类的结构(字段、方法等)计算的。它在http://download.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html中有说明,http://download.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100描述了确切的格式。
如果没有提供值,则规范描述了会发生什么,但自动生成使用相同的算法。
流中项目的顺序如下:
  • 类名。

  • 以32位整数表示的类修饰符。

  • 按名称排序的每个接口的名称。

  • 按字段名称排序的每个字段(除了私有静态和私有瞬态字段):

    • 字段名称。
    • 以32位整数表示的字段修饰符。
    • 字段描述符。
  • 如果存在类初始化程序,请写出以下内容:

    • 方法名称“<clinit>”。
    • 方法修饰符java.lang.reflect.Modifier.STATIC,以32位整数表示。
    • 方法描述符“()V”。
  • 按方法名称和签名排序的每个非私有构造函数:

    • 方法名称。
    • 以32位整数表示的方法修饰符。
    • 方法描述符。
  • 按方法名称和签名排序的每个非私有方法:

    • 方法名称。
    • 以32位整数表示的方法修饰符。
    • 方法描述符。
    • SHA-1算法在DataOutputStream产生的字节流上执行,并生成五个32位值sha[0..4]。哈希值由SHA-1消息摘要的第一个和第二个32位值组成。如果消息摘要的结果,即五个32位字H0 H1 H2 H3 H4,存储在名为sha的五个int值的数组中,则哈希值将如下计算:
    • long hash = ((sha[0] >>> 24) & 0xFF) |

      ((sha[0] >>> 16) & 0xFF) << 8 |

      ((sha[0] >>> 8) & 0xFF) << 16 |

      ((sha[0] >>> 0) & 0xFF) << 24 |

      ((sha[1] >>> 24) & 0xFF) << 32 |

      ((sha[1] >>> 16) & 0xFF) << 40 |

      ((sha[1] >>> 8) & 0xFF) << 48 |

      ((sha[1] >>> 0) & 0xFF) << 56;

这里的 long hash 不是指 hashcode

在JVM中,每个类只有一个实例。因此,文档中关于hashCode的内容是指类实例... - Ketan
请问您能分享文档参考吗? - Shiva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接