当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:17:00  来源:本站整理

操作"长期性"[Java编程]

赞助商链接



  本文“操作"长期性"[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
一个对比诱人的设法是用序列化技术保存程序的一些状况信息,从而将程序便利地恢复到从前的状况.但在具体实现从前,有些问题是必须办理的.假如两个对象都有指向第三个对象的句柄,该若何对这两个对象序列化呢?假如从两个对象序列化后的状况恢复它们,第三个对象的句柄只会呈目前一个对象身上吗?假如将这两个对象序列化成独立的文件,然后在代码的差别部份重新装配它们,又会得到什么后果呢?
下面这个例子对上述问题举行了很好的阐明:
//: MyWorld.java
import java.io.*;
import java.util.*;

class House implements Serializable {}

class Animal implements Serializable {
  String name;
  House preferredHouse;
  Animal(String nm, House h) { 
    name = nm; 
    preferredHouse = h;
  }
  public String toString() {
    return name + "[" + super.toString() + 
      "], " + preferredHouse + "\n";
  }
}

public class MyWorld {
  public static void main(String[] args) {
    House house = new House();
    Vector  animals = new Vector();
    animals.addElement(
      new Animal("Bosco the dog", house));
    animals.addElement(
      new Animal("Ralph the hamster", house));
    animals.addElement(
      new Animal("Fronk the cat", house));
    System.out.println("animals: " + animals);

    try {
      ByteArrayOutputStream buf1 = 
        new ByteArrayOutputStream();
      ObjectOutputStream o1 =
        new ObjectOutputStream(buf1);
      o1.writeObject(animals);
      o1.writeObject(animals); // Write a 2nd set
      // Write to a different stream:
      ByteArrayOutputStream buf2 = 
        new ByteArrayOutputStream();
      ObjectOutputStream o2 =
        new ObjectOutputStream(buf2);
      o2.writeObject(animals);
      // Now get them back:
      ObjectInputStream in1 =
        new ObjectInputStream(
          new ByteArrayInputStream(
            buf1.toByteArray()));
      ObjectInputStream in2 =
        new ObjectInputStream(
          new ByteArrayInputStream(
            buf2.toByteArray()));
      Vector animals1 = (Vector)in1.readObject();
      Vector animals2 = (Vector)in1.readObject();
      Vector animals3 = (Vector)in2.readObject();
      System.out.println("animals1: " + animals1);
      System.out.println("animals2: " + animals2);
      System.out.println("animals3: " + animals3);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
} ///:~
这里一件风趣的事情是大概是能针对一个字节数组利用对象的序列化,从而实现对任何Serializable(可序列化)对象的一个“全面复制”(全面复制意味着复制的是整个对象网,而不但是基本对象和它的句柄).复制问题将在第12章举行全面报告.
Animal对象包含了范例为House的字段.在main()中,会成立这些Animal的一个Vector,并对其序列化两次,辨别送入两个差别的数据流内.这些数据重新装配并打印出来后,可看到下面这样的后果(对象在每次运行时城市处在差别的内存位置,所以每次运行的后果有辨别):
animals: [Bosco the dog[Animal@1cc76c], House@1cc769
, Ralph the hamster[Animal@1cc76d], House@1cc769
, Fronk the cat[Animal@1cc76e], House@1cc769
]
animals1: [Bosco the dog[Animal@1cca0c], House@1cca16
, Ralph the hamster[Animal@1cca17], House@1cca16
, Fronk the cat[Animal@1cca1b], House@1cca16
]
animals2: [Bosco the dog[Animal@1cca0c], House@1cca16
, Ralph the hamster[Animal@1cca17], House@1cca16
, Fronk the cat[Animal@1cca1b], House@1cca16
]
animals3: [Bosco the dog[Animal@1cca52], House@1cca5c
, Ralph the hamster[Animal@1cca5d], House@1cca5c
, Fronk the cat[Animal@1cca61], House@1cca5c
]
当然,我们但愿装配好的对象有与本来差别的地址.但注意在animals1和animals2中呈现了相同的地址,此中包含同享的、对House对象的引用.在另一方面,当animals3恢复今后,系统没有办法知道另一个流内的对象是第一个流内对象的化身,所以会产生一个完好差别的对象网.
只要将全部东西都序列化到单独一个数据流里,就可以恢复得到与从前写入时完好一样的对象网,不会不慎造成对象的反复.当然,在写第一个和最后一个对象的时间之间,可改变对象的状况,但那必须由我们明确采纳操作——序列化时,对象会采取它们当时的任何状况(包含它们与其他对象的衔接关系)写入.
若想保存系统状况,最安全的做法是当作一种“微观”操作序列化.假如序列化了某些东西,再去做其他一些工作,再来序列化更多的东西,以此类推,那么终究将无法安全地保存系统状况.相反,应将构成系统状况的全部对象都置入单个调集内,并在一次操作里完成那个调集的写入.这样一来,一样只需一次办法调用,便可成功恢复之.
下面这个例子是一套假想的计算机帮助计划(CAD)系统,对这一办法举行了很好的演示.此外,它还为我们引入了static字段的问题——如留神联机文档,就会发现Class是“Serializable”(可序列化)的,所以只需简单地序列化Class对象,就可以实现static字段的保存.这无论若何都是一种明智的做法.
//: CADState.java
// Saving and restoring the state of a 
// pretend CAD system.
import java.io.*;
import java.util.*;

abstract class Shape implements Serializable {
  public static final int 
    RED = 1, BLUE = 2, GREEN = 3;
  private int xPos, yPos, dimension;
  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;
    dimension = dim;
  }
  public String toString() {
    return getClass().toString() + 
      " color[" + getColor() +
      "] xPos[" + xPos +
      "] yPos[" + yPos +
      "] dim[" + dimension + "]\n";
  }
  public static Shape randomFactory() {
    int xVal = r.nextInt() % 100;
    int yVal = r.nextInt() % 100;
    int dim = r.nextInt() % 100;
    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 {
  private static int color = RED;
  public Circle(int xVal, int yVal, int dim) {
    super(xVal, yVal, dim);
  }
  public void setColor(int newColor) { 
    color = newColor;
  }
  public int getColor() { 
    return color;
  }
}

class Square extends Shape {
  private static int color;
  public Square(int xVal, int yVal, int dim) {
    super(xVal, yVal, dim);
    color = RED;
  }
  public void setColor(int newColor) { 
    color = newColor;
  }
  public int getColor() { 
    return color;
  }
}

class Line extends Shape {
  private 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);
  }
  public void setColor(int newColor) { 
    color = newColor;
  }
  public int getColor() { 
    return color;
  }
}

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.addElement(Circle.class);
      shapeTypes.addElement(Square.class);
      shapeTypes.addElement(Line.class);
      // Make some shapes:
      for(int i = 0; i < 10; i++)
        shapes.addElement(Shape.randomFactory());
      // 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's 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 shapes:
    System.out.println(shapes);
  }
} ///:~
Shape(多少形状)类“实现了可序列化”(implements Serializable),所以从Shape担当的任何东西也城市自动“可序列化”.每个Shape都包含了数据,并且每个衍生的Shape类都包含了一个特别的static字段,用于决意全部那些范例的Shape的颜色(如将一个static字段置入底子类,后果只会产生一个字段,因为static字段未在衍生类中复制).可对底子类中的办法举行覆盖处理,以便为差别的范例设置颜色(static办法不会动态绑定,所以这些都是普通的办法).每次调用randomFactory()办法时,它城市成立一个差别的Shape(Shape值采取随机值).
Circle(圆)和Square(矩形)属于对Shape的直接扩大;唯一的差别是Circle在定义时会初始化颜色,而Square在构建器中初始化.Line(直线)的问题将留到今后谈论.
在main()中,一个Vector用于包容Class对象,而另一个用于包容形状.若不供应呼应的号令行参数,就会成立shapeTypes Vector,并增添Class对象.然后成立shapes Vector,并增添Shape对象.接下来,全部static color值城市设成GREEN,并且全部东西城市序列化到文件CADState.out.
若供应了一个号令行参数(假定CADState.out),便会翻开那个文件,并用它恢复程序的状况.无论在哪类情形下,后果产生的Shape的Vector城市打印出来.下面列出它某一次运行的后果:
>java CADState
[class Circle color[3] xPos[-51] yPos[-99] dim[38]
, class Square color[3] xPos[2] yPos[61] dim[-46]
, class Line color[3] xPos[51] yPos[73] dim[64]
, class Circle color[3] xPos[-70] yPos[1] dim[16]
, class Square color[3] xPos[3] yPos[94] dim[-36]
, class Line color[3] xPos[-84] yPos[-21] dim[-35]
, class Circle color[3] xPos[-75] yPos[-43] dim[22]
, class Square color[3] xPos[81] yPos[30] dim[-45]
, class Line color[3] xPos[-29] yPos[92] dim[17]
, class Circle color[3] xPos[17] yPos[90] dim[-76]
]

