Яка різниця між 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це реліквія Яви 1,1 днів. У цьому насправді більше немає потреби.


61
Не відповідно до цих орієнтирів: [ code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking] ручна серіалізація (з використанням externizable) набагато швидше, ніж використання серіалізації за замовчуванням Java. Якщо швидкість має значення для вашої роботи, обов'язково напишіть власний серіалізатор.
volni

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

Серіалізація забезпечує функціональність за замовчуванням для зберігання та подальшого відтворення об’єкта. Він використовує багатослівний формат для визначення цілого графа об'єктів, що підлягають збереженню, наприклад, припустимо, що у вас є linkedList і ви кодуєте, як показано нижче, тоді серіалізація за замовчуванням виявить усі об'єкти, які пов’язані між собою, і серіалізується. При серіалізації за замовчуванням об'єкт будується повністю з його збережених бітів, без викликів конструктора.

  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. Маркерний інтерфейс : Serializableце інтерфейс маркера без будь-яких методів. Externalizableінтерфейс містить два способи: writeExternal()і readExternal().
  2. Процес серіалізації : Процес серіалізації за замовчуванням розпочнеться для класів, що реалізують Serializableінтерфейс. Процес серіалізації, визначений програмістом, стартує для Externalizableінтерфейсів класів, що реалізують .
  3. Технічне обслуговування : Несумісні зміни можуть порушити серіалізацію.
  4. Зворотна сумісність і контроль : Якщо вам доведеться підтримувати кілька версій, ви можете мати повний контроль з Externalizableінтерфейсом. Ви можете підтримувати різні версії вашого об’єкта. Якщо ви реалізуєте Externalizable, це ваша відповідальність за серіалізацію superкласу
  5. громадський конструктор No-arg : Serializableвикористовує відображення для побудови об'єкта і не вимагає конструктора аргументів. Але Externalizableвимагає публічного конструктора без аргументів.

Зверніться до блогу шляхом Hitesh Gargдля отримання більш докладної інформації.


1
(3) невірно. Існує великий репертуар змін, які ви можете внести до класу, не порушуючи де-серіалізацію існуючих об'єктів, і додавання членів серіалізації, безумовно, є одним із них. Видалення їх - інше. Див. Розділ " Версія для об єктів" у специфікації специфікації об'єкта Java.
Маркіз Лорн

1
Переформульоване речення.
Равіндра бабу

Дякуємо, що поділилися посиланням на специфікацію серіалізації.
JL_SO

21

Серіалізація використовує певні поведінки за замовчуванням для зберігання та подальшого відтворення об'єкта. Ви можете вказати, в якому порядку чи як обробляти посилання та складні структури даних, але з часом це зводиться до використання поведінки за замовчуванням для кожного примітивного поля даних.

Екстерналізація використовується в тих рідкісних випадках, коли ви дійсно хочете зберігати і перебудовувати свій об'єкт зовсім іншим способом і без використання механізмів серіалізації за замовчуванням для полів даних. Наприклад, уявіть, що у вас була своя унікальна схема кодування та стиснення.


5
Ми використовували Externalizable для великих колекцій "вибраних ідентифікаторів" - це було набагато ефективнішим екстерналізацією як більш-менш числом і масивом примітивних вкладень, ніж серіалізація за замовчуванням. Це дуже простий шафа, нічого "особливого" чи "унікального".
Thomas W

9

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

  • NotSerializableException: packageName.ClassName«Для участі в об'єкті класу в процесі серіалізації, клас повинен реалізовувати інтерфейс Serializable або Externalizable.

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


Серіалізаційний інтерфейс

Об'єктна серіалізація створює потік з інформацією про класи 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отримати серіалізацію.


Приклад « реалізує 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();
        }
    }
}

@побачити


7

Інтерфейс Externalizable насправді не був забезпечений для оптимізації продуктивності процесу серіалізації! але забезпечити засоби реалізації власної власної обробки та запропонувати повний контроль над форматом та вмістом потоку для об’єкта та його супер типів!

Прикладами цього є реалізація видалення AMF (ActionScript Format Format) для передачі власних об'єктів сценарію дії через мережу.


7

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

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

Екстерналізація дає виробнику об'єктного потоку повний контроль над точними метаданими класу (якщо такі є) за межами мінімально необхідної ідентифікації класу (наприклад, його назви). Це явно бажано в певних ситуаціях, наприклад, у закритих середовищах, коли виробник потоку об'єктів та його споживач (який відводить об'єкт із потоку) узгоджуються, а додаткові метадані про клас не служать ніякій меті та погіршують продуктивність.

Додатково (як зазначає Урі) екстерналізація також забезпечує повний контроль над кодуванням даних у потоці, що відповідає типам Java. Для (надуманого) прикладу, ви можете записати булеве значення true як "Y", а false як "N". Екстерналізація дозволяє це зробити.


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

Я додав зразок коду, щоб пояснити краще. будь ласка, зареєструйте / вимкніть об'єктний випадок Externalizable. Вони не пов'язані ні з якою реалізацією безпосередньо.
Де Outstream / Instream тісно пов'язані з класами. Ми можемо розширити ObjectOutputStream / ObjectInputStream, але це буде трохи важко у використанні.


1
Чи можете ви детальніше розробити це? Коли я читав це, я не розумію, що ви намагаєтесь сказати. Крім того, якщо ви зможете відформатувати текст за допомогою деяких абзаців та прикладів, це може бути чудовою відповіддю.
Ширкам

0

По суті, Serializableце маркерний інтерфейс, який передбачає, що клас безпечний для серіалізації і JVM визначає, як він серіалізується. Externalizableмістить 2 способи readExternalта writeExternal. Externalizableдозволяє реалізатору вирішити, як об’єкт серіалізується, де як Serializableсеріалізує об'єкти за замовчуванням.


0

Деякі відмінності:

  1. Для серіалізації немає необхідності конструктора за замовчуванням цього класу, тому що Object тому, що JVM створює те саме за допомогою Reflection API. У разі екстерналізації кондуктора без аргументу не потрібно, оскільки управління знаходиться в руці програміста, а пізніше призначається десеріалізовані дані об'єкту через сетери.

  2. При серіалізації, якщо користувач хоче пропустити певні властивості для серіалізації, він повинен позначати ці властивості як перехідні, навпаки, для екстерналізації не потрібно.

  3. Якщо очікується підтримка зворотної сумісності для будь-якого класу, тоді рекомендується перейти з Externalizable. Серіалізація підтримує defaultObject, що зберігається, і якщо структура об'єкта порушена, це спричинить проблему під час десеріалізації.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.