java 对象序列化
Posted Delta
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 对象序列化相关的知识,希望对你有一定的参考价值。
对象序列化
序列化 :将java对象转换成字节序列,这些字节序列可以保存在磁盘上,或通过网络传输。
反序列化:将字节序列转换成java对象。
对象序列化步骤
- 需要序列化的对象所对应的类需要实现Serializable接口;
- 创建一个ObjectOutputStream实例,ObjectOutputStream是一个处理流,需要建立在其他节点流的基础之上;
// FileInputStream为节点流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
- 调用ObjectOutputStream的writeObject()方法输出对象;
// 将person对象写入object.txt文件中 oos.writeObject(person);
示例如下:
定义一个Person类,该类实现Serializable接口
class Person implements java.io.Serializable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public void setName(String name) {this.name = name;} public String getName() {return name;} public void setAge(int age) {this.age = age;} public int getAge() {return age;} }
创建一个Person类的实例对象,并将该对象写入object.txt文件中。
public static void main(String[] args) throws IOException { // FileInputStream为节点流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt")); Person person = new Person("Sunwukong", 500); // 将person对象写入object.txt文件中 oos.writeObject(person); }
对象反序列化
反序列化:将字节序列转换成java对象。
对象反序列化步骤
- 创建一个ObjectInputStream实例,ObjectInputStream是一个处理流,需要建立在其他节点流的基础之上;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
- 调用ObjectInputStream的readObject()方法读取流中的对象,该方法返回一个Object类型的java对象,如果知道java对象的类型,可以将该对象强制类型转换成其真实类型;
Person person = (Person) ois.readObject();
示例如下:
恢复object.txt文件中存储的person对象。
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt")); Person newPerson = (Person) ois.readObject(); System.out.println(newPerson.getName()); // 输出Sunwukong System.out.println(newPerson.getAge()); // 输出500 }
反序列化得到的对象是一个全新的对象,是一个重新建造的对象,与原对象不同。
public static void main(String[] args) throws IOException, ClassNotFoundException { // 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt")); Person person = new Person("Sunwukong", 500); oos.writeObject(person); // 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt")); Person newPerson = (Person) ois.readObject(); // newPerson是新建的对象,与person不是同一个对象 System.out.println(person == newPerson); // 输出false }
限制序列化的实例变量
在一些情况下,一个类的某些实例变量为敏感信息,不希望系统将这些实例变量序列化。
或某些实例变量不可被序列化。
通过在实例变量前使用transient关键字,可以指定java序列化时忽略这些实例变量。
如在Person类中的实例变量age前使用transient关键字修饰,Person实例对象序列化时会忽视该变量
class Person { private String name; // transient修饰age变量 // 对象序列化时会忽略该变量 private transient int age; public Person(String name, int age) { this.name = name; this.age = age; } public void setName(String name) {this.name = name;} public String getName() {return name;} public void setAge(int age) {this.age = age;} public int getAge() {return age;} }
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt")); Person newPerson = (Person) ois.readObject(); System.out.println(newPerson.getName()); // 输出Sunwukong // age变量没有序列化,反序列化得到的值为默认值 System.out.println(newPerson.getAge()); // 输出0 }
实例变量为引用类型时
该引用类型必须是可序列化的,否则拥有该实例变量的类是不可序列化的(除非使用transient修饰该实例变量)。
当对某个对象进行序列化时,系统自动把该对象的实例变量序列化,如果某个实例变量引用到另一个对象,则被引用的对象也会被序列化;
若果被引用对象的实例变量也引用了其他对象,则被引用的对象也会被实例化;
. . . . . . .
这种情况被称为递归序列化。
示例:
定义Teacher类,该类的一个实例变量student为引用类型Person。
class Teacher implements java.io.Serializable { private String name; // student为引用类型 private Person student; public Teacher(String name, Person student) { this.name = name; this.student = student; } public void setName(String name) {this.name = name;} public String getName() {return name;} public void setStudent(Person student) {this.student = student;} public Person getStudent() {return student;} }
创建Teacher类的实例对象,并将该对象序列化(写入object.txt文件中)
// 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt")); Person person = new Person("Sunwukong", 500); Teacher teacher = new Teacher("Tangseng", person); // 将teacher对象写入object.txt时, // 同时会将teacher中的引用类型变量student所指向的person对象写入object.txt中 oos.writeObject(teacher);
反序列化teacher对象,也可以得到person对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt")); Teacher newTeacher = (Teacher) ois.readObject(); System.out.println(newTeacher.getName()); // 输出Tangseng Person newPerson = newTeacher.getStudent(); System.out.println(newPerson.getName()); // 输出Sunwukong System.out.println(newPerson.getAge()); // 输出500
多个对象的序列化
当多个对象序列化时,java序列化机制采用如下算法:
- 所有保存到磁盘中的对象都有一个序列化编号;
- 当程序试图序列化一个对象时,程序将先检查该对象是否已经被序列化过,只有该对象从未序列化过,系统才会将该对象序列化;
- 如果某个对象已经序列化过,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象。
示例:
创建一个Person类实例对象person;
创建两个Teacher类实例对象t1与t2,两个对象都包含person;
依次向object.txt文件中写入实例对象t1 、t2、person、t1
public static void main(String[] args) throws IOException, ClassNotFoundException { // 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt")); Person person = new Person("Sunwukong", 500); Teacher t1 = new Teacher("Tangseng", person); Teacher t2 = new Teacher("Putizushi", person); // 将以上对象写入object.txt时, oos.writeObject(t1); oos.writeObject(t2); oos.writeObject(person); oos.writeObject(t1); // 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt")); // 依次读取object.txt中的对象 Teacher newt1 = (Teacher)ois.readObject(); Teacher newt2 = (Teacher)ois.readObject(); Person newPerson = (Person) ois.readObject(); Teacher obj = (Teacher)ois.readObject(); System.out.println(newt1.getStudent() == newt2.getStudent()); // true System.out.println(newt1.getStudent() == newPerson); // true System.out.println(newt1 == obj); // true }
上述程序只有3个对象被序列化:person、t1、t2。
oos.writeObject(t1); // 序列化t1与person
oos.writeObject(t2); // 序列化t2,person已经被序列化,t2中存放的是person序列化编码
oos.writeObject(person); // person已经被序列化,存放的是person序列化编码
oos.writeObject(t1); // t1已经被序列化,存放的是t1序列化编码
所以,从object.txt中取出对象时
newPerson与 newt1、newt2中的person都是同一个对象
obj与newt1也是同一个对象。
其他
关于对象序列化有以下几点需要注意:
对象的类名、实例变量都会被序列化,方法、类变量(static修饰的成员变量)、transient实例变量都不会被序列化。
序列化对象的实例变量应当也是可序列化的,否则使用transient关键字修饰。
反序列化对象时必须有序列化对象的class文件。
反序列化读取对象,必须按实际写入顺序读取。
以上是关于java 对象序列化的主要内容,如果未能解决你的问题,请参考以下文章