Что подразумевается под «сериализацией объекта»? Не могли бы вы объяснить это несколькими примерами?
Возможный дубликат Что такое сериализация и десериализация объектов?




Сериализация берет «живой» объект в памяти и преобразует его в формат, который можно где-то сохранить (например, в памяти, на диске), а затем «десериализовать» обратно в живой объект.
Сериализация - это процесс преобразования состояния объекта в биты, чтобы его можно было сохранить на жестком диске. Когда вы десериализуете тот же объект, он сохранит свое состояние позже. Он позволяет воссоздавать объекты без необходимости сохранять свойства объектов вручную.
http://en.wikipedia.org/wiki/Serialization
«... чтобы его можно было сохранить на жестком диске». Или передается по бинарному протоколу.
Сериализация - это преобразование объекта в серию байтов, чтобы объект можно было легко сохранить в постоянное хранилище или передать по каналу связи. Затем поток байтов можно десериализовать - преобразовать в реплику исходного объекта.
это обязательно? я должен сериализовать данные перед их отправкой? в какой формат он конвертируется?
@FranciscoCorralesMorales - за кулисами все данные будут сериализованы перед отправкой в потоке. Сколько вам нужно сделать и в каком формате это будет, зависит от того, какую платформу и библиотеки вы используете.
@FranciscoCorralesMorales Как ты это говоришь? я имею в виду, вы говорите, что формат зависит от платформы и библиотек. Я действительно хочу знать формат.
Применимо ли это только к объектам? Можем ли мы сериализовать переменные (объявленные без использования объектов)?
Только объекты @Rumado
Я нашел аналогичный ответ на tecmentor.in, я думаю, что действительно помогу разобраться в деталях.
Сериализация - это процесс преобразования объекта Java в байтовый массив, а затем снова в объект с его сохраненным состоянием. Полезно для различных вещей, таких как отправка объектов по сети или кеширование данных на диск.
Прочтите больше из эта короткая статья, в которой достаточно хорошо объясняется программная часть процесса, а затем перейдите к Сериализуемый javadoc. Вам также может быть интересно прочитать этот связанный вопрос.
Вы можете думать о сериализации как о процессе преобразования экземпляра объекта в последовательность байтов (которые могут быть двоичными или нет, в зависимости от реализации).
Это очень полезно, когда вы хотите передать данные одного объекта по сети, например, от одной JVM к другой.
В Java механизм сериализации встроен в платформу, но вам необходимо реализовать интерфейс Сериализуемый, чтобы сделать объект сериализуемым.
Вы также можете предотвратить сериализацию некоторых данных в вашем объекте, отметив атрибут как преходящий.
Наконец, вы можете переопределить механизм по умолчанию и указать свой собственный; это может быть подходящим в некоторых особых случаях. Для этого вы используете один из скрытые функции в Java.
Важно отметить, что сериализуется «значение» объекта или его содержимое, а не определение класса. Таким образом, методы не сериализуются.
Вот очень простой образец с комментариями, чтобы облегчить его чтение:
import java.io.*;
import java.util.*;
// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {
// These attributes conform the "value" of the object.
// These two will be serialized;
private String aString = "The value of that string";
private int someInteger = 0;
// But this won't since it is marked as transient.
private transient List<File> unInterestingLongLongList;
// Main method to test.
public static void main( String [] args ) throws IOException {
// Create a sample object, that contains the default values.
SerializationSample instance = new SerializationSample();
// The "ObjectOutputStream" class has the default
// definition to serialize an object.
ObjectOutputStream oos = new ObjectOutputStream(
// By using "FileOutputStream" we will
// Write it to a File in the file system
// It could have been a Socket to another
// machine, a database, an in memory array, etc.
new FileOutputStream(new File("o.ser")));
// do the magic
oos.writeObject( instance );
// close the writing.
oos.close();
}
}
Когда мы запускаем эту программу, создается файл «o.ser», и мы можем видеть, что произошло за ним.
Если мы изменим значение: someInteger на, например, Целое число.MAX_VALUE, мы можем сравнить вывод, чтобы увидеть, в чем разница.
Вот скриншот, демонстрирующий именно эту разницу:

