В чем разница между Serializable и Externalizable в Java? - PullRequest
273 голосов

Ответы [ 11 ]

261 голосов
/ 04 мая 2009

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

35 голосов
/ 20 марта 2013

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

  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;

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

24 голосов
/ 20 декабря 2010

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

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

21 голосов
/ 07 апреля 2016

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

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

См. blog by Hitesh Garg для получения более подробной информации.

21 голосов
/ 04 мая 2009

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

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

9 голосов
/ 17 января 2018

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

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

enter image description here


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

Сериализация объектов создает поток с информацией о классах 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 для сохранения / восстановления состояния объекта.
  • Программист должен позаботиться о том, какие объекты сериализуются. Как программист позаботится о сериализации Итак, здесь временное ключевое слово не будет ограничивать какой-либо объект в процессе сериализации.
  • Когда объект 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 голосов
/ 27 августа 2012

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

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

7 голосов
/ 04 мая 2009

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

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

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

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

2 голосов
/ 11 октября 2017

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

2 голосов
/ 28 октября 2011

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

...