В чем разница между Serializable и Externalizable в Java?

В чем разница между Serializable и Externalizable в Java?

Ответ 1

Чтобы добавить к другим ответам, реализовав java.io.Serializable, вы получаете возможность "автоматической" сериализации для объектов вашего класса. Нет необходимости реализовывать какую-либо другую логику, она будет работать. Java runtime будет использовать рефлексию, чтобы выяснить, как маршалировать и развязывать ваши объекты.

В более ранней версии Java отражение было очень медленным, и поэтому сериализация крупных объектных графов (например, в клиент-серверных приложениях RMI) была проблемой производительности. Чтобы справиться с этой ситуацией, был предоставлен интерфейс java.io.Externalizable, который похож на java.io.Serializable, но с настраиваемыми механизмами для выполнения функций маршаллинга и unmarshalling (вам нужно реализовать методы readExternal и writeExternal в вашем классе). Это дает вам возможность обойти узкое место производительности отражения.

В последних версиях Java (начиная с версии 1.3, конечно) производительность отражения намного лучше, чем раньше, и поэтому это гораздо менее проблематично. Я подозреваю, что вам будет трудно получить значимую выгоду от Externalizable с современной JVM.

Кроме того, встроенный механизм сериализации Java не является единственным, вы можете получить сторонние замены, такие как JBoss Serialization, что значительно быстрее и является заменой по умолчанию.

Большой недостаток Externalizable заключается в том, что вы должны сами поддерживать эту логику - если вы добавляете, удаляете или изменяете поле в своем классе, вы должны изменить методы writeExternal/readExternal, чтобы учесть его.

Таким образом, Externalizable является реликвией Java 1.1 дней. Нет необходимости в этом больше.

Ответ 2

Сериализация предоставляет функции по умолчанию для хранения и последующего воссоздания объекта. Он использует подробный формат для определения всего графика объектов, которые нужно сохранить, например. предположим, что у вас есть связанныйList, и вы код, как показано ниже, то сериализация по умолчанию обнаружит все объекты, которые связаны и будут сериализованы. В сериализации по умолчанию объект полностью построен из его сохраненных битов, без вызовов конструктора.

  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;

Надеюсь, это поможет. Прошу прощения, если я допустил ошибки. Спасибо.

Ответ 3

Только для полноты ключевое слово transient также закрывает промежуток между ними.

Если вы хотите сериализовать часть своего объекта, просто установите определенные поля как transient, отметив их как не сохраняемые, и реализуйте Serializable.

Ответ 4

Сериализация использует определенное поведение по умолчанию для хранения и последующего воссоздания объекта. Вы можете указать, в каком порядке или как обрабатывать ссылки и сложные структуры данных, но в конечном итоге это сводится к использованию поведения по умолчанию для каждого примитивного поля данных.

В редких случаях, когда вы действительно хотите сохранить и перестроить свой объект, внешняя система используется совершенно иначе и без использования механизмов сериализации по умолчанию для полей данных. Например, представьте, что у вас есть своя уникальная схема кодирования и сжатия.

Ответ 5

Основные различия между Serializable и Externalizable

  • Интерфейс маркера: Serializable - это интерфейс маркера без каких-либо методов. Интерфейс Externalizable содержит два метода: writeExternal() и readExternal().
  • Процесс сериализации. Процесс Serialization по умолчанию будет запущен для классов, реализующих интерфейс Serializable. Определенный программистом процесс Serialization будет запущен для классов, реализующих интерфейс Externalizable.
  • Обслуживание: Несовместимые изменения могут нарушить сериализацию.
  • Обратная совместимость и управление. Если вам нужно поддерживать несколько версий, вы можете иметь полный контроль с интерфейсом Externalizable. Вы можете поддерживать разные версии вашего объекта. Если вы реализуете Externalizable, это ваша ответственность за сериализацию super class
  • public No-arg constructor: Serializable использует отражение для построения объекта и не требует конструктора arg. Но Externalizable требует публичного конструктора no-arg.

Подробнее см. блог Hitesh Garg.

Ответ 6

https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html

