知识目标 1.掌握对象序列化的基本概念。 2.掌握对象序列化的方法。 能力目 标熟练使用对象的序列化编写相应应用程序。 素质目标 1. 能够阅读科技文档和撰写分析文档。 2. 能够查阅JDK API。 3. 增强学生团队协作能力。
序列化是一种将对象以一连串的字节进行描述的过程,用于解决在对对象流进行读写操作时所引发的问题。序列化可以将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统中,并在需要时把该流读取出来重新构造一个相同的对象。
序列化的概念
将在内存中的各种对象的状态(也就是实例变量,不是方法)保存在磁盘中或者在网络中进行传输,并且可以把保存的对象状态再读出来。将一个Java对象写入IO流;与此对应的,则是从IO流中恢复一个Java对象。Java提供这种保存对象状态的机制,就是序列化。对象序列化是Java编程中的必备武器。
任务实施
任务一 使用Serializable序列化实体对象
1、任务需求
将一个对象序列化后写入到本地文件中。
2.任务分析
本任务类图如图5-1所示。
Employee.Java类是一个可序列化的实体类,要实现Serializable接口,同时需要有一个成员变量serialVersionUID。Address.Java类描述员工的地址信息。TestSerialize.Java类是测试类。文件是:D:\employee.dat。实现Serializable接口非常简单,只要让Java实现Serializable接口即可,无须实现任何方法。一个类一旦实现了Serializable接口,那么该类的对象就是可序列化的。实现类的对象的序列化可以使用ObjectOutputStream,实现步骤如下。• 创建ObjectOutputStream对象;• 调用ObjectOutputStream的writeObject方法输出对象。
3、任务实现
(1)地址类Address.java
package 序列化.使用Serializable序列化实体对象;
import java.io.Serializable;
public class Address implements Serializable {
private static final long serialVersionUID = 4983187287403615604L;
private String state; // 表示员工所在的国家
private String province; // 表示员工所在的省
private String city; // 表示员工所在的市
public Address(String state, String province, String city) {// 利用构造方法初始化各个域
this.state = state;
this.province = province;
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
@Override
public String toString() {// 使用地址属性表示地址对象
StringBuilder sb = new StringBuilder();
sb.append("国家:" + state + ", ");
sb.append("省:" + province + ", ");
sb.append("市:" + city);
return sb.toString();
}
}
(2)员工类Employee.Java
package 序列化.使用Serializable序列化实体对象;
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 3049633059823371192L;
private String name; // 表示员工的姓名
private int age; // 表示员工的年龄
private Address address;// 表示员工的地址
// 利用构造方法初始化各个域
public Employee(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
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;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {// 重写toString()方法
StringBuilder sb = new StringBuilder();
sb.append("姓名:" + name + ", ");
sb.append("年龄:" + age + "\n");
sb.append("地址:" + address);
return sb.toString();
}
}
(3)测试类TestSerialize.Java
package 序列化.使用Serializable序列化实体对象;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestSerialize {
public static void main(String[] args) {
// 创建一个员工对象
Address address = new Address("中国", "吉林", "长春");// 创建address对象
Employee employee = new Employee("张XX", 30, address);// 创建employee对象
// 将该对象写入到文件中,序列化该对象
File file = new File("employee.dat");
try {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(employee);
oos.flush();
oos.close();
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// try{
// FileInputStream fis = new FileInputStream(file);
// ObjectInputStream ois = new ObjectInputStream(fis);
// Object o = ois.readObject();
// System.out.println(o.toString());
//
// ois.close();
// fis.close();
//
// } catch (FileNotFoundException e) {
// throw new RuntimeException(e);
// } catch (IOException e) {
// throw new RuntimeException(e);
// } catch (ClassNotFoundException e) {
// throw new RuntimeException(e);
// }
}
}
任务二 使用反序列化将Person对象从磁盘上读出
1. 任务需求
使用反序列化将Employee对象从磁盘上读出并修改员工信息,然后再写入到文件中。
2. 任务分析
相应的反序列化需要使用的类是ObjectInputStream,反序列化的步骤如下。• 创建ObjectInputStream对象;• 使用ObjectInputStream的readObject方法取出对象。
3. 任务实现
重构代码,实现反序列化,代码如下。
TestDeserialize.java
package 序列化.使用Serializable序列化实体对象;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestDeserialize {
public static void main(String[] args) {
File file = new File("employee.dat");
// 从文件中读取对象,反序列化该对象
Employee employee1 = null;
try {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
employee1 = (Employee) ois.readObject();
System.out.println("修改前员工的信息:");
System.out.println(employee1);// 输出employee对象
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 修改该员工的相关信息
employee1.getAddress().setState("中国");
employee1.getAddress().setProvince("湖北省");
employee1.getAddress().setCity("武汉市");
employee1.setAge(21);
// 将该员工对象再次写入文件中,进行序列化
try {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(employee1);
oos.flush();
oos.close();
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 再次从文件中读取对象,进行反序列化
Employee employee2 = null;
try {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
employee2 = (Employee) ois.readObject();
System.out.println("修改后员工的信息:");
System.out.println(employee2);// 输出employee对象
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
说明
关于对象序列化与反序列化还有几点需要注意。• 反序列化无须通过构造器初始化对象;• 如果使用序列化机制向文件中写入了多个对象,那么取出和写入的顺序必须一致;• Java对类的对象进行序列化时,若类中存在对象引用(且值不为null),也会对类的引用对象进行序列化。