Использование readObject/writeObject в Сериализации
Я просматривал эту статью, чтобы лучше понять процесс сериализации Java. Когда дело доходит до использования readObject/writeObject
Я мог видеть два варианта использования:
- Мы можем использовать
writeObject
зашифровать байт-код перед сериализацией. С точки зрения безопасности это хорошо. - мы можем использовать
readObject
чтобы выполнить любой конкретный фрагмент кода, который должен выполняться сразу после десериализации, и, конечно, из пункта № 1, мы можем даже использоватьreadObject
расшифровать байт-код, который был зашифрован при сериализации объекта.
Есть ли какой-либо другой практический сценарий, с которым вы сталкивались при сериализации / десериализации объектов путем написания метода customR readObject/writeObject? Или если бы вы могли указать мне в любое место, где я мог бы увидеть некоторые приличные и практические использования readObject/writeObject?
7 ответов
Изготовленный на заказ readObject
Методы также полезны, когда вам нужно инициализировать временные (не сериализованные) поля после десериализации объекта.
Кстати, ознакомьтесь с Effective Java, глава 11 (я не уверен, какой номер главы / элемента указан во 2-м изд.). Это отличное чтение по сериализации.
Вы можете реализовать свой собственный readObject / writeObject по соображениям производительности, или по причинам обратной совместимости, или потому что поле, которое вы хотите сериализовать, не сериализуемо.
Хорошие примеры readObject / writeObject я бы посмотрел в исходном коде, который поставляется с JDK. Или я бы попробовал http://www.google.co.uk/search?q=readObject+writeObject+examples
Там может быть несколько причин для использования пользовательских сериализации:
- Спектакль.
- Взаимодействие с внешними системами. (За пределами вашей досягаемости или даже просто не-Java системы.)
- Нуждается в удобочитаемом формате.
- Поддержка старых версий сериализованных классов.
Чтобы назвать только несколько, но я уверен, что есть еще много.
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private int empno;
private String ename;
private String job;
// setter & 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();
}
}
Мне кажется, что расшифровку лучше выполнить с помощью ObjectOutputStream, основанного на CipherOutputsStream.
Наиболее важное использование writeObject/readObject - это если вы хотите сохранить сериализацию стабильной в течение нескольких ревизий кода. Ваше внутреннее представление (переменные-члены) может измениться, но сериализация должна быть стабильной, поскольку существует старая система, с которой вы общаетесь (например, путем чтения старых данных из файлов).
Но я предпочитаю интерфейс Externalizable для этих случаев, так как он проще в использовании (без неявных вызовов и методов, о которых знает только jvm).
Методы 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();
}
}
Теперь объекты подкласса нельзя сериализовать.
Один интересный вариант использования
readObject
является реализацией сериализуемого Singleton, где мы хотим, чтобы экземпляр 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
здесь, чтобы всегда возвращать ссылку на экземпляр singleton вместо десериализованного объекта.