Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 467a3c9

Browse filesBrowse files
author
zhupeiquan
committed
What is a serialVersionUID and why should I use it?
1 parent 5cce1f1 commit 467a3c9
Copy full SHA for 467a3c9

File tree

Expand file treeCollapse file tree

1 file changed

+141
-0
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+141
-0
lines changed
+141Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# serialVersionUID 有什么作用?该如何使用?
2+
3+
当一个对象实现 Serializable 接口时,多数 ide 会提示声明一个静态常量 serialVersionUID(版本标识),那 serialVersionUID 到底有什么作用呢?应该如何 serialVersionUID ?
4+
5+
serialVersionUID 是实现 Serializable 接口而来的,而 Serializable 则是应用于Java 对象序列化/反序列化。对象的序列化主要有两种用途:
6+
7+
- 把对象序列化成字节码,保存到指定介质上(如磁盘等)
8+
- 用于网络传输
9+
10+
现在反过来说就是,serialVersionUID 会影响到上述所提到的两种行为。那到底会造成什么影响呢?
11+
12+
[java.io.Serializable](http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html) doc 文档,给出了一个相对详细解释:
13+
serialVersionUID 是 Java 为每个序列化类产生的版本标识,可用来保证在反序列时,发送方发送的和接受方接收的是可兼容的对象。如果接收方接收的类的 serialVersionUID 与发送方发送的 serialVersionUID 不一致,进行反序列时会抛出 InvalidClassException。序列化的类可显式声明 serialVersionUID 的值,如下:
14+
```
15+
ANY-ACCESS-MODIFIER static final long serialVersionUID = 1L;
16+
```
17+
18+
文档上还建议 serialVersionUID 置为 private。
19+
20+
举例说明如下:
21+
现在尝试从将一个类 Person 序列化到磁盘和反序列化来说明 serialVersionUID 的作用: Person 两日如下:
22+
```
23+
public class Person implements Serializable {
24+
25+
private static final long serialVersionUID = 1L;
26+
27+
private String name;
28+
private Integer age;
29+
private String address;
30+
31+
public Person() {
32+
}
33+
34+
public Person(String name, Integer age, String address) {
35+
this.name = name;
36+
this.age = age;
37+
this.address = address;
38+
}
39+
40+
41+
@Override
42+
public String toString() {
43+
return "Person{" +
44+
"name='" + name + '\'' +
45+
", age=" + age +
46+
", address='" + address + '\'' +
47+
'}';
48+
}
49+
}
50+
```
51+
52+
简单的测试一下:
53+
```
54+
@Test
55+
public void testversion1L() throws Exception {
56+
File file = new File("person.out");
57+
// 序列化
58+
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));
59+
Person person = new Person("John", 21, "广州");
60+
oout.writeObject(person);
61+
oout.close();
62+
// 反序列化
63+
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
64+
Object newPerson = oin.readObject();
65+
oin.close();
66+
System.out.println(newPerson);
67+
}
68+
```
69+
70+
测试发现没有什么问题。有一天,因发展需要, 需要在 Person 中增加了一个字段 email,如下:
71+
```
72+
public class Person implements Serializable {
73+
74+
private static final long serialVersionUID = 1L;
75+
76+
private String name;
77+
private Integer age;
78+
private String address;
79+
private String email;
80+
81+
public Person() {
82+
}
83+
84+
public Person(String name, Integer age, String address) {
85+
this.name = name;
86+
this.age = age;
87+
this.address = address;
88+
}
89+
90+
public Person(String name, Integer age, String address,String email) {
91+
this.name = name;
92+
this.age = age;
93+
this.address = address;
94+
this.email = email;
95+
}
96+
97+
@Override
98+
public String toString() {
99+
return "Person{" +
100+
"name='" + name + '\'' +
101+
", age=" + age +
102+
", address='" + address + '\'' +
103+
", email='" + email + '\'' +
104+
'}';
105+
}
106+
}
107+
```
108+
109+
这时我们假设和之前序列化到磁盘的 Person 类是兼容的,便不修改版本标识 serialVersionUID。再次测试如下
110+
```
111+
@Test
112+
public void testversion1LWithExtraEmail() throws Exception {
113+
File file = new File("person.out");
114+
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
115+
Object newPerson = oin.readObject();
116+
oin.close();
117+
System.out.println(newPerson);
118+
}
119+
```
120+
将以前序列化到磁盘的旧 Person 反序列化到新 Person 类时,没有任何问题。
121+
122+
可当我们增加 email 字段后,不作向后兼容。即放弃原来序列化到磁盘的 Person 类,这时我们可以将版本标识提高,如下:
123+
```
124+
private static final long serialVersionUID = 2L;
125+
```
126+
127+
再次进行序列化,则会报错,如下:
128+
```
129+
java.io.InvalidClassException:Person local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
130+
```
131+
132+
谈到这里,我们大概可以清楚,serialVersionUID 就是控制版本是否兼容的,若我们认为修改的 Person 是向后兼容的,则不修改 serialVersionUID;反之,则提高 serialVersionUID的值。再回到一开始的问题,为什么 ide 会提示声明 serialVersionUID 的值呢?
133+
134+
因为若不显式定义 serialVersionUID 的值,Java 会根据类的细节自动生成 serialVersionUID 的值,如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,也有可能会导致不同的serialVersionUID。所以 ide 才会提示声明 serialVersionUID 的值。
135+
136+
附录拓展:
137+
138+
- [深入理解 Java 对象序列化](http://developer.51cto.com/art/201202/317181.htm)
139+
- [对象的序列化和反序列化](http://www.blogjava.net/lingy/archive/2008/10/10/233630.html)
140+
141+
stackoverflow原址:http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.