#java #serialization
#java #сериализация
Вопрос:
Я просматривал эту статью, чтобы больше понять процесс сериализации Java. Когда дело доходит до использования readObject/writeObject
, я мог видеть два варианта использования:
- Мы можем использовать
writeObject
для шифрования байтового кода перед его сериализацией. С точки зрения безопасности, это хорошая вещь. - мы можем использовать
readObject
для выполнения любого конкретного фрагмента кода, который необходимо выполнить сразу после десериализации, и, отклоняясь от пункта 1, мы можем даже использоватьreadObject
для расшифровки байтового кода, который был удален при сериализации объекта.
Есть ли какой-либо другой практический сценарий, с которым вы столкнулись при сериализации / десериализации объектов путем написания пользовательского метода readObject / writeObject? Или, если бы вы могли указать мне на любое место, где я мог бы увидеть некоторые достойные и практические применения readObject / writeObject?
Комментарии:
1. Пожалуйста, обновите ссылку на статью.
Ответ №1:
Пользовательские readObject
методы также полезны, когда вам нужно инициализировать временные (несериализованные) поля после десериализации объекта.
Кстати, ознакомьтесь с Эффективной Java, глава 11 (я не уверен, какой номер главы / элемента во 2-м издании.). Это отличное чтение о сериализации.
Комментарии:
1. На самом деле это так… Я искал некоторые комментарии о том, как именно это было использовано в вашем приложении. Хотя пользовательская сериализация — это необычная вещь, но инициализация временных или статических переменных в readObject() часто используется.
2. @Vicky: «на самом деле это так» как в, эффективная ссылка Java отвечает на ваш вопрос?
3. да, я сейчас просматриваю книгу. Но ваш ответ об инициализации переходного поля помог мне.
Ответ №2:
Вы можете реализовать свой собственный readObject / writeObject по соображениям производительности или обратной совместимости, или потому, что поле, которое вы хотите сериализовать, не является сериализуемым.
Хорошие примеры readObject / writeObject я бы поискал в исходном коде, который поставляется вместе с JDK. Или я бы попробовал http://www.google.co.uk/search ?q=readObject writeObject примеры
Ответ №3:
Может быть несколько причин для использования пользовательской сериализации:
- Производительность.
- Взаимодействие с внешними системами. (Недоступные для вас или даже просто не Java-системы.)
- Требуется формат, понятный человеку.
- Поддержка более старых версий сериализованных классов.
Назову лишь некоторые, но я уверен, что их гораздо больше.
Ответ №4:
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private int empno;
private String ename;
private String job;
// setter amp; getter
@Override
public String toString() {
return "Employee [empno=" empno ", ename=" ename ", job=" job
"]";
}
private void writeObject(ObjectOutputStream out) throws IOException {
// default serialization
// out.defaultWriteObject();
// custom serialization
out.writeInt(empno);
out.writeUTF(ename);
// out.writeUTF(job); //job will not serialize
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
// default deSerialization
// in.defaultReadObject();
// custom deSerialization
empno = in.readInt();
ename = in.readUTF();
// this.job = in.readUTF();
}
}
Ответ №5:
Я думаю, что дешифрование может быть лучше выполнено с использованием ObjectOutputStream на основе CipherOutputsStream.
Наиболее важное использование writeObject / readObject — это если вы хотите сохранить стабильность сериализации при нескольких версиях кода. Ваше внутреннее представление (переменные-члены) может измениться, но сериализация должна быть стабильной, поскольку вы взаимодействуете со старой системой (например, путем чтения старых данных из файлов).
Но я предпочитаю экстернализуемый интерфейс для этих случаев, поскольку он проще в использовании (никаких неявных вызовов и методов, о которых знает только jvm).
Комментарии:
1. Является ли это причиной того, что (например) реализация LinkedList в Java реализует методы writeObject / readObject?
Ответ №6:
Методы writeObject() и readObject() также используются для предотвращения сериализации объекта.
Когда суперкласс реализует Serializable, все его подклассы сериализуемы по умолчанию. Но если вы хотите, чтобы подкласс не был сериализуемым, переопределите методы writeObject() и readObject() в подклассе, как показано ниже
class Parent implements Serailizable
{
int id;
}
class child extends Parent
{
String name;
private void writeObject(ObjectOutputStream out) throws NotSerializableException
{
throw new NotSerializableException();
}
private void readObject(ObjectInputStream in) throws NotSerializableException
{
throw new NotSerializableException();
}
}
Теперь объекты подкласса не могут быть сериализованы.
Ответ №7:
Одним из интересных вариантов использования для readObject
является реализация сериализуемого синглтона, где мы хотим, чтобы экземпляр Singleton сохранял значения полей, которые были определены до сериализации. Итак, во время десериализации экземпляра Singleton мы хотим, чтобы значения полей были точно такими же, как до сериализации, даже если они могли быть изменены перед сериализацией и десериализацией.
@Serial
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
boolean deserializedField = objectInputStream.readFields().get("field", isField());
instance.setField(deserializedField);
}
@Serial
public Object readResolve() {
return instance;
}
Кроме того, здесь нам нужен другой полезный метод readResolve
, чтобы всегда возвращать ссылку на одноэлементный экземпляр вместо десериализованного объекта.