1、概述
(1)用于从流中读取对象的操作流 ObjectInputStream称为 反序列化流;
(2)用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流。
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。
2、对象序列化流ObjectOutputStream
(1)ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储;
(2)只能将支持 java.io.Serializable 接口的对象写入流中。
Person类
1 import java.io.Serializable; 2 3 public class Person implements Serializable { 4 private String name; 5 private int age; 6 7 public Person() { 8 super(); 9 } 10 11 public Person(String name, int age) { 12 super(); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 33 @Override 34 public String toString() { 35 return "Person [name=" + name + ", age=" + age + "]"; 36 } 37 }
测试类
1 import java.io.FileOutputStream; 2 import java.io.IOException; 3 import java.io.ObjectOutputStream; 4 5 public class ObjectStreamDemo { 6 public static void main(String[] args) throws IOException, 7 ClassNotFoundException { 8 /* 9 * 将一个对象存储到持久化(硬盘)的设备上。 10 */ 11 writeObj();// 对象的序列化。 12 } 13 14 public static void writeObj() throws IOException { 15 // 1,明确存储对象的文件。 16 FileOutputStream fos = new FileOutputStream("D:\Java\obj.object"); 17 // 2,给操作文件对象加入写入对象功能。 18 ObjectOutputStream oos = new ObjectOutputStream(fos); 19 // 3,调用了写入对象的方法。 20 oos.writeObject(new Person("王五", 20)); 21 // 关闭资源。 22 oos.close(); 23 } 24 }
在反序列化程序中运行后能够正常输出Person的相关信息,但是在目录下的文件“obj.object”用文本编辑器打开之后却是乱码的。这是为什么呢?
因为序列化和反序列化都是基于二进制流的,其实就是将person的相关信息转化为二进制存储在了obj.object这个文件中,那么用文本编辑器打开查看的话当然是会出现乱码的。只有通过反序列化才能将存储的二进制读取出来,然后正常显示在控制台上。
3、对象反序列化流ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。支持 java.io.Serializable接口的对象才能从流读取。
1 import java.io.FileInputStream; 2 import java.io.IOException; 3 import java.io.ObjectInputStream; 4 5 public class ObjectStreamDemo2 { 6 public static void main(String[] args) throws IOException, 7 ClassNotFoundException { 8 readObj();// 对象的反序列化。 9 } 10 11 public static void readObj() throws IOException, ClassNotFoundException { 12 13 // 1,定义流对象关联存储了对象文件。 14 FileInputStream fis = new FileInputStream("D:\Java\obj.object"); 15 16 // 2,建立用于读取对象的功能对象。 17 ObjectInputStream ois = new ObjectInputStream(fis); 18 19 Person obj = (Person) ois.readObject(); 20 21 System.out.println(obj.toString()); 22 23 } 24 }
4、序列化接口
(1)当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口。否则会发生异常NotSerializableException异常;
(2)同时当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException;
(3)发生这个异常的原因如下:
该类的序列版本号与从流中读取的类描述符的版本号不匹配;
该类包含未知数据类型;
该类没有可访问的无参数构造方法;
(4)Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
(5)代码修改如下,修改后再次写入对象,读取对象测试
1 import java.io.Serializable; 2 3 public class Person implements Serializable { 4 // 给类显示声明一个序列版本号。 5 private static final long serialVersionUID = 1L; 6 private String name; 7 private int age; 8 9 public Person() { 10 super(); 11 12 } 13 14 public Person(String name, int age) { 15 super(); 16 this.name = name; 17 this.age = age; 18 } 19 20 public String getName() { 21 return name; 22 } 23 24 public void setName(String name) { 25 this.name = name; 26 } 27 28 public int getAge() { 29 return age; 30 } 31 32 public void setAge(int age) { 33 this.age = age; 34 } 35 36 @Override 37 public String toString() { 38 return "Person [name=" + name + ", age=" + age + "]"; 39 } 40 }
5、瞬态关键字transient
(1)当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会琲序列化了;
(2)同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
(3)代码修改如下,修改后再次写入对象,读取对象测试
1 import java.io.Serializable; 2 3 public class Person implements Serializable { 4 /* 5 * 给类显示声明一个序列版本号。 6 */ 7 private static final long serialVersionUID = 1L; 8 private static String name; 9 private transient/* 瞬态 */int age; 10 11 public Person() { 12 super(); 13 14 } 15 16 public Person(String name, int age) { 17 super(); 18 this.name = name; 19 this.age = age; 20 } 21 22 public String getName() { 23 return name; 24 } 25 26 public void setName(String name) { 27 this.name = name; 28 } 29 30 public int getAge() { 31 return age; 32 } 33 34 public void setAge(int age) { 35 this.age = age; 36 } 37 38 @Override 39 public String toString() { 40 return "Person [name=" + name + ", age=" + age + "]"; 41 } 42 }