Философия Java3
Шрифт:
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»; //
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);
}
} /* Output:
[class Circlecolor[3] xPos[58] yPos[55] dim[93] class Squarecolor[3] xPos[61] yPos[61] dim[29] продолжение &
. class Linecolor[3] xPos[68] yPos[0] dim[22]
. class Circlecolor[3] xPos[7] yPos[88] dim[28]
. class Squarecolor[3] xPos[51] yPos[89] dim[9]
. class Linecolor[3] xPos[78] yPos[98] dim[61]
. class Circlecolor[3] xPos[20] yPos[58] dim[16]
, class Squarecolor[3] xPos[40] yPos[ll] dim[22]
. class Linecolor[3] xPos[4] yPos[83] dim[6]
, class Circlecolor[3] xPos[75] yPos[10] dim[42] ]
*/// ~
Класс Shape реализует интерфейс Serializable, поэтому все унаследованные от него классы по определению поддерживают сериализацию и восстановление. В каждой фигуре Shape содержатся некоторые данные, и в каждом унаследованном от Shape классе имеется статическое (static) поле, которое определяет цвет фигуры. (Если бы мы поместили статическое поле в базовый класс, то получили бы одно поле для всех фигур, поскольку статические поля в производных классах не копируются.) Для задания цвета некоторого типа фигур можно переопределить методы базового класса (статические методы не используют динамическое связывание). Метод randomFactory создает при каждом вызове новую фигуру, используя для этого случайные значения Shape.
Классы Circle и Square — простые подклассы Shape, различающиеся только способом инициализации поля color: окружность (Circle) задает значение этого поля в месте определения, а прямоугольник (Square) инициализирует его в конструкторе. Класс Line мы обсудим чуть позже.
В методе main один список ArrayList используется для хранения объектов Class, а другой — для хранения фигур.
Восстановление объектов выполняется вполне тривиально:
// io/RecoverCADState java
// Восстановление состояния вымышленной системы CAD // {RunFirst StoreCADState} import java io.*. import java util *.
public class RecoverCADState {
@SuppressWarni ngs("unchecked")
public static void main(Stnng[] args) throws Exception { ObjectlnputStream in = new ObjectInputStream( new Fi1eInputStream("CADState.out")). //
(List<Class<? extends Shape») in readObject О. Line deserializeStaticState(in); List<Shape> shapes = (List<Shape>)in.readObject. System out println(shapes).
}
} /* Output
[class Circlecolor[l] xPos[58] yPos[55] dim[93] . class Squarecolor[0] xPos[61] yPos[61] dim[29] . class Linecolor[3] xPos[68] yPos[0] dim[22] . class Circlecolor[l] xPos[7] yPos[88] dim[28] . class Squarecolor[0] xPos[51] yPos[89] dim[9] . class Linecolor[3] xPos[78] yPos[98] dim[61]
. class
, class
, class
, class
]
*/// ~
Мы видим, что значения переменных xPos, у Pos и dim сохранились и были успешно восстановлены, однако при восстановлении статической информации произошло что-то странное. При записи все статические поля color имели значение 3, но восстановление дало другие результаты. В окружностях значением стала единица (то есть константа RED), а в прямоугольниках поля color вообще равны нулю (помните, в этих объектах инициализация проходит в конструкторе). Похоже, статические поля вообще не сериализовались! Да, это именно так — хотя класс Class и реализует интерфейс Serializable, происходит это не так, как нам хотелось бы. Отсюда, если вам понадобится сохранить статические значения, делайте это самостоятельно.
Именно для этой цели предназначены методы serializeStaticState и dese-rializeStaticState класса Line. Вы можете видеть, как они вызываются в процессе сохранения и восстановления системы. (Заметьте, порядок действий при сохранении информации должен соблюдаться и при ее десериализации.) Поэтому для правильного выполнения этих программ необходимо сделать следующее:
1. Добавьте методы serializeStaticState и deserializeStaticState во все фигуры Shape.
2. Уберите из программы список shapeTypes и весь связанный с ним код.
3. При сериализации и восстановлении вызывайте новые методы для сохранения статической информации.
Также стоит позаботиться о безопасности, ведь сериализация сохраняет и закрытые (private) поля. Если в вашем объекте имеется конфиденциальная информация, ее необходимо пометить как transient. Но в таком случае придется подумать о безопасном способе хранения такой информации, ведь при восстановлении объекта необходимо восстанавливать все его данные.
Предпочтения
В пакете JDK 1.4 появился программный интерфейс API для работы с предпочтениями (preferences). Предпочтения гораздо более тесно связаны с долговременным хранением, чем механизм сериализации объектов, поскольку они позволяют автоматически сохранять и восстанавливать вашу информацию. Однако они применимы лишь к небольшим, ограниченным наборам данных — хранить в них можно только примитивы и строки, и длина строки не должна превышать 8 Кбайт (не так уж мало, но вряд ли подойдет для решения серьезных задач). Как и предполагает название нового API, предпочтения предназначены для хранения и получения информации о предпочтениях пользователя и конфигурации программы.