一:起因
Java提供一种机制叫做序列化,其实就是把实体类的对象(Bean对象)以二进制的形式就行存储和传输(读取),多有需要序列化的对象对应的类需要继承 接口 Serializable。
(1)通过有序的格式或者字节序列持久化java对象,其中包含对象的数据,还有对象的类型,和保存在对象中的数据类型。所以,如果我们已经序列化了一个对象,那么它可以被读取并通过对象的类型和其他信息进行反序列化,并最终获取对象的原型。
(2)ObjectInputStream 和 ObjectOutputStream对象是高级别的流对象,包含序列化和反序列化的方法。ObjectOutputStream 拥有很多序列化对象的方法.
(2-2) 我们可以通过序列化来保存一个对象的状态(实例变量)到文件中,也可以从这个格式化的文件中很容易地读取对象的状态从而可以恢复我们保存的对象;用来实现序列化的类都在java.io包中,我们常用的类或接口有:ObjectOutputStream:提供序列化对象并把其写入流的方法ObjectInputStream:读取流并反序列化对象 ;Serializable:一个对象想要被序列化,那么它的类就要实现 此接口
(3)那么哪里会需要序列化呢?序列化通常在需要通过网络传输数据,或者保存对象到文件的场合使用。这里说的数据是对象而不是文本。
现在的问题是,我们的网络架构和硬盘都只能识别二进制和字节,而不能识别Java对象。序列化就是把Java对象中的value/states翻译为字节,以便通过网络传输或者保存。另外,反序列化就是通过读取字节码,并把它翻译回java对象
二:示例
(1)员工实体类(Employee.java 是一个bean,内含get set方法)
import java.io.Serializable;
public class Employee implements Serializable{
int employeeId;
String employeeName;
String department;
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
(2)这里以存储在外部文件为例子,外部文件命名为employee.out (文件的读写以employee类的对象进行)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
public class SerializeMain {
/**
* @author zyp
*/
public static void main(String[] args) {
Employee emp = new Employee();
emp.setEmployeeId(101);
emp.setEmployeeName("zyp 张燕鹏");
emp.setDepartment("com.CS");
Employee emp2 = new Employee();
emp2.setEmployeeId(102);
emp2.setEmployeeName("xqz 徐勤柱");
emp2.setDepartment("中国海洋大学");
ArrayList<Employee> emps = new ArrayList<Employee>();
emps.add(emp);
emps.add(emp2);
// 以上两个用于测试的
try
{
FileOutputStream fileOut = new FileOutputStream("employee.out",true);
// employee.ser 这可是文件名称的,相当于序列化的文件名的内的内容的,无法用普通的文本查看器查看的
ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
for(int i=0;i<emps.size();i++){
outStream.writeObject(emps.get(i));
System.out.println(emps.get(i));
}
outStream.writeObject(null);// 非常关键的哦,否则报错的peekByte错误的,用于读取的时候判空的
outStream.close();
fileOut.close();
}catch(IOException i)
{
i.printStackTrace();
}
}
}
(3)读取(2)存储的文件
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
public class DeserializeMain {
/**
* @author zyp
*/
public static void main(String[] args) {
ArrayList<Employee> emps = new ArrayList<Employee>();
Employee emp = null;
try
{
FileInputStream fis =new FileInputStream("employee.out");
//employee.ser 这可是之前保存的文件名称的,相当于读取序列化的文件名的内的内容的,无法用普通的文本查看器查看的
ObjectInputStream ois = new ObjectInputStream(fis);
emp = (Employee) ois.readObject();
//
while(emp!=null){
emps.add(emp);
emp = (Employee)ois.readObject();
}
ois.close();
fis.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
for(int i=0;i<emps.size();i++){
emp = emps.get(i);
System.out.println("Deserialized Employee...");
System.out.println("Emp id: " + emp.getEmployeeId());
System.out.println("Name: " + emp.getEmployeeName());
System.out.println("Department: " + emp.getDepartment());
System.out.println(emp);
}
}
}
(4)注意事项:
outStream.writeObject(null); (2)中的这一句话,非常关键的哦,否则报错的peekByte错误的,这是用于读取的时候判空的,否者到了文件末尾EOF还在读取employee对象,肯定报错的,错误如下(如果没有这句代码的话)
错误提示
(5)employee.out文件是以16进制进行数据存储的,一般的notepad++文本文件打不开的,UE可以打开的查看16进制代码
(6)eclipse 调试说明:首先打开debug模式(视图)开启,之后设置断点(设置多个断点)