Що означає Serializable?


136

Що саме означає для класу перебування Serializableна Java? Або взагалі з цього приводу ...


10
@skaffman Ось що йдеться про клас Serializable: Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
Ritwik Bose

32
Чудове пояснення, якщо ви вже знаєте, що означають серіалізовані та десеріалізовані. (Не комплімент.) Такі визначення допомагають зрозуміти проблему краще технічно один раз, і лише один раз ви вже маєте певні знання з цього питання.
Xonatron

Відповіді:


132

Серіалізація зберігає об'єкт із пам'яті до послідовності бітів, наприклад, для збереження на диску. Десеріалізація - навпаки - зчитування даних з диска для гідратації / створення об’єкта.

У контексті Вашого питання це інтерфейс, який, якщо реалізований у класі, цей клас може автоматично серіалізуватися та десеріалізуватися різними серіалізаторами.


2
Також зауважте, що всі поля, які явно не позначені інакше, будуть також серіалізовані. Це означає, що ви можете легко зберегти складну структуру даних, просто серіалізуючи кореневий об’єкт.
Thorbjørn Ravn Andersen

1
Отже, коли ми говоримо про "Об'єкти", чи маємо на увазі об'єкт, створений класом, або просто будь-який "Програмний об'єкт", як збірки, файли тощо? І якщо це останнє, чи це просто стандартизований спосіб передачі даних між програмами та середовищами?
Sunburst275

1
@ Sunburst275 - в цьому випадку це представлення класу в пам'яті класу в пам’яті - тобто екземпляр класу (не існує реального сенсу говорити про серіалізацію збірок, оскільки вони зазвичай на диску є файлами, які можуть просто надіслати навколо, як є).
Одід

44

Хоча більшість користувачів вже відповіли, але я хотів би додати приклад для тих, хто цього потребує, щоб пояснити ідею:

Скажімо, у вас є людина класу на кшталт наступного:

public class Person implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

а потім ви створюєте такий об'єкт:

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

Ви можете серіалізувати цей об’єкт у багатьох потоках. Я зроблю це для двох потоків:

Серіалізація до стандартного виходу:

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

Серіалізація до файлу:

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

Тоді:

Десеріалізувати з файлу:

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }

Дякую. Я думаю, я зараз це отримав.
Sunburst275

40

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


15

Ось детальне пояснення серіалізації : (мій власний блог)

Серіалізація:

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

У чому потреба серіалізації?

У сучасній архітектурі сучасності завжди є необхідність зберігати стан об'єкта, а потім отримувати його. Наприклад, в режимі Hibernate, щоб зберігати об’єкт, ми повинні зробити клас Serializable. Це означає, що після збереження стану об'єкта у вигляді байтів його можна перенести в іншу систему, яка потім може прочитати з цього стану та отримати клас. Стан об'єкта може надходити з бази даних або іншого jvm або з окремого компонента. За допомогою серіалізації ми можемо отримати стан Object.

Приклад коду та пояснення:

Спочатку давайте подивимось на клас предметів:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

У наведеному вище коді видно, що клас Item реалізує Serializable .

Це інтерфейс, який дозволяє класу бути серіалізаційним.

Тепер ми можемо бачити, що змінна, що називається serialVersionUID , ініціалізована на змінну Long. Це число обчислюється компілятором на основі стану класу та атрибутів класу. Це число, яке допоможе jvm ідентифікувати стан об'єкта, коли він зчитує стан об'єкта з файлу.

Для цього ми можемо ознайомитись з офіційною документацією Oracle:

Тривалість виконання серіалізації асоціює з кожним класом серіалізаційного номера номер версії, який називається serialVersionUID, який використовується під час десеріалізації для перевірки того, що відправник і приймач серіалізованого об'єкта завантажують класи для цього об'єкта, сумісні щодо серіалізації. Якщо одержувач завантажив клас для об'єкта, який має інший serialVersionUID, ніж клас відповідного класу відправника, то десеріалізація призведе до InvalidClassException. Клас серіалізації може оголосити власний serialVersionUID явно, оголосивши поле під назвою "serialVersionUID", яке повинно бути статичним, остаточним і типу довгим: ANY-ACCESS-MODIFIER статичний остаточний довгий serialVersionUID = 42L; Якщо серіалізаційний клас явно не оголошує serialVersionUID, тоді час виконання серіалізації буде обчислювати значення за замовчуванням serialVersionUID для цього класу на основі різних аспектів класу, як описано в специфікації об’єкта серіалізації Java (TM). Однак настійно рекомендується, щоб усі класи, що серіалізуються, явно декларували значення serialVersionUID, оскільки обчислення serialVersionUID за замовчуванням дуже чутливі до деталей класу, які можуть змінюватися залежно від реалізації компілятора, і, таким чином, можуть призвести до несподіваних InvalidClassExceptions під час десеріалізації. Отже, щоб гарантувати послідовне значення serialVersionUID у різних реалізаціях компілятора Java, серіалізаційний клас повинен оголосити явне значення serialVersionUID. Також настійно рекомендується, щоб явні serialVersionUID декларації використовували приватний модифікатор, де це можливо,

Якщо ви помітили, є ще одне нами ключове ключове слово, яке є тимчасовим .

Якщо поле не є серіалізаційним, воно повинно бути позначене тимчасовим. Тут ми позначили itemCostPrice як перехідний і не хочемо, щоб він був записаний у файл

Тепер давайте подивимось, як записати стан об’єкта у файл, а потім прочитати його звідти.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

У вищесказаному ми можемо побачити приклад серіалізації та десеріалізації об'єкта.

Для цього ми використовували два класи. Для серіалізації об'єкта ми використовували ObjectOutputStream. Ми використовували метод writeObject для запису об'єкта у файл.

Для десеріалізації ми використовували ObjectInputStream, який читає з об'єкта з файлу. Він використовує readObject для зчитування даних об'єкта з файлу.

Вихід з вищевказаного коду буде таким:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

Зауважте, що itemCostPrice з десеріалізованого об'єкта є нульовим, оскільки він не був записаний.


2
Дякую за детальне пояснення.
Обіцяйте Престону

Це приємне пояснення! Дякую! Але якщо чесно, цей запис виглядає набагато чіткіше, ніж той, що у вашому блозі. У будь-якому випадку це дуже допомогло!
Sunburst275

11

Серіалізація передбачає збереження поточного стану об'єкта в потоці та відновлення еквівалентного об'єкта з цього потоку. Потік функціонує як контейнер для об'єкта


1
Це визначення видається більш точним. Дякую.
Обіцяйте Престону

6

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

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


5
Це не "прапор компілятору". Це прапор підсистеми серіалізації під час виконання.
Маркіз Лорн

1
@EJP - Спасибі, не знав цього
AphexMunky

Щодо поваги, навіщо писати це, коли ви не знаєте, що це правда? Ви також залишилися "тимчасовими". Загалом погана відповідь, вибачте.
Маркіз Лорн

19
Якби я не писав цього, я б не виправлявся, і було б гірше. Усі інші відповіді також минули тимчасово. Ти навіть відповіді не написав, ти просто тролінг інших людей.
AphexMunky

4

Серіалізація - це метод зберігання або запису об'єктів і даних у файли. За допомогою ObjectOutputStreamта FileOutputStreamзаняттях. Ці класи мають свої конкретні методи збереження об'єктів. подібно доwriteObject();

для чіткого пояснення цифрами. Дивіться тут для отримання додаткової інформації


2

Представити з іншої точки зору. Серіалізація - це різновид інтерфейсу, який називається маркером інтерфейсу. Інтерфейс маркера - це інтерфейс, який не містить оголошень методу, а лише позначає (або "мітки") клас, який реалізує інтерфейс як якийсь властивість. Якщо ви розумієте поліморфізм, це матиме дуже великий сенс. У випадку інтерфейсу маркера Serializable, метод ObjectOutputStream.write (Object) вийде з ладу, якщо його аргумент не реалізує інтерфейс. Це потенційна помилка Java, це могло бути ObjectOutputStream.write (Serializable)

Настійно рекомендуємо: читати пункт 37 з Ефективної Java Джошуа Блоха, щоб дізнатися більше.


2

Серіалізація: стан запису в файл / мережу або деінде. (Середня форма, що підтримується об'єктом Java, до форми, що підтримується файлом, або підтримується мережею форми)

Десеріалізація: стан читання об'єкта з файлу / мережі або з будь-якого місця. (Середня форма файлу / мережі, що підтримується, до форми, що підтримується об'єктом Java)


1

Просто додати до інших відповідей і щодо загальності. Серіалізація іноді відома як архівація, наприклад в Objective-C.

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