Ответы на вопросы по ревью 4. Java io. Ключевым понятием здесь является понятие потока
Скачать 1.93 Mb.
|
Переопределение сериализации в интерфейсе SerializableЕсли у сериализуемого объекта реализован один из следующих методов, то механизм сериализации будет использовать его, а не метод по умолчанию : writeObject - запись объекта в поток; readObject - чтение объекта из потока; writeReplace - позволяет заменить себя экземпляром другого класса перед записью; readResolve - позволяет заменить на себя другой объект после чтения. Ниже приводятся примеры использования данных методов. Сериализация не безопаснаДвоичный формат сериализации полностью документирован и обратим. Для того, чтобы определить параметры объекта и его значения, достаточно просто вывести содержимое сериализованного потока в консоль. Это имеет некоторые связанные с безопасностью неприятные последствия. Например, при выполнении удаленного вызова метода с помощью RMI все закрытые поля пересылаемых по сети объектов выглядят в потоке сокета почти как обычный текст, что, конечно же, нарушает даже самые простые правила безопасности. К счастью разработчиков Java Serialization API позволяет "вклиниться" в процесс сериализации, и изменить (или запутать) поля данных как перед сериализацией, так и после десериализации. Это можно сделать, определив методы writeObject, readObject объекта Serializable. Изменение сериализованных данных, writeObject, readObjectЧтобы изменить процесс сериализации в классе Person реализуем метод writeObject. Для модифицирования процесса десериализации определим в том же классе метод readObject. При реализации этих методов необходимо корректно восстановить данные. private void writeObject(ObjectOutputStream stream) throws IOException { // "Криптование"/скрытие истинного значения age = age << 2; stream.defaultWriteObject(); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); // "Декриптование"/восстановление истинного значения age = age >> 2; } В данных методах значение возраста age просто умножается на 4 при записи объекта, а при восстановлении - делится на четыре. Алгоритм, конечно же можно усложнить; в примере он представлен только для демонстрации возможностей сериализации. Сериализация и рефакторинг кодаСериализация позволяет вносить небольшие изменения в структуру класса, так что даже после рефакторинга класс ObjectInputStream по-прежнему будет с ним прекрасно работать. К наиболее важным изменениям, с которыми спецификация Java Object Serialization может справляться автоматически: добавление новых полей в класс; изменение полей из статических в нестатические; изменение полей из транзитных в нетранзитные. Обратные изменения (нестатических и нетранзитных полей в статические и транзитные) или удаление полей требуют определенной дополнительной обработки в зависимости от того, какая степень обратной совместимости требуется. Рефакторинг сериализованного классаДля тестирования сериализации с измененной структурой класса Person на основе предыдущего примера необходимо проделать следующие предварительные шаги : Создать файл данных с использованием метода setUpBeforeClass класса JUnitPerson и блокировкой удаления файла в методе tearDownAfterClass; можно закоментировать строку удаления файла. Блокировать создание файла данных в методе setUpBeforeClass класса JUnitPerson при следующем выполнении; также можно закоментировать строки создание файла. Изменить код класса Person, как это представлено в следующем листинге. Листинг изменений класса Person// Определение вне класса Person enum Gender { Male, Female } // Следующие изменения внутри класса Person // Переменная private Gender gender; // Методы get и set public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } // Текстовое описание объекта public String toString() { return "[Person: firstName = " + firstName + ", lastName = " + lastName + ", gender = " + gender + ", age = " + age + ", spouse = " + spouse.getFirstName() + "]"; } Теперь можно выполнить тест testSerialization класса JUnitPerson и увидеть, что тест прошел успешно, т.е. класс ObjectInputStream прочитал данные и объект был восстановлен корректно. При желании можно в конце кода testSerialization вставить строку fail(alex.toString()); чтобы убедиться, что значения объекта восстановлены правильно, и что параметр gender равен null. |