对象持续性
在我写的Java学习之对象序列化(一)中您已经知道了序列化机制的一些含义和如何实现序列化,在本文中我们将深入到该机制的内部看看它到底是怎么工作的!
举个例子来说:
假设现在写好了两个类,一个Employee(员工类),一个Manager(经理类),接着创建它们的对象,在创建Manager对象时需要为Manager指定一个秘书而秘书也是一个Employee,在这里我们就用现成的Employee对象做Manager的秘书,也就是说需要在Manager中包含一个Employee的对象引用,如下代码:
Employee harry = new Employee("Harry Hacke",.........); //是员工又是秘书
Manager manager1 = new Manager("Tony Tester",.......); //经理对象
manager1.setSecretary(harry); //设置秘书为harry
现在,在内存中实际创建了两个对象,一个Employee,一个Manager而Manager中包含了一个指向Employee对象的引用,是引用而已,当我们把以上这些写入磁盘的时候发生了变化,harry的数据被保存了两次,也就是说我们在Manager中获得了harry对象的完整拷贝,这当然不是我们想看到的,比如我们要给harry加薪,当然不希望还要搜索该对象的其他全部拷贝,换言之我们希望磁盘上的对象布局和内存中的对象布局保持完全的一致。这就是“对象持续性”!
你可能会想到可以保存“秘书”对象的内存地址,不行的,因为,每一次加载对象都可能使用和原来截然不同的内存地址!
不过,现在好了,Java解决这个问题的办法就是采用序列化机制,下面是序列化具体的算法:
1.保存到磁盘的所有对象都获得一个序列号(1,2,3等等)
2.当要保存一个对象时,先检查该对象是否已经保存过。
3.如果以前保存过,只需写入“与已经保存的具有序列号x的对象相同”标记;否则,保存该对象。
通过以上的步骤不久解决了“对象持续性”的问题了!
看个例子吧!(在JDK1.4下调试通过)
import java.io.*;
import java.util.*;
public class ObjectRefTest
{
public static void main(String[] args)
{
Employee harry = new Employee("Harry Hacker", 50000);
Manager manager1 = new Manager("Tony Tester", 80000);
manager1.setSecretary(harry);
Employee[] staff = new Employee[2];
staff[0] = harry;
staff[1] = manager1;
try
{
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("employee.dat"));
out.writeObject(staff);
out.close();
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("employee.dat"));
Employee[] newStaff = (Employee[])in.readObject();
in.close();
/**
*通过harry对象来加薪
*将在secretary上反映出来
*/
newStaff[0].raiseSalary(10);
for (int i = 0; i < newStaff.length; i++)
System.out.println(newStaff[i]);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class Employee implements Serializable
{
public Employee() {}
public Employee(String n, double s)
{
name = n;
salary = s;
}
/**
*加薪水
*/
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString()
{
return getClass().getName()
+ "[name = "+ name
+ ",salary = "+ salary
+ "]";
}
private String name;
private double salary;
private Date hireDay;
}
class Manager extends Employee
{
public Manager(String n, double s)
{
super(n, s);
secretary = null;
}
/**
*设置秘书
*/
public void setSecretary(Employee s)
{
secretary = s;
}
public String toString()
{
return super.toString()
+ "[secretary = "+ secretary
+ "]";
}
//secretary代表秘书
private Employee secretary;
}
以上都是序列化默认的行为,实际编程中我们还会遇到许多情况导致序列化的默认行为出错,在下篇中我们将看到如何修改默认的序列化!谢谢阅读!