>java CADState CADState.out
[class Circle color[1] xPos[-51] yPos[-99] dim[38]
, class Square color[0] xPos[2] yPos[61] dim[-46]
, class Line color[3] xPos[51] yPos[73] dim[64]
, class Circle color[1] xPos[-70] yPos[1] dim[16]
, class Square color[0] xPos[3] yPos[94] dim[-36]
, class Line color[3] xPos[-84] yPos[-21] dim[-35]
, class Circle color[1] xPos[-75] yPos[-43] dim[22]
, class Square color[0] xPos[81] yPos[30] dim[-45]
, class Line color[3] xPos[-29] yPos[92] dim[17]
, class Circle color[1] xPos[17] yPos[90] dim[-76]
]
从中可以看出,xPos,yPos以及dim的值都已成功保存和恢复出来.但在获得static信息时却呈现了问题.全部“3”都已进入,但没有正常地出来.Circle有一个1值(定义为RED),而Square有一个0值(记着,它们是在构建器里初始化的).看上去仿佛static根本没有得到初始化!实情恰是如此——固然类Class是“可以序列化的”,但却不能按我们但愿的工作.所以假定想序列化static值,必须亲身着手.
这恰是Line中的serializeStaticState()和deserializeStaticState()两个static办法的用处.可以看到,这两个办法都是作为存储和恢复进程的一部份明确调用的(注意写入序列化文件和从中读回的次序不能改变).所认为了使CADState.java精确运行起来,必须采取下述三种办法之一:
(1) 为多少形状增添一个serializeStaticState()和deserializeStaticState().
(2) 删除Vector shapeTypes以及与之有关的全部代码
(3) 在多少形状内增添对新序列化和撤消序列化静态办法的调用
要注意的另一个问题是安全,因为序列化处理也会将private数据保存下来.若有需求保密的字段,应将其标志成transient.但在这之后,必须计划一种安全的信息保存办法.这样一来,一旦需求恢复,便可以重设那些private变量.
  以上是“操作"长期性"[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: 与您的QQ/BBS好友分享!
  • 好的评价 如果您觉得此文章好,就请您
      0%(0)
  • 差的评价 如果您觉得此文章差,就请您
      0%(0)

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .