哈希码作为 serialVersionUid
Hashcode as serialVersionUid
我在一篇文章中看到,JVM默认提供的serialVersionUid是一个对象的hashcode。如果不覆盖class中的hashcode方法,通常hashcode是object的内存地址,反序列化时如何计算hashcode?
I read in an article that the default serialVersionUid
provided by JVM is the hashcode of an object.
这是不正确的。 (要么文章不正确,要么你误读/误解了它。)
可序列化 class 的默认序列版本 UID 与 hashCode 完全无关。
生成默认序列号版本UID的算法如下:
基本上,它根据 classes 名称、修饰符、接口名称及其字段、构造函数和方法的签名创建 SHA-1 哈希。然后它获取散列的前 8 个字节并将它们组装成 long
.
我想你误会了。不是hashcode
。 serialVersionUid
是静态变量,hashcode
是实例方法,对象的哈希码值因对象而异。
serialVersionUid
是根据你的class的结构计算出来的——字段、方法等。它在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 确切格式。
规范描述了未提供值时发生的情况,但自动生成使用相同的算法。
流中的项目顺序如下:
class 姓名。
class修饰符写成32位整数。
每个接口的名称按名称排序。
对于class的每个字段按字段名排序(私有的除外
静态和私有瞬态字段:
- 字段名称。
- 写成32位整数的字段修饰符。
- 字段的描述符。
如果存在 class 初始值设定项,写出以下内容:
- 方法名称,。
- 方法的修饰符,
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默认提供的serialVersionUid是一个对象的hashcode。如果不覆盖class中的hashcode方法,通常hashcode是object的内存地址,反序列化时如何计算hashcode?
I read in an article that the default
serialVersionUid
provided by JVM is the hashcode of an object.
这是不正确的。 (要么文章不正确,要么你误读/误解了它。)
可序列化 class 的默认序列版本 UID 与 hashCode 完全无关。
生成默认序列号版本UID的算法如下:
基本上,它根据 classes 名称、修饰符、接口名称及其字段、构造函数和方法的签名创建 SHA-1 哈希。然后它获取散列的前 8 个字节并将它们组装成 long
.
我想你误会了。不是hashcode
。 serialVersionUid
是静态变量,hashcode
是实例方法,对象的哈希码值因对象而异。
serialVersionUid
是根据你的class的结构计算出来的——字段、方法等。它在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 确切格式。
规范描述了未提供值时发生的情况,但自动生成使用相同的算法。
流中的项目顺序如下:
class 姓名。
class修饰符写成32位整数。
每个接口的名称按名称排序。
对于class的每个字段按字段名排序(私有的除外 静态和私有瞬态字段:
- 字段名称。
- 写成32位整数的字段修饰符。
- 字段的描述符。
如果存在 class 初始值设定项,写出以下内容:
- 方法名称,。
- 方法的修饰符, 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