序列化概念:
1.Java序列化与反序列化
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。
2.为什么需要序列化与反序列化
我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。
当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
3.如何实现Java序列化与反序列化
1)JDK类库中序列化API
java.io.ObjectOutputStream:表示对象输出流
它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream:表示对象输入流
它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。
2)实现序列化的要求
只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常。
3)实现Java对象序列化与反序列化的方法
假定一个Student类,它的对象需要序列化,可以有如下三种方法:
方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。
4)JDK类库中序列化的步骤
步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:
ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream(“D:\\objectfile.obj”));
步骤二:通过对象输出流的writeObject()方法写对象:
out.writeObject(“Hello”);
out.writeObject(new Date());
5)JDK类库中反序列化的步骤
步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:
ObjectInputStream in = new ObjectInputStream(new fileInputStream(“D:\\objectfile.obj”));
步骤二:通过对象输出流的readObject()方法读取对象:
String obj1 = (String)in.readObject();
Date obj2 = (Date)in.readObject();
说明:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。
6)在现实应用中,有些时候不能使用默认序列化机制。比如,希望在序列化过程中忽略掉敏感数据,可以使用transient关键字。
当某个字段被声明为transient后,默认序列化机制就会忽略该字段。此处将Person类中的age字段声明为transient,如下所示,
public class Person implements Serializable {
transient private Integer age = null;
}
序列化实例:
实体类:
1 package cn.chapter3.learn.test2;
2
3 public class Student implements java.io.Serializable{
4 private String name;
5 private int age;
6 private String sex;
7
8 public Student(String name, int age, String sex) {
9 super();
10 this.name = name;
11 this.age = age;
12 this.sex = sex;
13 }
14 public String getName() {
15 return name;
16 }
17 public int getAge() {
18 return age;
19 }
20 public String getSex() {
21 return sex;
22 }
23
24 }
实体类student
单个对象序列化及反序列化:
1 package cn.chapter3.learn.test2;
2
3 import java.io.FileInputStream;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.ObjectInputStream;
8 import java.io.ObjectOutputStream;
9
10 public class TestSerializable {
11
12 /**
13 * Student对象的序列化和反序列化
14 * @param args
15 *
16 */
17 public static void main(String[] args) {
18 // 创建 ObjectOutputStream输出流变量
19 ObjectOutputStream oos = null;
20 // 创建ObjectInputStream输入流变量
21 ObjectInputStream ois = null;
22 // 创建Student对象
23 Student stu1 = new Student("安娜", 30, "女");
24 try {
25 // 创建 ObjectOutputStream输出流对象
26 oos = new ObjectOutputStream(new FileOutputStream(
27 "D:\\temp\\stu.txt"));
28 // 创建ObjectInputStream输入流对象// 创建从指定InputStream 读取的ObjectInputStream。
29 ois = new ObjectInputStream(
30 new FileInputStream("D:\\temp\\stu.txt"));
31
32 // 对象序列化,写入输出流
33 oos.writeObject(stu1);
34 // 反序列化,强制转换为Student类
35 Student stu = (Student) ois.readObject();
36 System.out.println("学生信息为:");
37 System.out.println("姓名" + stu.getName() + ",年龄:" + stu.getAge()
38 + ",性别:" + stu.getSex());
39
40 } catch (FileNotFoundException e) {
41 e.printStackTrace();
42 } catch (IOException e) {
43 e.printStackTrace();
44 } catch (ClassNotFoundException e) {
45 e.printStackTrace();
46 } finally {
47 // 写完了关闭相应的流
48 try {
49 if (oos != null) {
50 oos.close();
51 }
52 if (ois != null) {
53 ois.close();
54 }
55 } catch (IOException e) {
56 e.printStackTrace();
57 }
58 }
59 }
60
61 }
单个对象序列化
集合序列化及反序列化:
1 package cn.chapter3.learn.test2;
2
3 import java.io.FileInputStream;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.ObjectInputStream;
8 import java.io.ObjectOutputStream;
9 import java.util.ArrayList;
10 import java.util.List;
11
12 public class TestSerializable2 {
13
14 /**
15 * 集合的序列化和反序列化
16 * @param args
17 *
18 */
19 public static void main(String[] args) {
20 // 创建 ObjectOutputStream输出流
21 ObjectOutputStream oos = null;
22 // 创建ObjectInputStream输入流
23 ObjectInputStream ois = null;
24 Student stu1 = new Student("安娜", 30, "女");
25 Student stu2 = new Student("李慧", 20, "女");
26 List<Student> stuList = new ArrayList<Student>();
27 stuList.add(stu1);
28 stuList.add(stu2);
29 try {
30 oos = new ObjectOutputStream(new FileOutputStream(
31 "D:\\temp\\stu.txt"));
32 // 创建从指定InputStream 读取的ObjectInputStream
33 ois = new ObjectInputStream(
34 new FileInputStream("D:\\temp\\stu.txt"));
35 oos.writeObject(stuList);// 将list对象序列化,写入输出流
36 // 反序列化,将读取到的Object强制转换为ArrayList<Student>
37 ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
38 // foreach遍历学生信息
39 for (Student stu : list) {
40 System.out.println("姓名" + stu.getName() + ",年龄:" + stu.getAge()
41 + ",性别:" + stu.getSex());
42 }
43 } catch (FileNotFoundException e) {
44 e.printStackTrace();
45 } catch (IOException e) {
46 e.printStackTrace();
47 } catch (ClassNotFoundException e) {
48 e.printStackTrace();
49 } finally {// 写完了要关闭相应的流
50 try {
51 if (oos != null) {
52 oos.close();
53 }
54 if (ois != null) {
55 ois.close();
56 }
57 } catch (IOException e) {
58 e.printStackTrace();
59 }
60 }
61 }
62
63 }
list序列化