Java序列化Serializable和反序列化Deserializable详解及代码示例
概念介绍
-
序列化主要是针对对象而言,像字符串以及基本数据类型等可以通过常用的输入输出方法将其写入到文件中,需要时读取文件到内存中。
-
序列化:
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。 -
反序列化:
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。 -
整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
代码示例
- 类 ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,ObjectOutputStream 类包含很多写方法来写各种数据类型,但是一个特别的方法例外:
//这个方法序列化一个对象,并将它发送到输出流。
public final void writeObject(Object x) throws IOException
- 同样ObjectInputStream 类包含如下反序列化一个对象的方法:
//该方法从流中取出下一个对象,并将对象反序列化。它的返回值为Object,因此,你需要将它转换成合适的数据类型。
public final Object readObject() throws IOException, ClassNotFoundException
- 定义一个学生类Student,该类实现了Serializable 接口。
//Student.java 文件代码:
import java.io.Serializable;
public class Student implements Serializable {
private String number;
private String name;
private int sex;
private int age;
private int grades;
public Student(String number, String name, int sex, int age, int grades) {
this.number = number;
this.name = name;
this.sex = sex;
this.age = age;
this.grades = grades;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getGrades() {
return grades;
}
public void setGrades(int grades) {
this.grades = grades;
}
public void hello(){
System.out.println("你好,我是"+grades+"年级的"+name);
}
@Override
public String toString() {
return "Student{" +
"number='" + number + '\'' +
", name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", grades=" + grades +
'}';
}
}
-
注意,一个类的对象要想序列化成功,必须满足两个条件:
1、该类必须实现 java.io.Serializable 接口。
2、该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。 -
接下来序列化Student对象
//SerializeStudent.java 代码:
//该程序执行后,就创建了一个名为 student.ser 文件。注意: 当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializeStudent {
public static void main(String[] args) {
Student stu1 = new Student("10001", "张三", 0, 18, 10);
try {
FileOutputStream fileOut = new FileOutputStream("D:\\aspring\\student.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(stu1);
out.close();
fileOut.close();
System.out.println("Student对象文件已被保存在:D:/aspring/student.ser");
}catch(IOException i) {
i.printStackTrace();
}
}
}
- 序列化文件如图:
- 反序列化Student对象
//DeserializeStudent.java 文件代码:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserializeStudent {
public static void main(String[] args) {
Student stu1 = null;
try {
FileInputStream fis = new FileInputStream("D:\\aspring\\student.ser");
ObjectInputStream in = new ObjectInputStream(fis);
stu1 = (Student) in.readObject();
in.close();
fis.close();
System.out.println("反序列化的结果为:"+stu1.toString());
stu1.hello();
}catch(IOException e) {
e.printStackTrace();
return;
}catch(ClassNotFoundException e) {
e.printStackTrace();
return;
}
}
}
//执行结果如下:
反序列化的结果为:Student{number='10001', name='张三', sex=0, age=18, grades=10}
你好,我是10年级的张三
Process finished with exit code 0
- 注意:如果有属性不想被序列化,那么需要在Student对象的相应属性前,加 transient 修饰,表示该属性是短暂的。在序列化时,不会将 transient 修饰的属性序列化到文件中。示例如下:
private transient int sex;