Can you spot the differences? ;)
В сериализации Java есть дополнительное соответствующее поле: serialversionUID, но я полагаю, что это уже слишком долго, чтобы охватить его.
@ raam86 пример - сериализуемый объект. Вы можете рассматривать основной метод как отдельную программу, которая создает объект типа SerializationSample.
@ raam86 - это первая инструкция в основном методе: SerializationSample instance = new SerializationSample();, тогда вывод создается, и объект записывается в этот вывод.
Ой. Не следил достаточно близко. Большой!!
Что произойдет, если вы не реализуете Serializable? Как бы этот файл изменить?
@jacktrades Почему бы тебе не попробовать. Просто скопируйте / вставьте пример и увидите, как выбрасывается NotSerializableException :)
@jacktrades, потому что компьютеру не было сказано, что объекту разрешено сериализовать :) что означает oos?
неважно, я обнаружил, что это объект, но получаю следующую ошибку: cannot find symbol symbol: class ObjectOutputStream location: class Article
Мне очень нравятся объяснения простыми словами, краткими и ясными. (+1)
Android использует скрытые особенности, упомянутый @OscarRyz, для реализации Parcelable, который является модификацией сериализуемого для повышения производительности за счет уменьшения количества объектов, созданных во время реализации.
Можете ли вы рассказать мне больше о том, «что может быть двоичным или нет, в зависимости от реализации», меня смущает «последовательность байтов». Не нужно ли, чтобы все в памяти было двоичным?
@yuxh это также может быть строка, разделенная запятыми. class O { String s = "c"} можно сериализовать (с помощью специального сериализатора) в нечто вроде: `" class: O "," c ". Сериализация не всегда выполняется в двоичном формате, это может быть XML, JSON, YAML, а также многие другие недвоичные форматы.
так что неправильно "последовательность байтов" равняться "двоичной"? как я могу понять "последовательность байтов"? поскольку сериализованный формат "class: O", "c", наконец, будет преобразован в двоичный, могу ли я думать, что сериализатор формата JSON и т. д. работает над двоичным форматом, таким как Thrift?
Сериализация означает сохранение объектов в java. Если вы хотите сохранить состояние объекта и хотите восстановить его позже (возможно, в другой JVM), можно использовать сериализацию.
Обратите внимание, что свойства объекта будут только сохранены. Если вы хотите снова воскресить объект, у вас должен быть файл класса, потому что будут сохранены только переменные-члены, а не функции-члены.
например:
ObjectInputStream oos = new ObjectInputStream(
new FileInputStream( new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();
Searializable - это интерфейс маркера, который отмечает, что ваш класс сериализуем. Интерфейс маркера означает, что это просто пустой интерфейс, и использование этого интерфейса будет уведомлять JVM о том, что этот класс можно сделать сериализуемым.
Мне понравилось, как преподносит @OscarRyz. Хотя здесь я продолжаю история сериализации, который изначально был написан @amitgupta.
Даже зная о структуре классов роботов и сериализовав данные, ученые Земли не смогли десериализовать данные, которые могут заставить роботов работать.
Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:
Ученые Марса ждали полной оплаты. Как только оплата была произведена, ученые Марса поделились serialversionUID с учеными Земли. Ученый Земли установил его на класс роботов, и все стало хорошо.
Сериализация - это процесс сохранения объекта на носителе данных (например, файла или буфера памяти) или его передачи по сетевому соединению в двоичной форме. Сериализованные объекты не зависят от JVM и могут быть повторно сериализованы с помощью любой JVM. В этом случае состояние java-объектов «в памяти» преобразуется в поток байтов. Этот тип файла не может быть понят для пользователя. Это особые типы объектов, повторно используемые JVM (виртуальной машиной Java). Этот процесс сериализации объекта также называется дефляцией или маршалингом объекта.
Сериализуемый объект должен реализовывать интерфейс java.io.Serializable.
Механизм сериализации по умолчанию для объекта записывает класс объекта, подпись класса и значения всех непереходных и нестатических полей.
class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,
Интерфейс ObjectOutput расширяет интерфейс DataOutput и добавляет методы для сериализации объектов и записи байтов в файл. ObjectOutputStream расширяет java.io.OutputStream и реализует интерфейс ObjectOutput. Он сериализует объекты, массивы и другие значения в поток. Таким образом, конструктор ObjectOutputStream записывается как:
ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));
Приведенный выше код был использован для создания экземпляра класса ObjectOutput с конструктором ObjectOutputStream( ), который принимает экземпляр FileOuputStream в качестве параметра.
Интерфейс ObjectOutput используется путем реализации класса ObjectOutputStream. ObjectOutputStream создан для сериализации объекта.
Десериализация объекта в java
Противоположная операция сериализации называется десериализацией, то есть извлечение данных из серии байтов называется десериализацией, которая также называется раздуванием или демаршализацией.
ObjectInputStream расширяет java.io.InputStream и реализует интерфейс ObjectInput. Он десериализует объекты, массивы и другие значения из входного потока. Таким образом, конструктор ObjectInputStream записывается как:
ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));
Приведенный выше код программы создает экземпляр класса ObjectInputStream для десериализации того файла, который был сериализован классом ObjectInputStream. Приведенный выше код создает экземпляр, используя экземпляр класса FileInputStream, который содержит указанный файловый объект, который должен быть десериализован, поскольку конструктору ObjectInputStream() требуется входной поток.
Java Сериализация объекта
Serialization - это механизм преобразования графа объектов Java в массив байтов для хранения (to disk file) или передачи (across a network), затем с помощью десериализация мы можем восстановить граф объектов.
Графики объектов восстанавливаются правильно с помощью механизма совместного использования ссылок. Но перед сохранением проверьте, совпадают ли serialVersionUID из входного файла / сети и serialVersionUID из файла .class. Если нет - киньте java.io.InvalidClassException.
Each versioned class must identify the original class version for which it is capable of writing streams and from which it can read. For example, a versioned class must declare:
serialVersionUID Syntax
// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L; private static final long serialVersionUID = 3487495895819393L;
serialVersionUID важен для процесса сериализации. Но разработчику необязательно добавлять его в исходный файл java. Если serialVersionUID не включен, среда выполнения сериализации сгенерирует serialVersionUID и свяжет его с классом. Сериализованный объект будет содержать этот serialVersionUID вместе с другими данными.
Примечание - Настоятельно рекомендуется, чтобы все сериализуемые классы явно объявляли serialVersionUID, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, что может привести к неожиданным конфликтам serialVersionUID во время десериализации, что приведет к сбою десериализации.
Проверка сериализуемых классов
A Java object is only serializable. if a class or any of its superclasses implements either the java.io.Serializable interface or its subinterface, java.io.Externalizable.
Класс должен реализовать java.io.Serializable интерфейс, чтобы успешно сериализовать свой объект. Serializable - это интерфейс маркера, который используется для информирования компилятора о том, что к классу, реализующему его, необходимо добавить сериализуемое поведение. Здесь виртуальная машина Java (JVM) отвечает за автоматическую сериализацию.
transient Keyword:
java.io.Serializable interfaceWhile serializing an object, if we don't want certain data members of the object to be serialized we can use the transient modifier. The transient keyword will prevent that data member from being serialized.
- Fields declared as transient or static are ignored by the serialization process.
+--------------+--------+-------------------------------------+ | Flag Name | Value | Interpretation | +--------------+--------+-------------------------------------+ | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.| +--------------+--------+-------------------------------------+ |ACC_TRANSIENT | 0x0080 | Declared transient; not written or | | | | read by a persistent object manager.| +--------------+--------+-------------------------------------+
class Employee implements Serializable {
private static final long serialVersionUID = 2L;
static int id;
int eno;
String name;
transient String password; // Using transient keyword means its not going to be Serialized.
}
Реализация интерфейса Externalizable позволяет объекту взять на себя полный контроль над содержимым и форматом сериализованной формы объекта. Методы интерфейса Externalizable, writeExternal и readExternal, вызываются для сохранения и восстановления состояния объектов. При реализации классом они могут записывать и читать свое собственное состояние, используя все методы ObjectOutput и ObjectInput. Объекты несут ответственность за обработку любых возникающих версий.
class Emp implements Externalizable {
int eno;
String name;
transient String password; // No use of transient, we need to take care of write and read.
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(eno);
out.writeUTF(name);
//out.writeUTF(password);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.eno = in.readInt();
this.name = in.readUTF();
//this.password = in.readUTF(); // java.io.EOFException
}
}
Только объекты, поддерживающие интерфейс java.io.Serializable или java.io.Externalizable, могут быть потоками written to/read from. Класс каждого сериализуемого объекта кодируется, включая имя класса и сигнатуру класса, значения полей и массивов объекта, а также закрытие любых других объектов, на которые ссылаются исходные объекты.
Пример сериализуемого файла
public class SerializationDemo {
static String fileName = "D:/serializable_file.ser";
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
Employee emp = new Employee( );
Employee.id = 1; // Can not Serialize Class data.
emp.eno = 77;
emp.name = "Yash";
emp.password = "confidential";
objects_WriteRead(emp, fileName);
Emp e = new Emp( );
e.eno = 77;
e.name = "Yash";
e.password = "confidential";
objects_WriteRead_External(e, fileName);
/*String stubHost = "127.0.0.1";
Integer anyFreePort = 7777;
socketRead(anyFreePort); //Thread1
socketWrite(emp, stubHost, anyFreePort); //Thread2*/
}
public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
objectOut.writeObject( obj );
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
Employee emp = (Employee) readObject;
System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( Emp obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
Emp emp = new Emp();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
emp.readExternal(ois);
System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Сериализуемый пример по сети
Состояние Распространяющий объект в разных адресных пространствах, либо в разных процессах на одном компьютере, либо даже на нескольких компьютерах, подключенных через сеть, но которые работают вместе, обмениваясь данными и вызывая методы.
/**
* Creates a stream socket and connects it to the specified port number on the named host.
*/
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
try { // CLIENT - Stub[marshalling]
Socket client = new Socket(stubHost, anyFreePort);
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
out.writeObject(objectToSend);
out.flush();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Creates a server socket, bound to the specified port.
public static void socketRead( Integer anyFreePort ) {
try { // SERVER - Stub[unmarshalling ]
ServerSocket serverSocket = new ServerSocket( anyFreePort );
System.out.println("Server serves on port and waiting for a client to communicate");
/*System.in.read();
System.in.read();*/
Socket socket = serverSocket.accept();
System.out.println("Client request to communicate on port server accepts it.");
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Employee objectReceived = (Employee) in.readObject();
System.out.println("Server Obj : "+ objectReceived.name );
socket.close();
serverSocket.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
@видеть
Когда вы добавляете ответ на вопрос шестилетней давности, на который уже есть несколько очень хороших ответов, вам нужно сделать намного лучше, чем какофония орфографических ошибок.
@ejp Downvoting - это инструмент, чтобы высказать свое негативное мнение. Неприемлемо быть оскорбительным и на грани грубости.
@KonstantinosChertouras Объяснение причин отрицательного голоса полезно для постера, и это мои причины, нравятся они или нет, как вы.
Вам также необходимо избегать ошибок, таких как утверждение, что сериализация имеет целью безопасность. Это не так.
@EJP Я обновил свой пост, исправив, что сериализация не предназначена для целей безопасности, но она используется для преобразования состояния объекта в любое хранилище и для возврата исходного состояния объекта с помощью SUID через механизм десериализации. JVM to JVM
Орфографические ошибки остаются; также некорректные утверждения о Serializable, сообщающие компилятору; также полная путаница между тем, что вы цитируете, и тем, что вы вносите сами ».
@EJP, если в моем сообщении есть орфографические ошибки, то любой может исправить это. Вы больше всего запутались в моем посте, почему так? Запутался на какой строчке. вы можете упомянуть комментарий над комментарием, чтобы я мог исправить его, если это возможно.
Осмелившись ответить на вопрос 6-летней давности, добавив лишь очень высокого уровня понимания для людей, плохо знакомых с Java.
What is Serialization?
Преобразование объекта в байты
What is Deserialization?
Преобразование байтов обратно в объект (десериализация).
When is serialization used?
Когда мы хотим сохранить объект. Когда мы хотим, чтобы объект существовал вне времени существования JVM.
Real World Example:
Банкомат: когда владелец учетной записи пытается снять деньги с сервера через банкомат, информация о владельце учетной записи, такая как сведения о снятии, будет сериализована и отправлена на сервер, где данные десериализованы и используются для выполнения операций.
How serialization is performed in java.
Реализуйте интерфейс java.io.Serializable (интерфейс маркера, поэтому нет метода для реализации).
Сохранение объекта: используйте класс java.io.ObjectOutputStream, поток фильтра, который является оболочкой для байтового потока нижнего уровня (для записи объекта в файловые системы или передачи плоского объекта по сетевому кабелю и его восстановления на другой стороне).
writeObject(<<instance>>) - для записи объектаreadObject() - для чтения сериализованного объектаRemember:
При сериализации объекта будет сохранено только состояние объекта, а не файл класса или методы объекта.
Когда вы сериализовали 2-байтовый объект, вы увидите 51-байтовый сериализованный файл.
Steps how the object is serialized and de-serialized.
Ответ на вопрос: Как он конвертировался в файл размером 51 байт?
java.lang.Object.If you are interested in more in-depth information about Java Serialization please check this link.
Редактировать: еще один хороший ссылка на сайт для чтения.
Это ответит на несколько частых вопросов:
Как не сериализовать какое-либо поле в классе.
Ответ: используйте временное ключевое слово
При сериализации дочернего класса сериализуется ли родительский класс?
Ответ: Нет, если родительский элемент не расширяет поле родителей сериализуемого интерфейса, не сериализуется.
При сериализации родительского класса сериализуется ли дочерний класс?
Ответ: Да, по умолчанию дочерний класс также сериализуется.
Как избежать сериализации дочернего класса?
Ответ: а. Переопределить методы writeObject и readObject и выбросить NotSerializableException.
б. также вы можете отметить все поля как временные в дочернем классе.
Большое спасибо за лаконичный ответ, это было очень полезно!
Вернуть файл как объект: http://www.tutorialspoint.com/java/java_serialization.htm
import java.io.*;
public class SerializeDemo
{
public static void main(String [] args)
{
Employee e = new Employee();
e.name = "Reyan Ali";
e.address = "Phokka Kuan, Ambehta Peer";
e.SSN = 11122333;
e.number = 101;
try
{
FileOutputStream fileOut =
new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
import java.io.*;
public class DeserializeDemo
{
public static void main(String [] args)
{
Employee e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Employee...");
System.out.println("Name: " + e.name);
System.out.println("Address: " + e.address);
System.out.println("SSN: " + e.SSN);
System.out.println("Number: " + e.number);
}
}
Это не отвечает на части вопроса «что есть» или «пожалуйста, объясните».
Мои два цента из моего собственного блога:
Вот подробное объяснение сериализации.: (мой собственный блог)
Сериализация:
Сериализация - это процесс сохранения состояния объекта. Он представлен и хранится в виде последовательности байтов. Это можно сохранить в файле. Процесс чтения состояния объекта из файла и его восстановления называется десериализацией.
Зачем нужна сериализация?
В современной архитектуре всегда необходимо сохранять состояние объекта, а затем извлекать его. Например, в Hibernate, чтобы сохранить объект, мы должны сделать класс Serializable. Что он делает, так это то, что как только состояние объекта сохраняется в виде байтов, оно может быть передано в другую систему, которая затем может читать из состояния и извлекать класс. Состояние объекта может поступать из базы данных, другого jvm или отдельного компонента. С помощью сериализации мы можем получить состояние объекта.
Пример кода и объяснение:
Сначала давайте посмотрим на класс предметов:
public class Item implements Serializable{
/**
* This is the Serializable class
*/
private static final long serialVersionUID = 475918891428093041L;
private Long itemId;
private String itemName;
private transient Double itemCostPrice;
public Item(Long itemId, String itemName, Double itemCostPrice) {
super();
this.itemId = itemId;
this.itemName = itemName;
this.itemCostPrice = itemCostPrice;
}
public Long getItemId() {
return itemId;
}
@Override
public String toString() {
return "Item [itemId = " + itemId + ", itemName = " + itemName + ", itemCostPrice = " + itemCostPrice + "]";
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Double getItemCostPrice() {
return itemCostPrice;
}
public void setItemCostPrice(Double itemCostPrice) {
this.itemCostPrice = itemCostPrice;
}
}
В приведенном выше коде можно увидеть, что класс Пункт реализует Сериализуемый.
Это интерфейс, который позволяет сериализовать класс.
Теперь мы видим, что переменная serialVersionUID инициализируется переменной Long. Это число рассчитывается компилятором на основе состояния класса и атрибутов класса. Это число, которое поможет jvm определить состояние объекта при чтении состояния объекта из файла.
Для этого мы можем взглянуть на официальную документацию Oracle:
The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members.
Если вы заметили, мы использовали еще одно ключевое слово - преходящий.
Если поле не сериализуемое, оно должно быть помечено как временное. Здесь мы отметили itemCostPrice как временный и не хотим, чтобы он записывался в файл.
Теперь давайте посмотрим, как записать состояние объекта в файл, а затем прочитать его оттуда.
public class SerializationExample {
public static void main(String[] args){
serialize();
deserialize();
}
public static void serialize(){
Item item = new Item(1L,"Pen", 12.55);
System.out.println("Before Serialization" + item);
FileOutputStream fileOut;
try {
fileOut = new FileOutputStream("/tmp/item.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(item);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in /tmp/item.ser");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deserialize(){
Item item;
try {
FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
item = (Item) in.readObject();
System.out.println("Serialized data is read from /tmp/item.ser");
System.out.println("After Deserialization" + item);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Выше мы видим пример сериализации и десериализации объекта.
Для этого мы использовали два класса. Для сериализации объекта мы использовали ObjectOutputStream. Мы использовали метод writeObject для записи объекта в файл.
Для десериализации мы использовали ObjectInputStream, который считывает объект из файла. Он использует readObject для чтения данных объекта из файла.
Результат приведенного выше кода будет таким:
Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]
Обратите внимание, что itemCostPrice из десериализованного объекта - это ноль, поскольку он не был записан.
Мы уже обсуждали основы сериализации Java в части I этой статьи.
Теперь давайте подробно обсудим это и то, как это работает.
Сначала начнем с serialversionuid.
serialVersionUID используется в качестве контроля версий в классе Serializable.
Если вы явно не объявляете serialVersionUID, JVM сделает это за вас автоматически на основе различных свойств класса Serializable.
Алгоритм вычисления serialversionuid в Java (подробнее здесь)
- The class name.
- The class modifiers written as a 32-bit integer.
- The name of each interface sorted by name.
- For each field of the class sorted by field name (except private static and private transient fields: The name of the field. The modifiers of the field written as a 32-bit integer. The descriptor of the field.
- If a class initializer exists, write out the following: The name of the method, .
- The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer.
- The descriptor of the method, ()V.
- For each non-private constructor sorted by method name and signature: The name of the method, . The modifiers of the method written as a 32-bit integer. The descriptor of the method.
- For each non-private method sorted by method name and signature: The name of the method. The modifiers of the method written as a 32-bit integer. The descriptor of the method.
- The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and produces five 32-bit values sha[0..4]. The hash value is assembled from the first and second 32-bit values of the SHA-1 message digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named sha, the hash value would be computed as follows:
long hash = ((sha[0] >>> 24) & 0xFF) |
> ((sha[0] >>> 16) & 0xFF) << 8 |
> ((sha[0] >>> 8) & 0xFF) << 16 |
> ((sha[0] >>> 0) & 0xFF) << 24 |
> ((sha[1] >>> 24) & 0xFF) << 32 |
> ((sha[1] >>> 16) & 0xFF) << 40 |
> ((sha[1] >>> 8) & 0xFF) << 48 |
> ((sha[1] >>> 0) & 0xFF) << 56;
Алгоритм сериализации Java
The algorithm to serialize an object is described as below:
1. It writes out the metadata of the class associated with an instance.
2. It recursively writes out the description of the superclass until it finds java.lang.object.
3. Once it finishes writing the metadata information, it then starts with the actual data associated with the instance. But this time, it starts from the topmost superclass.
4. It recursively writes the data associated with the instance, starting from the least superclass to the most-derived class.
Что нужно иметь в виду:
Статические поля в классе нельзя сериализовать.
public class A implements Serializable{
String s;
static String staticString = "I won't be serializable";
}
Если serialversionuid отличается в классе чтения, это вызовет исключение InvalidClassException.
Если класс реализует сериализуемый, тогда все его подклассы также будут сериализуемыми.
public class A implements Serializable {....};
public class B extends A{...} //also Serializable
Если класс имеет ссылку на другой класс, все ссылки должны быть сериализуемыми, иначе процесс сериализации не будет выполнен. В таком случае NotSerializableException выбрасывается во время выполнения.
Например:
public class B{
String s,
A a; // class A needs to be serializable i.e. it must implement Serializable
}
«Сериализация - это процесс сериализации состояния объекта, представленного и сохраненного в виде последовательности байтов» не имеет смысла. Если serialVersionUID отличается, он выдаст InvalidClassException, а не ClassCastException. Нет необходимости тратить все это пространство на повторное определение вычислений serialVersionUID. Документация цитируется слишком долго, но без ссылок и надлежащего цитирования. Слишком много чуши и слишком много ошибок.
«Сериализация - это процесс сериализации» остается бессмысленным.
| * | Сериализация класса: преобразование объекта в байты и байтов обратно в объект (десериализация) .
class NamCls implements Serializable
{
int NumVar;
String NamVar;
}
| => Сериализация объекта - это процесс преобразования состояния объекта в пару байтов.
| => Десериализация объекта - это процесс получения состояния объекта и сохранения его в объекте (java.lang.Object) .
| => Объект Java сериализуем, только если его класс или любой из его суперклассов
| => Статические поля в классе не могут быть сериализованы.
class NamCls implements Serializable
{
int NumVar;
static String NamVar = "I won't be serializable";;
}
| => Если вы не хотите сериализовать переменную класса, используйте временное ключевое слово
class NamCls implements Serializable
{
int NumVar;
transient String NamVar;
}
| => Если класс реализует сериализуемый, то все его подклассы также будут сериализуемыми.
| => Если у класса есть ссылка на другой класс, все ссылки должны быть сериализуемыми, иначе процесс сериализации не будет выполнен. В таком случае во время выполнения создается исключение
NotSerializableException.
Я предлагаю аналогию, чтобы потенциально помочь в укреплении концептуальной цели / практичности сериализация / десериализация объекта.
Я представляю сериализация / десериализация объекта в контексте попытки переместить объект через ливневую канализацию. По сути, объект «декомпозируется» или сериализованный на более модульные версии самого себя - в данном случае на серия байтов - для того, чтобы получить возможность эффективно проходить через среду. В вычислительном смысле мы могли бы рассматривать путь, пройденный байтами через ливневую канализацию, как путь байтов, проходящих через сеть. Мы трансмутируем наш объект, чтобы он соответствовал более желательному способу транспортировки или формату. Сериализованный объект обычно хранится в двоичном файле, который позже может быть прочитан, записан или и то, и другое.
Возможно, как только наш объект сможет проскользнуть через сток в виде разложенной серии байтов, мы можем пожелать сохранить это представление объекта в виде двоичных данных в базе данных или на жестком диске. Однако главный вывод заключается в том, что при сериализации / десериализации у нас есть возможность позволить нашему объекту оставаться в его двоичной форме после сериализации или «получить» исходную форму объекта, выполнив десериализацию.
Если вас интересует реальный сценарий Java EE, в котором задействована сериализация, перейдите сюда: stackoverflow.com/q/2294551