Сериализация по умолчанию несколько подробна и предполагает максимально возможный сценарий использования сериализованного объекта, и, соответственно, формат по умолчанию (Serializable) аннотирует результирующий поток с информацией о классе сериализованного объекта.

Экстернализация дает производителю потока объектов полный контроль над точными метаданными класса (если таковые имеются) за минимально необходимой идентификацией класса (например, его именем). Это явно желательно в определенных ситуациях, таких как закрытые среды, в которых сопоставляются производитель потока объектов и его потребителя (который подтверждает объект из потока), а дополнительные метаданные о классе не имеют никакой цели и ухудшают производительность.

Дополнительно (как указано Uri) экстернализация также обеспечивает полный контроль над кодированием данных в потоке, соответствующем типам Java. Для (надуманного) примера вы можете записать логическое значение true, как "Y", а false - "N". Экстернализация позволяет это сделать.

Ответ 7

Интерфейс Externalizable фактически не предоставлялся для оптимизации производительности процесса сериализации! но и предоставить средства для реализации собственной пользовательской обработки и предложить полный контроль над форматом и содержимым потока для объекта и его супер-типов!

Примерами этого является реализация удаленного формата AMF (ActionScript Message Format) для переноса собственных действий script по сети.

Ответ 8

Сериализация объектов использует интерфейсы Serializable и Externalizable.  Объект Java является сериализуемым. если класс или любой из его суперклассов реализует либо интерфейс java.io.Serializable, либо его подчиненный интерфейс, java.io.Externalizable. Большинство классов java являются сериализуемыми.

  • NotSerializableException: packageName.ClassName" Чтобы участвовать в объекте класса в процессе сериализации, класс должен реализовывать интерфейс Serializable или Externalizable.

введите описание изображения здесь


Serializable Interface

Сериализация объектов создает поток с информацией о классах Java для сохраняемых объектов. Для сериализуемых объектов сохраняется достаточная информация для восстановления этих объектов, даже если присутствует другая (но совместимая) версия реализации класса. Интерфейс Serializable определен для идентификации классов, которые реализуют сериализуемый протокол:

package java.io;

public interface Serializable {};
  • Интерфейс сериализации не имеет методов или полей и служит только для идентификации семантики сериализации. Для сериализации/десериализации класса мы можем использовать методы writeObject по умолчанию и readObject (или), мы можем переопределять методы writeObject и readObject из класса.
  • JVM будет иметь полный контроль над сериализацией объекта. используйте ключевое слово переходного процесса, чтобы предотвратить сериализацию члена данных.
  • Здесь сериализуемые объекты восстанавливаются непосредственно из потока без выполнения
  • 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;
}
  • Интерфейс Externalizable имеет два метода: внешний объект должен реализовывать методы writeExternal и readExternal для сохранения/восстановления состояния объекта.
  • Программист должен позаботиться о том, какие объекты должны быть сериализованы. Как программист позаботится о сериализации Итак, здесь ключевое слово transient не будет ограничивать какой-либо объект в процессе Serialization.
  • Когда объект Externalizable реконструируется, экземпляр создается с использованием конструктора public no-arg, затем вызывается метод readExternal. Сериализуемые объекты восстанавливаются путем чтения их из ObjectInputStream.
  • 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, сериализуются.


Пример " реализует Serializable

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();
        }
    }
}

@see

Ответ 9

При рассмотрении вариантов повышения производительности не забывайте о специальной сериализации. Вы можете позволить Java делать то, что она делает хорошо, или, по крайней мере, достаточно хорошо, бесплатно и предоставлять индивидуальную поддержку тому, что она делает плохо. Обычно это намного меньше кода, чем полная поддержка Externalizable.

Ответ 10

Существует так много различий между 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();
            }

Я добавил пример кода, чтобы лучше объяснить. пожалуйста, проверьте в/из объекта случай Externalizable. Они не привязаны к какой-либо реализации напрямую.
Где, поскольку Outstream/Instream тесно связаны с классами. Мы можем расширить ObjectOutputStream/ObjectInputStream, но это будет немного сложно использовать.