序列化ID的作用:
序列化ID决定:是否能够成功反序列化!简单来说,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。等会我们可以通过代码验证一下。
序列化ID如何产生:
当我们一个实体类中没有显示的定义一个名为“serialVersionUID”、类型为long的变量时,Java序列化机制会根据编译时的class自动生成一个serialVersionUID作为序列化版本比较,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID。譬如,当我们编写一个类时,随着时间的推移,我们因为需求改动,需要在本地类中添加其他的字段,这个时候再反序列化时便会出现serialVersionUID不一致,导致反序列化失败。那么如何解决呢?便是在本地类中添加一个“serialVersionUID”变量,值保持不变,便可以进行序列化和反序列化。
验证“serialVersionUID”不一致导致反序列化失败
1. import java.io.Serializable;
2.
3. /**
4. *
5. * 测试序列化和反序列化
6. * @author crazyandcoder
7. * @date [2015-8-5 上午11:14:32]
8. */
9. public class Person implements Serializable {
10.
11. private int age;
12. // private String sex;
13. // private String name;
14. // private String hobby;
15. //序列化ID
16. // private static final long serialVersionUID = -5809782578272943999L;
17.
18. // public String getHobby() {
19. // return hobby;
20. // }
21. //
22. // public void setHobby(String hobby) {
23. // this.hobby = hobby;
24. // }
25.
26. public Person() {}
27.
28. public int getAge() {
29. return age;
30. }
31.
32. public void setAge(int age) {
33. this.age = age;
34. }
35.
36. // public String getSex() {
37. // return sex;
38. // }
39. //
40. // public void setSex(String sex) {
41. // this.sex = sex;
42. // }
43.
44. // public String getName() {
45. // return name;
46. // }
47. // public void setName(String name) {
48. // this.name = name;
49. // }
50.
51. }
复用前篇使用到的代码,首先,我们生成一个本地Person类,里面添加一个字段age,然后将其序列化存于本地E:/hello.txt中,
1. import java.io.FileNotFoundException;
2. import java.io.FileOutputStream;
3. import java.io.IOException;
4. import java.io.ObjectOutputStream;
5.
6.
7. /**
8. *
9. * 测试序列化和反序列化
10. * @author crazyandcoder
11. * @date [2015-8-5 上午11:16:14]
12. */
13. public class ObjSerializeAndDeserializeTest {
14.
15.
16. public static void main(String[] args) {
17.
18. //将Person对象序列化
19. SerializePerson();
20. }
21.
22.
23. /**
24. *
25. * @author crazyandcoder
26. * @Title: 序列化Person对象,将其存储到 E:/hello.txt文件中
27. * @param
28. * @return void
29. * @throws
30. * @date [2015-8-5 上午11:21:27]
31. */
32. private static void SerializePerson() {
33. Person person =new Person();
34. 30);
35. ObjectOutputStream outputStream = null;
36. try {
37. outputStream=new ObjectOutputStream(new FileOutputStream("E:/hello.txt"));
38. outputStream.writeObject(person);
39. "序列化成功。");
40. } catch (FileNotFoundException e) {
41. e.printStackTrace();
42.
43. } catch (IOException e) {
44. e.printStackTrace();
45.
46. } finally {
47. try {
48. outputStream.close();
49. } catch (IOException e) {
50. e.printStackTrace();
51. }
52. }
53.
54. }
55. }
运行一下,会在控制台中打印“序列化成功。”,然后我们在Person类中再添加一个字段,name,然后直接从E:/hello.txt中反序列化,再运行一下,看看会出现什么问题。
1. import java.io.FileInputStream;
2. import java.io.FileNotFoundException;
3. import java.io.FileOutputStream;
4. import java.io.IOException;
5. import java.io.ObjectInputStream;
6. import java.io.ObjectOutputStream;
7.
8. /**
9. *
10. * 测试序列化和反序列化
11. *
12. * @author crazyandcoder
13. * @date [2015-8-5 上午11:16:14]
14. */
15. public class ObjSerializeAndDeserializeTest {
16.
17. public static void main(String[] args) {
18.
19. // 反序列化生成Person对象
20. Person person = DeserializePerson();
21. "name :"
22. "age :"
23. }
24.
25. /**
26. * 执行反序列化过程生产Person对象
27. *
28. * @author crazyandcoder
29. * @Title: DeserializePerson
30. * @param @return
31. * @return Person
32. * @throws
33. * @date [2015-8-5 下午1:30:12]
34. */
35. private static Person DeserializePerson() {
36.
37. Person person = null;
38. ObjectInputStream inputStream = null;
39. try {
40. inputStream = new ObjectInputStream(new FileInputStream("E:/hello.txt"));
41. try {
42. person = (Person) inputStream.readObject();
43. "执行反序列化过程成功。");
44. } catch (ClassNotFoundException e) {
45. e.printStackTrace();
46. }
47. } catch (FileNotFoundException e) {
48. e.printStackTrace();
49. } catch (IOException e) {
50. e.printStackTrace();
51. } finally {
52. try {
53. inputStream.close();
54. } catch (IOException e) {
55. e.printStackTrace();
56. }
57. }
58. return person;
59. }
60. }
运行一下,不出意外,报了一个异常。
从上面两张图便可以看出两次的序列化ID是不一样的,导致反序列化失败。
总结:
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。