Философия Java3
Шрифт:
new ByteArrayOutputStream; ObjectOutputStream o2 = new 0bject0utputStream(buf2):
02 writeObject(animals).
// Теперь восстанавливаем записанные объекты ObjectlnputStream inl = new ObjectInputStream(
new ByteArrayInputStream(bufl toByteArrayO)). ObjectlnputStream in2 = new ObjectInputStream(
new ByteArrayInputStream(buf2 toByteArrayO));
List
animalsl = (List)inl readObjectO, animals2 = (List)inl readObjectO, ammals3 = (List)in2 readObjectO, printC'animalsl " + animalsl); pnnt("animals2. " + animals2); print("animals3 " + animals3).
}
} /* Output (Sample)
animals- [Bosco the dog[Animal@addbfl]. House@42e816 . Ralph the hamster[Animal@9304bl]. House@42e816
, Molly the cat[Animal@190dll]. House@42e816 ]
animalsl [Bosco the dog[Animal@de6f34]. House@156ee8e . Ralph the hamster[Animal@47b480]. House@156ee8e
, Molly the cat[Animal@19b49e6], House@156ee8e ]
animals2 [Bosco the dog[Animal@de6f34], House@156ee8e , Ralph the hamster[Animal@47b480]. House@156ee8e
. Molly the cat[Animal@19b49e6], House@156ee8e ]
animals3 [Bosco the dog[Animal@10d448], House@e0elc6 , Ralph the hamster[Animal@6calc], House@e0elc6
. Molly the cat[Animal@lbf216a]. House@e0elc6 ]
*/// ~
В
Объекты Animal содержат поля типа House. В методе main создается список ArrayList с несколькими объектами Animal, его дважды записывают в один поток и еще один раз — в отдельный поток. Когда эти списки восстанавливают и распечатывают, получается приведенный ранее результат (объекты при каждом запуске программы будут располагаться в различных областях памяти).
Конечно, нет ничего удивительного в том, что восстановленные объекты и их оригиналы будут иметь разные адреса. Но заметьте тот факт, что адреса в восстановленных объектах animalsl и animals2 совпадают, вплоть до повторения ссылок на объект House, общий для обоих списков. С другой стороны, при восстановлении списка animals3 система не имеет представления о том, что находящиеся в них объекты уже были восстановлены и имеются в программе, поэтому она создает совершенно иное семейство взаимосвязанных объектов.
Если вы будете проводить сериализацию с использованием единого выходного потока, сохраненная сеть объектов гарантированно восстановится в первоначальном виде, без излишних повторений объектов. Конечно, записать объекты можно тогда, когда они еще не приняли окончательного состояния, но это уже на вашей совести — сохраненные объекты останутся в том состоянии, в котором вы их записали (с теми связями, что у них были на момент сериализации).
Если уж необходимо зафиксировать состояние системы, безопаснее всего сделать это в рамках «атомарной» операции. Если вы сохраняете что-то, затем выполняете какие-то действия, снова сохраняете данные и т. д., у вас не получится безопасного хранилища состояния системы. Вместо этого следует поместить все объекты, являющиеся слагаемыми состояния системы в целом, в контейнер и сохранить этот контейнер единой операцией. Затем можно восстановить его вызовом одного метода.
Следующий пример — имитатор воображаемой системы автоматизированного проектирования (CAD), в котором используется такой подход. Вдобавок в нем продемонстрировано
сохранение статических (static) нолей — если вы взглянете на документацию JDK, то увидите, что класс Class реализует интерфейс Serializable, поэтому для сохранения статических данных достаточно сохранить объект Class. Это достаточно разумное решение.//• i o/StoreCADState.java
// Сохранение состояния вымышленной системы CAD
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 rand = new Random(47), private static int counter = 0; public abstract void setColor(int newColor); public abstract int getColorO; public Shape(int xVal. int yVal, int dim) { xPos = xVal; yPos = yVal; dimension = dim;
}
public String toStringO { return getClassO +
"color[" + getColorO + "] xPos[" + xPos + "] yPos[" + yPos + "] dim[" + dimension + "]\n";
}
public static Shape randomFactory { int xVal = rand.nextlnt(lOO); int yVal = rand.nextlnt(lOO); int dim = rand.nextlnt(lOO); switch(counter++ % 3) { default:
case 0: return new Circle(xVal. yVal. dim); case 1: return new Square(xVal. yVal, dim); case 2: return new LineCxVal. yVal. dim);
}
class Circle extends Shape {
private static int color = RED;
public CircleCint xVal. int yVal, int dim) {
super(xVal, yVal, dim).
public void setColor(int newColor) { color = newColor. } public int getColorO { return color. }
}
class Square extends Shape { private static int color, public Squared nt xVal. int yVal. int dim) { super(xVal. yVal. dim). color = RED.
}
public void setColor(int newColor) { color = newColor. } public int getColorO { return color. }
}
class Line extends Shape {
private static int color = RED. public static void
serializeStaticState(ObjectOutputStream os) throws IOException { os writelnt(color); } public static void
deserializeStaticState(ObjectInputStream os) throws IOException { color = os.readlntO. } public Line(int xVal. int yVal. int dim) { super(xVal, yVal, dim);
}
public void setColor(int newColor) { color = newColor; } public int getColorO { return color; }
}
public class StoreCADState {
public static void main(String[] args) throws Exception { List<Class<? extends Shape» shapeTypes =
new ArrayList<Class<? extends Shape»; // Добавление ссылок на объекты класса: shapeTypes add(Circle.class), shapeTypes add(Square.class); shapeTypes.add(Line.class); List<Shape> shapes = new ArrayList<Shape>; // Создание фигур, for(int i = 0; i < 10; i++)
shapes add(Shape.randomFactory); // Назначение всех статических цветов: for(int i = 0; i < 10. i++)
((Shape)shapes.get(i)).setColor(Shape.GREEN); // Сохранение вектора состояния: ObjectOutputStream out = new ObjectOutputStream( new FileOutputStreamC'CADState.out")); out.writeObject(shapeTypes); Line.serializeStaticState(out); out.writeObject(shapes); // Вывод фигур: System out.printin(shapes);