目录
显示
serialVersionUID可以避免在反序列时的失败
有什么用?
当我们将对象序列化后,对原来的对象进行了修改,比如新增了一个demo字段。
这是时候在将对象反序列化回来的时候,就会报错:
Exception in thread "main" java.io.InvalidClassException: com.github.codedrinker.p1413.User; local class incompatible: stream classdesc serialVersionUID = 6360520658036414457, local class serialVersionUID = -3025746955499933156
显示 serialVersionUID
不相同,反序列化失败了,可是我们没有定义serialVersionUID啊?
我们查看 java.io.ObjectStreamClass#writeNonProxy
源码,如果当前类(User
)没有定义 serialVersionUID
,就会调用java.io.ObjectStreamClass#computeDefaultSUID
生成默认的序列化唯一标示。我们简单的看代码,发现他的生成规则是根据类名,结果明,方法和属性等参数生成的 hash
值,所以我们给 User
添加了 desc
属性,所以对应的 serialVersionUID
肯定会变化。
具体引用场景
数据库实体类的序列化:
- 当你的数据库实体类需要序列化以在分布式系统中传输或缓存时,如果你预计数据库表结构可能发生变化,可以显式指定
serialVersionUID
以确保版本一致性。public class User implements Serializable { private static final long serialVersionUID = 123456789L; // ... }
缓存对象的序列化:
- 如果你将对象缓存在分布式缓存中,并且希望在应用升级后仍然能够反序列化旧版本的对象,可以使用
serialVersionUID
。public class CachedData implements Serializable { private static final long serialVersionUID = 987654321L; // ... }
消息传递:
- 在使用消息队列或其他方式进行异步消息传递时,如果你的消息类可能会在不同的应用版本之间传递,显式指定
serialVersionUID
是个好习惯。public class Message implements Serializable { private static final long serialVersionUID = 42L; // ... }
分布式系统中的远程调用:
- 当你在分布式系统中使用远程调用(例如 RMI)时,确保服务端和客户端对序列化的对象具有相同的
serialVersionUID
是非常重要的。public class RemoteObject implements Serializable { private static final long serialVersionUID = 567890123L; // ... }
## 测试
```java
//实现序列化接口,但不定义serialVersionUID 字段
public class Demo implements Serializable {
public static void main(String[] args) {
Demo demo =new Demo();
}
}
//实现序列化接口,自己定义serialVersionUID 字段
public class Demo implements Serializable {
private final static long serialVersionUID = 42L;
public static void main(String[] args) {
Demo demo =new Demo();
}
}