Что означает 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.
Ритвик Бозе

32
Отличное объяснение, если вы уже знаете, что означает сериализация и десериализация. (Не комплимент.) Такие определения помогут вам технически лучше понять проблему один раз, и только один раз вы уже знаете об этом.
Xonatron

Ответы:


132

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

В контексте вашего вопроса, это интерфейс, который, если реализован в классе, этот класс может автоматически сериализоваться и десериализироваться различными сериализаторами.


2
Также обратите внимание, что все поля, не помеченные явно, также будут сериализованы. Это означает, что вы можете легко сохранить сложную структуру данных, просто сериализовав корневой объект.
Турбьёрн Равн Андерсен

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 или отдельного компонента. С помощью сериализации мы можем получить состояние объекта.

Пример кода и объяснение:

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

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», которое должно быть статическим, конечным и типа long: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; Если сериализуемый класс явно не объявляет serialVersionUID, затем среда выполнения сериализации вычислит значение serialVersionUID по умолчанию для этого класса на основе различных аспектов класса, как описано в Спецификации сериализации объектов Java (TM). Однако настоятельно рекомендуется, чтобы все сериализуемые классы явно объявляли значения serialVersionUID, поскольку вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора, и, следовательно, могут привести к неожиданным исключениям InvalidClassExceptions во время десериализации. Поэтому, чтобы гарантировать согласованное значение serialVersionUID в различных реализациях Java-компилятора, сериализуемый класс должен объявить явное значение serialVersionUID. Также настоятельно рекомендуется, чтобы в явных объявлениях serialVersionUID использовался модификатор private, если это возможно,

Если вы заметили, что мы использовали другое ключевое слово, которое является временным .

Если поле не сериализуемо, оно должно быть помечено как переходное. Здесь мы отметили 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 из десериализованного объекта имеет значение null, поскольку оно не было записано.


2
Спасибо за это подробное объяснение.
Обещание Престон

Это хорошее объяснение! Спасибо! Но, честно говоря, эта запись выглядит намного чище, чем в вашем блоге. В любом случае, это очень помогло!
Sunburst275

11

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


1
Это определение кажется более точным. Спасибо.
Обещание Престон

6

Serializable вызывается как интерфейс, но больше похож на флаг подсистеме Serialization во время выполнения. Это говорит, что этот объект может быть сохранен. Все переменные экземпляра Objects, за исключением не сериализуемых объектов и помеченных как volatile, будут сохранены.

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


5
Это не «флаг компилятору». Это флаг подсистемы сериализации во время выполнения.
Маркиз Лорн

1
@EJP - Спасибо, не знал об этом
AphexMunky

С уважением, зачем писать, если не знаешь, что это правда? Вы также пропустили «переходный процесс». В целом плохой ответ, извините.
Маркиз Лорн

19
Если бы я не написал это, я бы не исправился и был бы в худшем положении. Все остальные ответы тоже были преходящими. Ты даже не написал ответ, ты просто троллишь других людей.
AphexMunky

4

Сериализация - это метод хранения или записи объектов и данных в файлы. С помощью ObjectOutputStreamи FileOutputStreamклассов. Эти классы имеют свои специфические методы для сохранения объектов. лайкwriteObject();

для наглядного объяснения цифрами. Смотрите здесь для получения дополнительной информации


2

Чтобы представить с другой точки зрения. Сериализация - это своего рода интерфейс, называемый «маркерный интерфейс». Интерфейс маркера - это интерфейс, который не содержит объявлений метода, а просто обозначает (или «маркирует») класс, который реализует интерфейс как имеющий некоторое свойство. Если вы понимаете полиморфизм, это будет иметь большой смысл. В случае интерфейса маркера Serializable метод ObjectOutputStream.write (Object) завершится ошибкой, если его аргумент не реализует интерфейс. Это потенциальная ошибка в Java, это мог быть ObjectOutputStream.write (Serializable)

Настоятельно рекомендуется: Читать статью 37 из книги «Эффективная Ява» Джошуа Блоха, чтобы узнать больше.


2

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

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


1

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.