目录
1、序列化Serialize和反序列化的概念
2、序列化和反序列化的代码演示:
3、序列化多个对象(序列化集合)
4、transient关键字将部分属性不参与序列化
1、序列化Serialize和反序列化的概念
在内存和硬盘的数据交互过程中,将Java对象拆分的过程
序列化就是将Java内存中的Java对象切割成像序列一样传递到硬盘文件中存储 (拆分对象)
反序列化就是通过硬盘序列好的Java对象组装重新返回到Java内存中(组装对象)
图示:
2、序列化和反序列化的代码演示:
序列化:
通过代码演示来加深理解:
首先创建一个普通的Student学生类,这个学生类没有实现任何接口,就是普通的:
package com.lbj.javase.bean;import java.io.Serializable;public class Student{private int no;private String name;public Student() {}public Student(int no, String name) {this.no = no;this.name = name;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}//重写toString方法@Overridepublic String toString() {return "Student{" +"no=" + no +", name='" + name + '\'' +'}';} }
再创建一个测试类,将Student对象进行序列化:
package com.lbj.javase.bean;import java.io.FileOutputStream; import java.io.ObjectOutputStream;public class ObjectOutputStreamTest01{public static void main(String[] args) throws Exception{//创建java对象Student s=new Student(123,"zhangsan");//包装类FileOutputStream fos=new FileOutputStream("student");//序列化ObjectOutputStream oos=new ObjectOutputStream(fos);//序列化对象oos.writeObject(s);//刷新oos.flush();//关闭oos.close();} }
报错:
总结:
Student是一个普通的类,并不支持序列化,需要加上Serializable的实现结构
修改测试(此时的Student类实现了Serializable接口):
package com.lbj.javase.bean;import java.io.Serializable;//Serializable只是一个标志性接口,这个接口其实什么都不写 public class Student implements Serializable {private int no;private String name;public Student() {}public Student(int no, String name) {this.no = no;this.name = name;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}//重写toString方法@Overridepublic String toString() {return "Student{" +"no=" + no +", name='" + name + '\'' +'}';} }
测试:
package com.lbj.javase.bean;import java.io.FileOutputStream; import java.io.ObjectOutputStream;public class ObjectOutputStreamTest01{public static void main(String[] args) throws Exception{//创建java对象Student s=new Student(123,"zhangsan");//包装类FileOutputStream fos=new FileOutputStream("student");//序列化ObjectOutputStream oos=new ObjectOutputStream(fos);//序列化对象oos.writeObject(s);//刷新oos.flush();//关闭oos.close();} }
测试结果:
总结:
1、参与序列化和反序列化的对象,必须实现Serializable接口
2、Serializable接口只是一个标志性接口,这个接口中什么也没有,只是起到让java虚拟机看到这个类实现了这个接口,可能对这个类特殊的待遇,java虚拟机会默认提供这个序列化的版本号(序列化版本号是用来区分序列化的类是否发生改变,用来达到安全性)
3、java虚拟机会自动序列化版本号,缺点。一旦被序列化的类A的代码确定后,不能进行后续的修改;只要修改,必定会重新编译,此时类A会生成全新的序列化版本号,这时候java虚拟机会认为这是一个全新的类(这样就不好了,会反序列化不成功,因为反序列化是根据序列化版本号进行重新读取)
4、结论:凡是一个类实现了Serializable接口,建议给该类一个固定不变的序列化版本号,这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类(Idea中可以生成一个序列化版本号,自己去探索,或者自己写一个也行)(P756)
-----------------------------------------------------------------------------------------------------------------------------------
反序列化:
代码演示:
package com.lbj.javase.bean;import java.io.FileInputStream;
import java.io.ObjectInputStream;public class ObjectInputStreamTest01 {public static void main(String[] args) throws Exception{//包装类FileInputStream fis=new FileInputStream("student");//序列化ObjectInputStream ois=new ObjectInputStream(fis);//开始反序列化,读Object obj=ois.readObject();//输出obj内容//反序列化回来是一个学生对象,所以会调用学生对象的toString方法System.out.println(obj.toString());//关闭流ois.close();}
}
输出结果:
Student{no=123, name='zhangsan'}
3、序列化多个对象(序列化集合)
代码演示:
创建一个实现Serializeable接口的Student类:
package com.lbj.javase.bean;import java.io.Serializable;//Serializable只是一个标志性接口,这个接口其实什么都不写
public class Student implements Serializable {private int no;private String name;public Student() {}public Student(int no, String name) {this.no = no;this.name = name;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}//重写toString方法@Overridepublic String toString() {return "Student{" +"no=" + no +", name='" + name + '\'' +'}';}
}
序列化:
package com.lbj.javase.bean;import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;public class ObjectOutputStreamTest02 {public static void main(String[] args) throws Exception{//创建一个集合对象List<Student> list=new ArrayList<>();//添加集合数据list.add(new Student(111,"lisi"));list.add(new Student(222,"Wanwu"));list.add(new Student(333,"liliu"));//输出流FileOutputStream fos=new FileOutputStream("students");//序列化ObjectOutputStream oos=new ObjectOutputStream(fos);//序列化一个集合,这个杰辉对象中放了很多其他对象oos.writeObject(list);//刷新流oos.flush();//关闭流oos.close();}
}
反序列化:
package com.lbj.javase.bean;import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;public class ObjectInputStreamTest02 {public static void main(String[] args) throws Exception{//输入流FileInputStream fis=new FileInputStream("students");//反序列化ObjectInputStream ois=new ObjectInputStream(fis);// Object obj=ois.readObject();
// System.out.println(obj.toString());//用列表形式输出List<Student> list = (List<Student>) ois.readObject();//集合的循环输出for (Student s:list) {System.out.println(s);}//关闭流ois.close();}
}
结果:
Student{no=111, name='lisi'}
Student{no=222, name='Wanwu'}
Student{no=333, name='liliu'}
注意:如果不用集合,直接存储多个对象,在存储第二个对象的时候会报错
4、transient关键字将部分属性不参与序列化
transient表示游离的,不参与序列化,只要给属性加上此限制,即可
演示:
结果(数据变成null):