1 序列化与反序列化
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
只能将支持 java.io.Serializable 接口的对象写入流中,即对象类要实现Serializable接口来完成序列化。同时必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象(简单理解为:读取文件时且要加载Person.java文件)。
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
2 代码示例
(1)学生类
package com.java.object;
import java.io.Serializable;
public class Person implements Serializable/*标记接口,启动类的序列化*/ {
// 静态数据可以不被序列化
public /*static*/ String name;
// 使用关键字transient保证不被序列化
public /*transient*/ int age;
/* 可序列化类可以通过声明名为 "serialVersionUID" 的字段
* 显式声明自己的 UID为常量,保证版本号一致。*/
public static final long serialVersionUID = 42L;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
有时我们不需要对类中成员变量都使用序列化,解决方法:
(1)静态数据不会被序列化
(2)对成员变量使用transient进行修饰
(2)对象流
package com.java.object;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 对象流的序列化
writerObject();
// 对象流的反序列化
readerObject();
}
// 需求:对封装了数据的对象进行持久化存储
private static void writerObject() throws IOException {
Person p2 = new Person("coco",30);
Person p1 = new Person("zhao",20);
Person p3 = new Person("你好",18);
/* 如果向文件中写入对象数据,进行持久化存储:ObjectOutputStream*/
FileOutputStream fos = new FileOutputStream("obj.object");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p2);
oos.writeObject(p1);
oos.writeObject(p3);
// 假如对象有多个,不想多次创建读取对象方法,就定义一个结束标记符
oos.writeObject(null);
oos.close();
}
// 需求:读取已有的对象文件,并获取对象中的数据
private static void readerObject() throws
IOException, ClassNotFoundException {
/*如果读取已有的对象文件,只能通过ObjectInputStream*/
FileInputStream fis = new FileInputStream("obj.object");
ObjectInputStream ois = new ObjectInputStream(fis);
// Object b1 = ois.readObject();
// System.out.println(b1);
// Object b2 = ois.readObject();
// System.out.println(b2);
Object obj = null;
while((obj = ois.readObject()) != null){
System.out.println(obj);
}
}
}
3 Serializable(验证)
序列化接口(相当于一个标记接口),该接口中没有任何方法,实现该接口不需要重写。类通过实现Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
作用:给每一个需要序列化的类分配一个序列版本号(UID),这个号和Person类相关联。在写入文件时也会将这个序列版本号写入文件,在读的过程中会读取文件中类的序列号和当前类的序列号进行匹配。如果不匹配就会发生InvalidClassException。(粗略的讲就是一个类在写入文件时会自动生成一个UID序列号,假如我修改了类的某些内容。此时我读取文件的对象,就会发现修改后的类和文件中的类的UID不同,异常出现。)解决这个问题的方法就是:可序列化类可以通过声明名为静态的、最终的常量。