1.认识序列化和反序列化
1.1 序列化
(1)序列化:将对象的状态存储到特定存储介质中的过程,也就是将对象状态转换为可保持或可传输格式的过程。存储介质通常指文件。
(2)在序列化过程中,会将对象的公有成员、私有成员包括类名转换为字节流,然后写入数据存储到存储介质中。
(3)使用序列话的意义在于将Java对象序列化后,可以将其转换为字节序列,这些字节序列可以被保存在磁盘上,也可以借助网络进行传输,同时序列化后的对象保存的是二进制状态,这样实现了平台无关性。即可以将在Windows操作系统中实现序列化的一个对象,传输到UNIX操作系统的机器上,再通过反序列化后得到相同对象,而无需担心数据因平台问题显示异常。
1.2 反序列化
(1)反序列化:将对象的状态信息保存到存储介质中,即:从特定的存储介质中读取数据并重新构建对象的过程。
(2)通过反序列化,可以将存储在文件上的对象信息读取出来,然后重新构建为对象。这样不需要将文件上的信息一一读取、分析再组织为对象。
2.序列化保存对象信息
(1)序列化介质允许将实现了序列化的Java对象转换为字节序列,这个过程需要借助于I/O流来实现。
(2)如果要将一个对象序列化,那么这个对象的类就必须要实现序列化接口Serializable,这个接口在java.io包中。
(3)Serializable表示可串行的、可序列化的,所以,对象序列化在某些文献上也称为串行化。
(4)JDK类库中有些类,如String类、包装类和Date类等都实现了Serializable接口。
(5)对象序列化的主要步骤如下:
1)创建一个对象输出流(ObjectOutputStream),它可以包装一个其他类型的输出流,如文件输出流FileOutputStream。
2)通过对象输出流的writeObject()方法写对象,也就是输出可序列化对象。
代码举例说明:
定义类
import java.io.Serializable;
//序列化对象的前提是,这个对象所在的类要实现序列化接口Serializable
public class Student implements Serializable{
private String name;
//transient关键字修饰的属性,不会进行序列化操作,那么反序列化得到的数据就是属性的默认值
private int age;
public Student() {
super();
}
public Student(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 "Student [name=" + name + ", age=" + age + "]";
}
}
写入学生对象信息:
//序列化:将对象的状态写入到文件中的过程
public static void main(String[] args) throws IOException {
//创建学生对象
Student stu1=new Student("王二", 21);
Student stu2=new Student("张三", 24);
OutputStream os=new FileOutputStream("E:/student.txt");
//创建ObjectOutputStream类对象
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(stu1);
oos.writeObject(stu2);
System.out.println("学生写入完毕");
oos.close();
os.close();
}
3.反序列化获取对象信息
反序列化的主要步骤如下:
1)创建一个对象输入流(ObjectInputStream),它可以包装一个其他类型的输入流,如文件输入流FileInputStream。
2)通过对象输入流的readObject()方法读取对象,该方法返回一个Object类型的对象,如果程序知道该Java对象的类型,则可以将该对象强制转换成其真实的类型。
(4)如果向文件中使用序列化机制写入多个对象,那么反序列化恢复对象时,必须按照写入的顺序读取。
(5)如果一个可序列化的类,有多个父类(包括直接父类或间接父类),则这些父类要么是可序列化的,要么有无参的构造器;否则会抛出异常。
(6)他通常,对象中的所有属性都会被序列化,但是对于一些比较敏感的信息,比如用户密码,一旦序列化后,人们完全可以通过读取文件或拦截网络传输数据的方式获得这些信息。因此,从安全考虑,某些属性应该限制被序列化,解决的办法是使用transient关键字来修饰。
代码举例说明:
获取学生对象信息
//反序列化:从文件中获取数据重新构建对象的过程
public static void main(String[] args) throws IOException, ClassNotFoundException {
InputStream is=new FileInputStream("E:/student.txt");
ObjectInputStream ois=new ObjectInputStream(is);
Object object1=ois.readObject();
Student stu1=(Student)object1;
System.out.println(stu1);
Object object2=ois.readObject();
Student stu2=(Student)object2;
System.out.println(stu2);
ois.close();
is.close();
}
注意:如果一个类的成员包含其他类的对象,那么序列化这个类的对象时,也要保证该类中的引用类型的对象也是可以序列化的。即当需要序列化某个特定对象时,它的各个成员对象也必须是可序列化的。