对象序列化
- 概述
- 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
- 使用一个字节序列表示一个对象, 该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
- 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息。当然,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。
对象序列化流
-
概述
将java对象的原始数据和图形写入文件,实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。 -
构造方法
构造方法 描述 ObjectOutputStream(OutputStream out) 创建一个对象序列化流 常用方法 描述 void writeObject(Object obj) 将指定的对象写入ObjectOutputStream //学生类 class Student implements Serializable { String name; int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } } //测试类 public class Demo { public static void main(String[] args) throws IOException { //创建学生对象 Student s1 = new Student("王磊",15); //创建对象序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt")); //对象写入文件 oos.writeObject(s1); oos.close(); } } ---*--- 输出结果: 在1.txt文件中写入了: sr com.Zh.Student都貒r帚 I ageL namet Ljava/lang/String;xp t 鐜嬬
注意:一个对象要想被序列化,该对象的数据类型必须实现 Serializable 接口(可序列化接口)。该接口不需要重写任何方法,仅用于标识该类可以序列化和反序列化。
对象反序列化流
-
概述
ObjectInputStream对先前使用ObjectOutputStream编写的原始数据和对象进行反序列化。 -
构造方法
构造方法 描述 ObjectInputStream(InputStream in) 创建一个从指定的InputStream读取的ObjectInputStream 常用方法 描述 Object readObject() 从ObjectInputStream中读取一个对象 public class Demo { public static void main(String[] args) throws IOException, ClassNotFoundException { //创建学生对象 Student s1 = new Student("王磊",15); //创建对象序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e:\\360sd\\1.txt")); //对象写入文件 oos.writeObject(s1); oos.close(); //创建对象反序列化流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:\\360sd\\1.txt")); //读取对象 Object o = ois.readObject(); Student s2 = (Student) o; System.out.println(s2.getName()+","+s2.getAge()); ois.close(); } } ---*--- 输出结果: 王磊,15
通过ObjectInputStream将ObjectOutputStream写入的对象通过readObject方法读取出来。
两个问题
- 1.使用对象序列化流序列化了一个对象之后,如果修改了对象的类文件,读取数据会出现什么问题?为什么会出现这样的问题?
- 序列化对象之后修改类文件,再读取数据会抛出InvaildClassException异常。因为序列化运行时会与每个可序列化的类关联一个版本号,serialVersionUID(序列化ID),在反序列化期间使用该版本号来验证序列化对象的发送方和接收方是否已加载与该序列化兼容的该对象的类。 也就是说当对象序列化或反序列化时都会默认隐性的为可序列化的类关联一个版本号,以验证序列化和反序列化的是兼容的类。而且版本号对类的细节十分十分敏感,可能因编译器实现而产生异常,所以可序列化类必须声明显式serialVersionUID值且必须为 static final long 类型:private static final long serialVersionUID = 42L;
- 2.对象中的成员变量的 值 不想被序列化,用什么方法实现?
- transient关键字修饰的成员变量不参与序列话。
//学生类 class Student implements Serializable { private static final long serialVersionUID = 4L; String name; transient int age; //transient修饰的成员变量不参与序列化 public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } } //测试类 public class Demo { public static void main(String[] args) throws IOException,ClassNotFoundException { writ(); read(); } public static void writ() throws IOException{ //创建学生对象 Student s1 = new Student("王磊",15); //创建对象序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e:\\360sd\\1.txt")); //对象写入文件 oos.writeObject(s1); oos.close(); } public static void read() throws IOException,ClassNotFoundException{ //创建对象反序列化流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:\\360sd\\1.txt")); //读取对象 Object o = ois.readObject(); Student s2 = (Student) o; System.out.println(s2.getName()+","+s2.getAge()); ois.close(); } } ---*--- 输出结果: 王磊,0