В чем разница между Serializable
и Externalizable
в Java?
В чем разница между Serializable
и Externalizable
в Java?
Ответы:
Чтобы добавить к другим ответам, реализуя java.io.Serializable
, вы получаете «автоматическую» возможность сериализации для объектов вашего класса. Не нужно реализовывать какую-либо другую логику, это просто сработает. Среда выполнения Java будет использовать отражение, чтобы выяснить, как маршалировать и демаршировать ваши объекты.
В более ранней версии Java отражение было очень медленным, и поэтому сериализация больших графов объектов (например, в клиент-серверных приложениях RMI) представляла собой небольшую проблему с производительностью. Чтобы справиться с этой ситуацией, java.io.Externalizable
был предоставлен интерфейс, который похож java.io.Serializable
на пользовательские механизмы для выполнения функций маршалинга и демаршаллинга (вам необходимо реализовать методы readExternal
и writeExternal
методы в вашем классе). Это дает вам возможность обойти узкое место производительности отражения.
В последних версиях Java (разумеется, начиная с версии 1.3) производительность отражения значительно выше, чем раньше, и поэтому это намного меньше проблем. Я подозреваю, что вам будет трудно получить значительную выгоду от Externalizable
современной JVM.
Кроме того, встроенный механизм сериализации Java не единственный, вы можете получить сторонние замены, такие как JBoss Serialization, который значительно быстрее и является заменой по умолчанию.
Большим недостатком Externalizable
является то, что вы должны поддерживать эту логику самостоятельно - если вы добавляете, удаляете или изменяете поле в своем классе, вы должны изменить свои writeExternal
/ readExternal
методы для его учета.
Таким образом, Externalizable
является пережитком Java 1.1 дней. Там действительно не нужно больше.
Externalizable
помогает .
Externalizable
подходит мне гораздо лучше, так как я не хочу выводить массивы с пустыми пробелами или объектами-заполнителями, плюс с явным интерфейсом вы можете обрабатывать наследование, что означает мою синхронизированную подпрограмму -класс может легко добавить блокировку по всему вызову writeExternal()
. Так что да, Externalizable по-прежнему очень актуален, безусловно, для больших или сложных объектов.
Сериализация обеспечивает функциональность по умолчанию для хранения и последующего воссоздания объекта. Он использует подробный формат для определения всего графа объектов, которые должны быть сохранены, например, предположим, что у вас есть связанный список и код, как показано ниже, тогда сериализация по умолчанию обнаружит все объекты, которые связаны, и сериализует. При сериализации по умолчанию объект создается полностью из его сохраненных битов, без вызовов конструктора.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
Но если вы хотите ограниченную сериализацию или не хотите, чтобы часть вашего объекта сериализовалась, используйте Externalizable. Интерфейс Externalizable расширяет интерфейс Serializable и добавляет два метода, writeExternal () и readExternal (). Они автоматически вызываются при сериализации или десериализации. При работе с Externalizable мы должны помнить, что конструктор по умолчанию должен быть публичным, иначе код будет выдавать исключение. Пожалуйста, следуйте приведенному ниже коду:
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Здесь, если вы прокомментируете конструктор по умолчанию, код выдаст ниже исключения:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Мы можем заметить, что, поскольку пароль является конфиденциальной информацией, я не сериализую его в методе writeExternal (ObjectOutput oo) и не устанавливаю его значение в readExternal (ObjectInput oi). Это гибкость, которую обеспечивает Externalizable.
Вывод вышеприведенного кода приведен ниже:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Мы можем наблюдать, как мы не устанавливаем значение passWord, поэтому оно равно нулю.
Этого также можно добиться, объявив поле пароля как переходное.
private transient String passWord;
Надеюсь, поможет. Я прошу прощения, если я сделал какие-либо ошибки. Спасибо.
Ключевые различия между Serializable
иExternalizable
Serializable
является маркером интерфейс без каких - либо методов. Externalizable
Интерфейс содержит два метода: writeExternal()
и readExternal()
.Serializable
интерфейс. Определенный программистом процесс сериализации будет запущен для классов, реализующих Externalizable
интерфейс.Externalizable
интерфейсом. Вы можете поддерживать разные версии вашего объекта. Если вы реализуете Externalizable
, вы несете ответственность за сериализацию super
классаSerializable
использует отражение для конструирования объекта и не требует никакого arg-конструктора. Но Externalizable
требует публичного безошибочного конструктора.Обратитесь к блогу путем Hitesh Garg
для получения более подробной информации.
Сериализация использует определенные поведения по умолчанию для хранения и последующего воссоздания объекта. Вы можете указать, в каком порядке или как обрабатывать ссылки и сложные структуры данных, но в конечном итоге все сводится к использованию поведения по умолчанию для каждого примитивного поля данных.
Экстернализация используется в тех редких случаях, когда вы действительно хотите хранить и перестраивать свой объект совершенно другим способом и без использования стандартных механизмов сериализации для полей данных. Например, представьте, что у вас есть собственная уникальная схема кодирования и сжатия.
Сериализация объектов использует интерфейсы Serializable и Externalizable. Объект Java только сериализуем. если класс или любой из его суперклассов реализует либо интерфейс java.io.Serializable, либо его подынтерфейс, java.io.Externalizable. Большинство классов Java являются сериализуемыми .
NotSerializableException
: packageName.ClassName
«Для участия объекта Class в процессе сериализации, класс должен реализовывать интерфейс Serializable или Externalizable.Сериализация объектов создает поток с информацией о классах Java для сохраняемых объектов. Для сериализуемых объектов хранится достаточно информации для восстановления этих объектов, даже если присутствует другая (но совместимая) версия реализации класса. Сериализуемый интерфейс определен для идентификации классов, которые реализуют сериализуемый протокол:
package java.io;
public interface Serializable {};
InvalidClassException
«В процессе десериализации, если значение локального класса serialVersionUID отличается от соответствующего класса отправителя. тогда результат в конфликте как
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Для объектов Externalizable контейнер сохраняет только идентичность класса объекта; класс должен сохранить и восстановить содержимое. Интерфейс Externalizable определяется следующим образом:
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
OptionalDataException
«Поля должны быть в том же порядке и типе, как мы их выписали. Если есть какое-либо несоответствие типа из потока, он генерирует исключение OptionalDataException.
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
Поля экземпляра класса, который написан (выставлен) для ObjectOutput
сериализации.
Пример « реализует Сериализуемый
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
Пример « реализует Externalizable
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
пример
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
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
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User 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.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@видеть
Интерфейс Externalizable фактически не был предоставлен для оптимизации производительности процесса сериализации! но предоставить средства для реализации собственной обработки и предложить полный контроль над форматом и содержимым потока для объекта и его супертипов!
Примерами этого является реализация AMF (ActionScript Message Format) удаленного взаимодействия для передачи собственных объектов сценария действия по сети.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
Сериализация по умолчанию несколько многословна и предполагает самый широкий возможный сценарий использования сериализованного объекта, и, соответственно, формат по умолчанию (Serializable) аннотирует результирующий поток информацией о классе сериализованного объекта.
Экстернализация дает производителю объектного потока полный контроль над точными метаданными класса (если таковые имеются) за пределами минимальной требуемой идентификации класса (например, его имени). Это явно желательно в определенных ситуациях, например, в закрытых средах, в которых сопоставляются производитель потока объекта и его потребитель (который получает объект из потока), а дополнительные метаданные о классе не служат цели и ухудшают производительность.
Кроме того (как указывает Ури), экстернализация также обеспечивает полный контроль над кодированием данных в потоке, соответствующем типам Java. Для (надуманного) примера вы можете записать логическое true как «Y» и false как «N». Экстернализация позволяет вам сделать это.
При рассмотрении вариантов повышения производительности не забывайте настраиваемую сериализацию. Вы можете позволить Java делать то, что он делает хорошо, или, по крайней мере, достаточно хорошо, бесплатно , и предоставлять настраиваемую поддержку того, что он делает плохо. Обычно это намного меньше кода, чем полная поддержка Externalizable.
Существует так много различий между Serializable и Externalizable, но когда мы сравниваем разницу между настраиваемыми Serializable (переопределенными writeObject () & readObject ()) и Externalizable, мы обнаруживаем, что пользовательская реализация тесно связана с классом ObjectOutputStream, где, как и в случае Externalizable, мы сами обеспечить реализацию ObjectOutput, который может быть классом ObjectOutputStream или другим, например org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
В случае интерфейса Externalizable
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
Я добавил пример кода, чтобы объяснить лучше. пожалуйста, проверьте вход / выход объекта case Externalizable. Они не связаны с какой-либо реализацией напрямую.
Где, как Outtream / Instream тесно связаны с классами. Мы можем расширить ObjectOutputStream / ObjectInputStream, но его будет немного сложно использовать.
По сути, Serializable
это маркерный интерфейс, который подразумевает, что класс безопасен для сериализации, а JVM определяет, как он сериализуется. Externalizable
содержит 2 метода, readExternal
и writeExternal
. Externalizable
позволяет разработчику решить, как сериализовать объект, где Serializable
сериализует объекты по умолчанию.
Некоторые отличия:
Для Сериализации не требуется конструктор по умолчанию для этого класса, потому что Object, потому что JVM создает то же самое с помощью Reflection API. В случае Externalization требуется конструктор без аргумента, потому что управление находится в руках программиста, а затем присваивает десериализованные данные объекту через сеттеры.
При сериализации, если пользователь хочет пропустить определенные свойства для сериализации, он должен пометить эти свойства как временные, и наоборот, для Externalization не требуется.
Если для любого класса ожидается поддержка обратной совместимости, рекомендуется использовать Externalizable. Сериализация поддерживает сохранение defaultObject, и если структура объекта нарушена, это вызовет проблемы при десериализации.