序列化和反序列化
Posted liupiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了序列化和反序列化相关的知识,希望对你有一定的参考价值。
一、序列化和反序列化的定义
1.序列化:把java对象转换为二进制字节序列的过程
反序列化:把二进制字节恢复为对象的过程。
2.序列化的主要用途
- 把一个java对象通过序列化后永久的保存到硬盘上,例如通过文件保存在硬盘上
- 在网络上通过流传送对象的字节序列
二.序列化和反序列化使用
在java中,只有实现了Serializable接口和Externalizable接口的类的对象才能被序列化,Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 对象序列化的过程如下:
1 /** 2 * 序列化和反序列化 3 */ 4 class Test implements Serializable{ 5 6 /** 7 * 序列化ID 8 */ 9 private static final long serialVersionUID = -2281553568822627366L; 10 private String name; 11 private int num; 12 public static int num2 = 10; 13 public String getName() { 14 return name; 15 } 16 public void setName(String name) { 17 this.name = name; 18 } 19 public int getNum() { 20 return num; 21 } 22 public void setNum(int num) { 23 this.num = num; 24 } 25 } 26 public class Demo{ 27 28 public static void main(String[] args) { 29 //将对象序列化成字节并存放到文件中 30 Test test = new Test(); 31 test.setName("aa"); 32 test.setNum(1); 33 System.out.println("序列化前:"+test.num2); 34 ObjectOutputStream oos=null; 35 try { 36 oos = new ObjectOutputStream(new FileOutputStream("E:\test\result.txt")); 37 oos.writeObject(test); 38 oos.close(); 39 //序列化后改变静态变量的值 40 Test.num2 = 1000; 41 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\test\result.txt")); 42 Test test2 = (Test) ois.readObject(); 43 ois.close(); 44 45 System.out.println("反序列回来的对象的信息:"); 46 System.out.println("name:"+test2.getName()); 47 System.out.println("num:"+test2.getNum()); 48 System.out.println("num2:"+test.num2); 49 } catch (FileNotFoundException e) { 50 e.printStackTrace(); 51 } catch (IOException e) { 52 e.printStackTrace(); 53 } catch (ClassNotFoundException e) { 54 e.printStackTrace(); 55 } 56 } 57 58 }
结果输出:
结果输出: 序列化前:10 反序列回来的对象的信息: name:aa num:1 num2:1000
结果可知,序列化保存的是对象的状态,被序列化的对象的静态变量是属于类的状态,因此序列化并不保存静态变量。
三、serialVersionUID的作用
s?e?r?i?a?l?V?e?r?s?i?o?n?U?I?D?:? ?字?面?意?思?上?是?序?列?化?的?版?本?号?,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量,实现Serializable接口的类如果类中没有添加serialVersionUID,一般,在开发工具中都会给预警,那么意味着这个字段肯定是有作用的。那么具体的作用是什么呢?其实,这个序列化ID起着关键的作用,它决定着是否能够成功反序列化!简单来说,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。如修改上述代码:
/** * 序列化和反序列化 */ class Test implements Serializable{ /** * 序列化ID */ //private static final long serialVersionUID = -2281553568822627366L; private static final long serialVersionUID = -2281553568822627367L;//对对象序列化后,修改序列化版本ID private String name; private int num; public static int num2 = 10; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } } public class Demo{ public static void main(String[] args) { //将对象序列化成字节并存放到文件中 /*Test test = new Test(); test.setName("aa"); test.setNum(1); ObjectOutputStream oos=null;*/ try { /*oos = new ObjectOutputStream(new FileOutputStream("E:\test\result.txt")); oos.writeObject(test); oos.close(); //序列化后改变静态变量的值 */ Test.num2 = 1000; //修改序列化ID后,重新进行反序列化,此时本地Test类的序列化ID已经修改! ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\test\result.txt")); Test test2 = (Test) ois.readObject(); ois.close(); System.out.println("反序列回来的对象的信息:"); System.out.println("name:"+test2.getName()); System.out.println("num:"+test2.getNum()); System.out.println("num2:"+test2.num2); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
结果输出:
java.io.InvalidClassException: com.demo.Test; local class incompatible: stream classdesc serialVersionUID = -2281553568822627366, local class serialVersionUID = -2281553568822627367
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1876)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at com.demo.Demo.main(Demo.java:60)
结果表明,序列化ID的作用正如前面描述的那样, 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。
以上是关于序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章