一、序列化对象网
如果两个对象都有指向第三个对象的句柄,只要将所有的东西都序列化到单独一个数据流里,就能恢复获得与以前写入时完全一样的对象网,不会造成对象的重复。若想保存系统状态,应将构成系统状态的所有对象都置入单个集合内,并在一次操作里完成对象的写入,这样只需一次方法调用,即可成功恢复。
二、反序列化static信息
首先看一个例子:
abstract class Shape implements Serializable{
public static final int RED = 1, BLUE = 2, GREEN
= 3;
private int xPos, yPos, dimenson;
private static Random r = new Random();
private static int counter = 0;
abstract public void setColor(int
newColor);
abstract public int getColor();
public Shape(int xVal, int yVal, int dim){
xPos = xVal;
yPos = yVal;
dimenson = dim;
}
public String toString(){
return getClass().getName()+"
color["+getColor()+
"] xPos["+xPos+"]
yPos["+yPos+"] dimenson["+dimenson+"] \n";
}
public static Shape randomFactroy(){
int xVal = r.nextInt()0;
int yVal = r.nextInt()0;
int dim = r.nextInt()0;
switch(counter++ % 3){
default:
case 0: return new Circle(xVal,
yVal, dim);
case 1: return new Square(xVal,
yVal, dim);
case 2: return new Line(xVal,
yVal, dim);
}
}
}
class Circle extends Shape{
public static int color = RED;
public Circle(int xVal, int yVal, int dim){
super(xVal, yVal, dim);
}
@Override
public int getColor() {
return color;
}
@Override
public void setColor(int newColor) {
color = newColor;
}
}
class Square extends Shape{
public static int color;
public Square(int xVal, int yVal, int dim){
super(xVal, yVal, dim);
color = RED;
}
@Override
public int getColor() {
return color;
}
@Override
public void setColor(int newColor) {
color = newColor;
}
}
class Line extends Shape{
public static int color = RED;
public static void
serializeStaticState(ObjectOutputStream os) throws
IOException{
os.writeInt(color);
}
public static void
deserializeStaticState(ObjectInputStream os) throws
IOException{
color = os.readInt();
}
public Line(int xVal, int yVal, int dim){
super(xVal, yVal, dim);
}
@Override
public int getColor() {
return color;
}
@Override
public void setColor(int newColor) {
color = newColor;
}
}
public class CADState {
public static void main(String[] args)throws
Exception{
Vector shapeTypes,
shapes;
if(args.length == 0){
shapeTypes =
new Vector();
shapes = new
Vector();
//Add handles
to the class objects:
shapeTypes.add(Circle.class);
shapeTypes.add(Square.class);
shapeTypes.add(Line.class);
//make some
shapes:
for(int i=0;
i<10; i++)
shapes.addElement(Shape.randomFactroy());
//Set all the
static colors to GREEN:
for(int i=0;
i<10; i++)
((Shape)shapes.elementAt(i)).setColor(Shape.GREEN);
//Save the
state vector:
ObjectOutputStream
out = new ObjectOutputStream(new
FileOutputStream("CADState.out"));
out.writeObject(shapeTypes);
Line.serializeStaticState(out);
out.writeObject(shapes);
}else{
//There is a
command-line argument:
ObjectInputStream
in = new ObjectInputStream(new FileInputStream(args[0]));
//Read in the
same order they were written:
shapeTypes =
(Vector)in.readObject();
Line.deserializeStaticState(in);
shapes =
(Vector)in.readObject();
}
//display the shape:
System.out.println(shapes);
}
}
类Circle,Square,Line继承了可序列化的Shape,所以这三个类可自动序列化。衍生类中都包含了数据,每个都包含了一个特殊的static字段,用于决定其颜色(如将一个static字段置入基础类,结果只会产生一个字段,static属性只属于类)。每次调用randomFactory()方法都会创建一个不用的shape。Cirlcle和Square是对Shape的直接扩展,唯一区别在于Circle在定义时初始化颜色,Square在构造方法里初始化。
在main中一个Vector用于容纳Class,另一个用于容纳形状,若不提供相应的命令行参数,就会创建shapeTypes
Vector,并添加Class对象,然后创建shapes Vector对象,并添加Shape对象。接下来所有static
color值设置为GREEN,所有东西都序列化到CADState.out文件中。若提供了命令行参数(比如CADState.out),便会打开那个文件,恢复它的程序状态。
这是某一次的运行结果:
[com.dong.javaThinking.Circle color[3] xPos[95]
yPos[98] dimenson[56]
, com.dong.javaThinking.Square color[3] xPos[23]
yPos[-80] dimenson[-99]
, com.dong.javaThinking.Line color[3] xPos[-16]
yPos[-56] dimenson[-24]
, com.dong.javaThinking.Circle color[3] xPos[19]
yPos[43] dimenson[-66]
, com.dong.javaThinking.Square color[3] xPos[18]
yPos[45] dimenson[60]
, com.dong.javaThinking.Line color[3] xPos[45]
yPos[27] dimenson[53]
, com.dong.javaThinking.Circle color[3] xPos[45]
yPos[-44] dimenson[-89]
, com.dong.javaThinking.Square color[3] xPos[-53]
yPos[74] dimenson[-15]
, com.dong.javaThinking.Line color[3] xPos[80]
yPos[44] dimenson[-36]
, com.dong.javaThinking.Circle color[3] xPos[-27]
yPos[47] dimenson[-33]
]
这是CADState.out文件读出的结果:
[com.dong.javaThinking.Circle color[1] xPos[95]
yPos[98] dimenson[56]
, com.dong.javaThinking.Square color[0] xPos[23]
yPos[-80] dimenson[-99]
, com.dong.javaThinking.Line color[3] xPos[-16]
yPos[-56] dimenson[-24]
, com.dong.javaThinking.Circle color[1] xPos[19]
yPos[43] dimenson[-66]
, com.dong.javaThinking.Square color[0] xPos[18]
yPos[45] dimenson[60]
, com.dong.javaThinking.Line color[3] xPos[45]
yPos[27] dimenson[53]
, com.dong.javaThinking.Circle color[1] xPos[45]
yPos[-44] dimenson[-89]
, com.dong.javaThinking.Square color[0] xPos[-53]
yPos[74] dimenson[-15]
, com.dong.javaThinking.Line color[3] xPos[80]
yPos[44] dimenson[-36]
, com.dong.javaThinking.Circle color[1] xPos[-27]
yPos[47] dimenson[-33]
]
比较写入与读出的结果会发现:Circle和Square的color分别变成了1和0(这是这两个类中的初始化值),而Line中读出的color没有改变,这正是Line中serializeStaticState()和deserializeStaticState()方法的用途,即想获取序列化static的值,必须亲自动手。这两个方法都是作为存储和恢复进程明确调用的(注意写入序列化文件和从中读回的顺序不能改变)。
为了使CADState.java 正确运行起来,必须采用下述三种方法之一:
(1)
为几何形状添加一个serializeStaticState()和deserializeStaticState()。
(2) 删除Vector shapeTypes 以及与之有关的所有代码
(3) 在几何形状内添加对新序列化和撤消序列化静态方法的调用
要注意的另一个问题是安全,因为序列化处理也会将private 数据保存下来。若有需要保密的字段,应将其
标记成transient。但在这之后,必须设计一种安全的信息保存方法。这样一来,一旦需要恢复,就可以重
设那些private 变量。