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

Ответы:

267

Чтобы добавить к другим ответам, реализуя 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 дней. Там действительно не нужно больше.

skaffman
источник
61
Не в соответствии с этими критериями: [ code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking] , ручная сериализация (с использованием externizable) намного, намного быстрее, чем с использованием сериализации по умолчанию в Java. Если скорость важна для вашей работы, обязательно напишите собственный сериализатор.
Вольни
6
обновление по новой ссылке github.com/eishay/jvm-serializers/wiki, предложенной @Jack
noquery
3
«Ява-руководство» в github.com/eishay/jvm-serializers/wiki вовсе не использовать Externalizable, который будет означать , используя ObjectOutputStream. См. Github.com/eishay/jvm-serializers/wiki/ToolBehavior для ссылки на код. Вместо этого это рукописный код, который использует DataOutputStream, поэтому он не страдает от вещей, которые замедляют ObjectOutputStream (таких как отслеживание экземпляров объектов и поддержка циклов объектов).
Эско Луонтола
7
Необходимость поддерживать логику самостоятельно - это только недостаток, если класс никогда не меняется и вам никогда не придется читать в постоянных версиях старых данных. Если вам нужна свобода менять свой класс без необходимости писать адский код для десериализации старых версий, это оченьExternalizable помогает .
Тим Будро
2
Мне просто нужно было написать собственную коллекцию, и я должен сказать, что она Externalizableподходит мне гораздо лучше, так как я не хочу выводить массивы с пустыми пробелами или объектами-заполнителями, плюс с явным интерфейсом вы можете обрабатывать наследование, что означает мою синхронизированную подпрограмму -класс может легко добавить блокировку по всему вызову writeExternal(). Так что да, Externalizable по-прежнему очень актуален, безусловно, для больших или сложных объектов.
Харавикк
37

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

  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;

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

Попытка
источник
22

Ключевые различия между SerializableиExternalizable

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

Обратитесь к блогу путем Hitesh Gargдля получения более подробной информации.

Равиндра Бабу
источник
1
(3) неверно. Существует большой список изменений, которые вы можете внести в класс, не нарушая десериализацию существующих объектов, и добавление сериализуемых членов, безусловно, является одним из них. Удаление их - это другое. См. Главу «Управление версиями объектов» в Спецификации сериализации объектов Java.
маркиз Лорн
1
Перефразированное предложение.
Равиндра Бабу
Спасибо, что поделились ссылкой на спецификацию сериализации.
JL_SO
21

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

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

Uri
источник
5
Мы использовали Externalizable для больших коллекций «отобранных идентификаторов» - это было гораздо эффективнее, если использовать более или менее число и массив примитивных целочисленных значений, чем сериализация по умолчанию. Это очень простой случай, ничего особенного или уникального.
Томас W
9

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

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

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


Сериализуемый интерфейс

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

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

@видеть

Яши
источник
7

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

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

Али Джудех
источник
7

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

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

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

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

alphazero
источник
2

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

Эд Стауб
источник
2

Существует так много различий между 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, но его будет немного сложно использовать.

Ашиш Шарма
источник
1
Не могли бы вы уточнить это подробнее? Когда я читаю это, я не понимаю, что вы пытаетесь сказать. Кроме того, если бы вы могли отформатировать текст с некоторыми параграфами и примерами, это могло бы быть отличным ответом.
Ширкам
0

По сути, Serializableэто маркерный интерфейс, который подразумевает, что класс безопасен для сериализации, а JVM определяет, как он сериализуется. Externalizableсодержит 2 метода, readExternalи writeExternal. Externalizableпозволяет разработчику решить, как сериализовать объект, где Serializableсериализует объекты по умолчанию.

Пика Волшебник китов
источник
0

Некоторые отличия:

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

  2. При сериализации, если пользователь хочет пропустить определенные свойства для сериализации, он должен пометить эти свойства как временные, и наоборот, для Externalization не требуется.

  3. Если для любого класса ожидается поддержка обратной совместимости, рекомендуется использовать Externalizable. Сериализация поддерживает сохранение defaultObject, и если структура объекта нарушена, это вызовет проблемы при десериализации.

Neeraj
источник