Co oznacza Serializable?

136

Co dokładnie oznacza, że ​​klasa jest Serializablew Javie? Lub ogólnie, jeśli o to chodzi ...

Ritwik Bose
źródło
10
@skaffman Oto, co jest napisane dla klasy 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
Świetne wyjaśnienie, jeśli już wiesz, co oznacza serializacja i deserializacja. (Nie jest to komplement). Takie definicje pomagają technicznie lepiej zrozumieć problem raz i tylko raz, gdy masz już pewną wiedzę na jego temat.
Xonatron,

Odpowiedzi:

132

Serializacja polega na utrwalaniu obiektu z pamięci do sekwencji bitów, na przykład w celu zapisania na dysku. Deserializacja jest odwrotna - odczyt danych z dysku w celu uwodnienia / stworzenia obiektu.

W kontekście twojego pytania jest to interfejs, który po zaimplementowaniu w klasie ta klasa może być automatycznie serializowana i deserializowana przez różne serializatory.

Oded
źródło
2
Należy również zauważyć, że wszystkie pola, które nie zostały wyraźnie oznaczone w inny sposób, również zostaną serializowane. Oznacza to, że można łatwo zapisać złożoną strukturę danych, po prostu serializując obiekt główny.
Thorbjørn Ravn Andersen
1
Więc kiedy mówimy o „obiektach”, czy mamy na myśli obiekt utworzony przez klasę, czy po prostu dowolne „obiekty programowe”, takie jak zespoły, pliki itp.? A jeśli to drugie, czy jest to po prostu ustandaryzowany sposób przesyłania danych między programami i środowiskami?
Sunburst275
1
@ Sunburst275 - w tym przypadku jest to reprezentacja w pamięci klasy w pamięci - tj. Wystąpienie klasy (nie ma sensu mówić o serializacji zestawów, ponieważ zwykle znajdują się one na dysku jako pliki, które mogą po prostu być rozsyłane tak, jak jest).
Oded
44

Chociaż większość użytkowników już udzieliła odpowiedzi, ale chciałbym dodać przykład dla tych, którzy tego potrzebują, aby wyjaśnić pomysł:

Załóżmy, że masz osobę z klasy, taką jak ta:

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

a następnie tworzysz taki obiekt:

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

Możesz serializować ten obiekt do wielu strumieni. Zrobię to dla dwóch strumieni:

Serializacja na standardowe wyjście:

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

Serializacja do pliku:

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

Następnie:

Deserializacja z pliku:

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();
    }
William Kinaan
źródło
Dziękuję Ci. Myślę, że mam to teraz.
Sunburst275
40

Oznacza to, że instancje klasy można przekształcić w strumień bajtów (na przykład w celu zapisania do pliku), a następnie ponownie przekształcić w klasy. To przeładowanie może nastąpić w innej instancji programu lub nawet na innym komputerze. Serializacja (w dowolnym języku) wiąże się jednak z różnego rodzaju problemami, zwłaszcza gdy masz odniesienia do innych obiektów w obrębie tego, który można serializować.

David
źródło
15

Oto szczegółowe wyjaśnienie serializacji : (mój własny blog)

Serializacja:

Serializacja to proces serializacji stanu obiektu, który jest reprezentowany i przechowywany w postaci sekwencji bajtów. Można to zapisać w pliku. Proces odczytywania stanu obiektu z pliku i przywracania go nazywa się deserializacją.

Jaka jest potrzeba serializacji?

We współczesnej architekturze zawsze istnieje potrzeba przechowywania stanu obiektu, a następnie jego pobierania. Na przykład w Hibernate, aby przechowywać obiekt, powinniśmy uczynić klasę Serializable. To, co robi, polega na tym, że po zapisaniu stanu obiektu w postaci bajtów można go przenieść do innego systemu, który może następnie odczytać stan i pobrać klasę. Stan obiektu może pochodzić z bazy danych lub innego pliku jvm lub z oddzielnego komponentu. Za pomocą serializacji możemy pobrać stan obiektu.

Kod Przykład i objaśnienie:

Najpierw spójrzmy na klasę przedmiotu:

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

W powyższym kodzie widać, że klasa Item implementuje Serializable .

To jest interfejs, który umożliwia serializację klasy.

Teraz widzimy, że zmienna o nazwie serialVersionUID jest inicjalizowana jako zmienna Long. Ta liczba jest obliczana przez kompilator na podstawie stanu klasy i atrybutów klasy. Jest to liczba, która pomoże jvm zidentyfikować stan obiektu, gdy odczytuje stan obiektu z pliku.

W tym celu możemy zajrzeć do oficjalnej dokumentacji Oracle:

Środowisko uruchomieniowe serializacji kojarzy z każdą możliwą do serializacji klasą numer wersji, zwany serialVersionUID, który jest używany podczas deserializacji w celu sprawdzenia, czy nadawca i odbiorca serializowanego obiektu załadowali klasy dla tego obiektu, które są zgodne pod względem serializacji. Jeśli odbiorca załadował klasę dla obiektu, który ma inny serialVersionUID niż klasa odpowiedniego nadawcy, deserializacja spowoduje wystąpienie InvalidClassException. Klasa możliwa do serializacji może jawnie zadeklarować swój własny serialVersionUID, deklarując pole o nazwie „serialVersionUID”, które musi być statyczne, final i typu long: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; Jeśli klasa możliwa do serializacji nie deklaruje jawnie serialVersionUID, następnie środowisko wykonawcze serializacji obliczy domyślną wartość serialVersionUID dla tej klasy na podstawie różnych aspektów tej klasy, zgodnie z opisem w specyfikacji serializacji obiektu Java (TM). Jednak zdecydowanie zaleca się, aby wszystkie możliwe do serializacji klasy jawnie deklarowały wartości serialVersionUID, ponieważ domyślne obliczenia serialVersionUID są bardzo wrażliwe na szczegóły klasy, które mogą się różnić w zależności od implementacji kompilatora i mogą w związku z tym spowodować nieoczekiwane InvalidClassExceptions podczas deserializacji. Dlatego, aby zagwarantować spójną wartość serialVersionUID w różnych implementacjach kompilatora Java, klasa możliwa do serializacji musi zadeklarować jawną wartość serialVersionUID. Zaleca się również, aby jawne deklaracje serialVersionUID używały prywatnego modyfikatora, jeśli to możliwe,

