一:起因
Java提供一种机制叫做序列化,其实就是把实体类的对象(Bean对象)以二进制的形式就行存储和传输(读取),多有需要序列化的对象对应的类需要继承 接口 Serializable。
(1)通过有序的格式或者字节序列持久化java对象,其中包含对象的数据,还有对象的类型,和保存在对象中的数据类型。所以,如果我们已经序列化了一个对象,那么它可以被读取并通过对象的类型和其他信息进行反序列化,并最终获取对象的原型。
(2)ObjectInputStream 和 ObjectOutputStream对象是高级别的流对象,包含序列化和反序列化的方法。ObjectOutputStream 拥有很多序列化对象的方法,最常用的是:
(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模式(视图)开启,之后设置断点(设置多个断点)