- java提供了一种对象序列化的机制,用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写入到文件中后,就相当于再文件中保存了一个对象信息。
- 反之,该字节序列还可以从文件读取出来,重构对象,对它进行反序列。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。
图解如下:
ObjecetOutputStream类
java.io.ObjectOutputStream类,将java对象的原始数据类型写入到文件中,实现对象的持久化存储。
构造方法: - public ObjectOutputStream(OutputStream out):创建一个指定的OutputStream的ObjectOutputStream类对象
特有的独有方法: - void writeObject(Object obj):将指定的对象写入到ObjectOutputStrem类对象中。
序列化操作
一个对象想要能够序列化和反序列化,必须满足两个条件: - 该类必须实现java.io.Serializable接口,Serializable接口,是一个标记型接口,如果该类没有实现Serializable接口,将会抛出NotSerializableException。
- 该类的所有的属性必须是可以实现序列化或者反序列化。如果有一个属性不行让它参与序列化,则该属性必须表明是瞬态的,瞬时的,这个关键字是transient。
public class Student implements Serializable {
private String name;
private transient Integer age;// 不让age属性参与序列化
}
ObjectInputStream类
java.io.objectInputStream类是反序列化流,将之前使用ObjectOutputStream序列化流的原始数据恢复为对象。
构造方法
- public ObjectInputStream(InputStream in):创建一个指定的InputStream的对象反序列化流对象。
特有的方法: - public final Onject readObject():从反序列化流中读取一个对象。
对于JVM来说,能够进行反序列化的对象,前提条件是必须能够找到class文件的类,如果找不到该类的class文件,则会抛出一个ClassNotFoundException异常。
另外,当JVM序列化对象时,能够找到class文件,但是class文件在序列化对象时,发生了修改,那么反序列化操作会抛出一个InvalidClassException异常。原因如下: - 该类的序列化版本号与从流中读取出来描述该类的版本号不一致。
- 该类包含了未知数据类型。
- 该类没有可访问的无参构造方法。
Serializable接口给需要序列化的类,提供了一个序列化版本号,SerialVersionUID该版本号的目的就是在于验证序列化的对象和对应的类是否是版本一致的。
代码示例如下:
//首先随便构建一个类对象,其中的属性自行随心定义
//我定义的是一个Student类 其中的属性为 name 和 age
// 序列化操作类
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws IOException {
//1.创建ObjectOutputStream流对象,构造方法中传递指定的字节输出流。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day30_IO\\student.txt"));
//2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中。
//2.1 先创建一个对象
Student s = new Student("小孙", 30);
//2.2写对象到文件中
oos.writeObject(s);
//3.释放资源。
oos.close();
}
}
// 反序列化类操作
public class Demo02ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 创建一个ObjectInputStream流对象,构造方法中传递一个字节输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day30_IO\\student.txt"));
// 2. 使用ObjectInputStream流对象中的方法readObject,读取保存在文件中的对象数据
Object obj = ois.readObject();
// 3.释放资源。
ois.close();
// 4. 查看对象的数据
System.out.println(obj);// Student{name='小孙', age=30}
if ( obj instanceof Student) {
Student student = (Student)obj;
System.out.println(student.getAge() + "--" + student.getName());
} else {
System.out.println("转换失败");
}
}
}
// 需要被序列化的类
import java.io.Serializable;
public class Student implements Serializable {
// 可以选择手动自定义一个序列化版本号
private static final long serialVersionUID = 1L;
//private static String name;//用static和transient修饰的属性皆不可被序列化
private String name;
private Integer age;
transient int score;//用static和transient修饰的属性皆不可被序列化
//以上所述可以自行验证
}
原理分析