Jeśli zauważyłeś, istnieje inne słowo kluczowe, którego użyliśmy, które jest przejściowe .

Jeśli pola nie można serializować, należy je oznaczyć jako przejściowe. Tutaj oznaczyliśmy itemCostPrice jako przejściowy i nie chcemy, aby był zapisywany w pliku

Przyjrzyjmy się teraz, jak zapisać stan obiektu w pliku, a następnie odczytać go stamtąd.

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

Na powyższym możemy zobaczyć przykład serializacji i deserializacji obiektu.

W tym celu użyliśmy dwóch klas. Do serializacji obiektu użyliśmy ObjectOutputStream. Do zapisania obiektu w pliku wykorzystaliśmy metodę writeObject.

Do deserializacji użyliśmy ObjectInputStream, który odczytuje obiekt z pliku. Używa readObject do odczytu danych obiektu z pliku.

Wynik powyższego kodu wyglądałby następująco:

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]

Zwróć uwagę, że itemCostPrice z deserializowanego obiektu ma wartość null, ponieważ nie został zapisany.

Pritam Banerjee
źródło
2
Dziękuję za to szczegółowe wyjaśnienie.
Promise Preston
To miłe wyjaśnienie! Dziękuję Ci! Ale szczerze mówiąc, ten wpis wygląda na znacznie bardziej przejrzysty niż ten na Twoim blogu. W każdym razie to bardzo pomogło!
Sunburst275
11

Serializacja obejmuje zapisanie bieżącego stanu obiektu do strumienia i przywrócenie równoważnego obiektu z tego strumienia. Strumień działa jako kontener dla obiektu

Jigar Joshi
źródło
1
Ta definicja wydaje się bardziej precyzyjna. Dziękuję Ci.
Promise Preston
6

Serializable jest wywoływany jak interfejs, ale bardziej przypomina flagę podsystemu serializacji w czasie wykonywania. Mówi, że ten obiekt można uratować. Wszystkie zmienne instancji Objects, z wyjątkiem żadnych obiektów, które można serializować, i tych oznaczonych jako ulotne, zostaną zapisane.

Wyobraź sobie, że Twoja aplikacja może zmienić kolor jako opcję, bez pozostawiania tego ustawienia na zewnątrz, musisz zmieniać kolor za każdym razem, gdy ją uruchomisz.

AphexMunky
źródło
5
Nie jest to „flaga dla kompilatora”. Jest to flaga podsystemu serializacji w czasie wykonywania.
Markiz Lorne
1
@EJP - Dzięki, nie wiedziałem tego
AphexMunky
Z całym szacunkiem, po co to pisać, skoro nie wiesz, że to prawda? Pominięto również termin „przejściowy”. W sumie zła odpowiedź, przepraszam.
Markiz Lorne
19
Gdybym tego nie napisał, nie zostałbym poprawiony i byłbym gorzej. Wszystkie inne odpowiedzi również nie były przejściowe. Nawet nie napisałeś odpowiedzi, po prostu trollujesz inne narody.
AphexMunky
4

Serializacja to technika przechowywania lub zapisywania obiektów i danych w plikach. Używając ObjectOutputStreami FileOutputStreamklas. Te klasy mają swoje specyficzne metody utrwalania obiektów. lubićwriteObject();

dla jasnego wyjaśnienia za pomocą liczb. Zobacz tutaj, aby uzyskać więcej informacji

Mdhar9e
źródło
2

Przedstawić z innej perspektywy. Serializacja to rodzaj interfejsu zwanego „interfejsem znaczników”. Interfejs znacznika to interfejs, który nie zawiera deklaracji metod, a jedynie wyznacza (lub „zaznacza”) klasę, która implementuje interfejs jako mający jakąś właściwość. Jeśli rozumiesz polimorfizm, będzie to miało sens. W przypadku interfejsu znacznika Serializable metoda ObjectOutputStream.write (Object) nie powiedzie się, jeśli jej argument nie implementuje interfejsu. To jest potencjalny błąd w Javie, mógł to być ObjectOutputStream.write (Serializable)

Bardzo zalecane: przeczytanie pozycji 37 z książki Effective Java autorstwa Joshua Blocha, aby dowiedzieć się więcej.

nanospeck
źródło
2

Serializacja: zapis stanu obiektu do pliku / sieci lub gdziekolwiek. (Średni formularz obsługiwanego obiektu Java do formularza obsługiwanego pliku lub formularza obsługiwanego przez sieć)

Deserializacja: odczyt stanu obiektu z pliku / sieci lub z dowolnego miejsca. (Średni plik / format obsługiwany przez sieć do formularza obsługiwanego przez obiekt Java)

Asif Mushtaq
źródło
1

Wystarczy dodać do innych odpowiedzi i w odniesieniu do ogólności. Serializacja jest czasami nazywana archiwizacją, na przykład w Objective-C.

Greg Sexton
źródło