Was bedeutet serialisierbar?


136

Was genau bedeutet es für eine Klasse, Serializablein Java zu sein? Oder generell ...


10
@skaffman Hier ist, was es für die Klasse sagt 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
Eine gute Erklärung, wenn Sie bereits wissen, was serialisiert und deserialisiert bedeuten. (Kein Kompliment.) Solche Definitionen helfen Ihnen, das Problem technisch einmal besser zu verstehen, und nur einmal haben Sie bereits einige Kenntnisse darüber.
Xonatron

Antworten:


131

Bei der Serialisierung bleibt ein Objekt aus dem Speicher in einer Folge von Bits erhalten, beispielsweise zum Speichern auf der Festplatte. Deserialisierung ist das Gegenteil - Lesen von Daten von der Festplatte, um ein Objekt zu hydratisieren / zu erstellen.

Im Kontext Ihrer Frage handelt es sich um eine Schnittstelle, die bei Implementierung in einer Klasse von verschiedenen Serialisierern automatisch serialisiert und deserialisiert werden kann.


2
Beachten Sie auch, dass alle Felder, die nicht explizit anderweitig markiert sind, ebenfalls serialisiert werden. Dies bedeutet, dass Sie eine komplexe Datenstruktur einfach speichern können, indem Sie das Stammobjekt serialisieren.
Thorbjørn Ravn Andersen

1
Wenn wir also von "Objekten" sprechen, meinen wir das Objekt, das von einer Klasse instanziiert wurde, oder nur irgendwelche "Softwareobjekte" wie Assemblys, Dateien usw.? Und wenn es das letztere ist, ist es nur eine standardisierte Methode zum Senden von Daten zwischen Programmen und Umgebungen?
Sunburst275

1
@ Sunburst275 - in diesem Fall ist dies die In-Memory-Darstellung einer Klasse im Speicher - dh eine Instanz einer Klasse (es macht keinen Sinn, über die Serialisierung von Assemblys zu sprechen, da diese normalerweise als Dateien auf der Festplatte gespeichert werden können einfach so wie es ist herumgeschickt werden).
Oded

43

Obwohl die meisten Benutzer die Antwort bereits gegeben haben, möchte ich ein Beispiel für diejenigen hinzufügen, die sie benötigen, um die Idee zu erklären:

Angenommen, Sie haben eine Klassenperson wie die folgende:

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

und dann erstellen Sie ein Objekt wie folgt:

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

Sie können dieses Objekt für viele Streams serialisieren. Ich werde das mit zwei Streams machen:

Serialisierung auf Standardausgabe:

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

Serialisierung in eine Datei:

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

Dann:

Deserialisieren aus Datei:

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

Danke dir. Ich glaube, ich habe es jetzt verstanden.
Sunburst275

39

Dies bedeutet, dass Instanzen der Klasse in einen Byte-Stream umgewandelt werden können (z. B. um in einer Datei gespeichert zu werden) und dann wieder in Klassen konvertiert werden können. Dieses Neuladen kann in einer anderen Instanz des Programms oder sogar auf einem anderen Computer erfolgen. Die Serialisierung (in jeder Sprache) ist jedoch mit allen möglichen Problemen verbunden, insbesondere wenn Sie Verweise auf andere Objekte innerhalb des serialisierbaren Objekts haben.


14

Hier ist eine detaillierte Erklärung der Serialisierung : (mein eigener Blog)

Serialisierung:

Bei der Serialisierung wird der Status eines Objekts serialisiert, das in Form einer Folge von Bytes dargestellt und gespeichert wird. Dies kann in einer Datei gespeichert werden. Der Vorgang zum Lesen und Wiederherstellen des Status des Objekts aus der Datei wird als Deserialisierung bezeichnet.

Was ist die Notwendigkeit der Serialisierung?

In der modernen Architektur besteht immer die Notwendigkeit, den Objektstatus zu speichern und dann abzurufen. Zum Beispiel sollten wir im Ruhezustand zum Speichern eines Objekts die Klasse Serializable machen. Sobald der Objektstatus in Form von Bytes gespeichert ist, kann er auf ein anderes System übertragen werden, das dann aus dem Status lesen und die Klasse abrufen kann. Der Objektstatus kann aus einer Datenbank oder einem anderen JVM oder aus einer separaten Komponente stammen. Mit Hilfe der Serialisierung können wir den Objektstatus abrufen.

Codebeispiel und Erklärung:

Schauen wir uns zuerst die Gegenstandsklasse an:

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

Im obigen Code ist zu sehen, dass die Item- Klasse Serializable implementiert .

Dies ist die Schnittstelle, über die eine Klasse serialisierbar ist.

Jetzt können wir sehen, dass eine Variable namens serialVersionUID mit der Variablen Long initialisiert wird. Diese Zahl wird vom Compiler basierend auf dem Status der Klasse und den Klassenattributen berechnet. Dies ist die Nummer, mit der der JVM den Status eines Objekts identifizieren kann, wenn er den Status des Objekts aus der Datei liest.

Dafür können wir uns die offizielle Oracle-Dokumentation ansehen:

Die Serialisierungslaufzeit ordnet jeder serialisierbaren Klasse eine Versionsnummer zu, die als serialVersionUID bezeichnet wird und während der Deserialisierung verwendet wird, um zu überprüfen, ob der Absender und der Empfänger eines serialisierten Objekts Klassen für dieses Objekt geladen haben, die hinsichtlich der Serialisierung kompatibel sind. Wenn der Empfänger eine Klasse für das Objekt geladen hat, das eine andere serialVersionUID als die Klasse des entsprechenden Absenders hat, führt die Deserialisierung zu einer InvalidClassException. Eine serialisierbare Klasse kann ihre eigene serialVersionUID explizit deklarieren, indem sie ein Feld mit dem Namen "serialVersionUID" deklariert, das statisch, final und vom Typ long sein muss: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; Wenn eine serialisierbare Klasse eine serialVersionUID nicht explizit deklariert, Anschließend berechnet die Serialisierungslaufzeit einen Standardwert für serialVersionUID für diese Klasse basierend auf verschiedenen Aspekten der Klasse, wie in der Java (TM) -Objektserialisierungsspezifikation beschrieben. Es wird jedoch dringend empfohlen, dass alle serialisierbaren Klassen explizit serialVersionUID-Werte deklarieren, da die Standardberechnung für serialVersionUID sehr empfindlich auf Klassendetails reagiert, die je nach Compiler-Implementierungen variieren können und daher während der Deserialisierung zu unerwarteten InvalidClassExceptions führen können. Um einen konsistenten serialVersionUID-Wert für verschiedene Java-Compiler-Implementierungen zu gewährleisten, muss eine serialisierbare Klasse daher einen expliziten serialVersionUID-Wert deklarieren. Es wird außerdem dringend empfohlen, dass explizite serialVersionUID-Deklarationen nach Möglichkeit den privaten Modifikator verwenden.

Wenn Sie bemerkt haben, dass wir ein anderes Schlüsselwort verwendet haben, das vorübergehend ist .

Wenn ein Feld nicht serialisierbar ist, muss es als vorübergehend markiert werden. Hier haben wir den itemCostPrice als vorübergehend markiert und möchten nicht, dass er in eine Datei geschrieben wird

Schauen wir uns nun an, wie Sie den Status eines Objekts in die Datei schreiben und von dort aus lesen.

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

Oben sehen wir ein Beispiel für die Serialisierung und Deserialisierung eines Objekts.

Dafür haben wir zwei Klassen verwendet. Für die Serialisierung des Objekts haben wir ObjectOutputStream verwendet. Wir haben die Methode writeObject verwendet, um das Objekt in die Datei zu schreiben.

Für die Deserialisierung haben wir ObjectInputStream verwendet, der aus dem Objekt aus der Datei liest. Es verwendet readObject, um die Objektdaten aus der Datei zu lesen.

Die Ausgabe des obigen Codes wäre wie folgt:

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]

Beachten Sie, dass itemCostPrice vom deserialisierten Objekt null ist, da es nicht geschrieben wurde.


2
Vielen Dank für diese ausführliche Erklärung.
Versprechen Preston

Das ist eine schöne Erklärung! Danke dir! Aber um ehrlich zu sein, sieht dieser Eintrag viel sauberer aus als der in Ihrem Blog. Wie auch immer, das hat sehr geholfen!
Sunburst275

11

Bei der Serialisierung wird der aktuelle Status eines Objekts in einem Stream gespeichert und ein gleichwertiges Objekt aus diesem Stream wiederhergestellt. Der Stream fungiert als Container für das Objekt


1
Diese Definition scheint genauer zu sein. Danke dir.
Versprechen Preston

6

Serializable wird wie eine Schnittstelle aufgerufen, ist jedoch eher ein Flag für den Compiler. Es heißt, dass dieses Objekt gespeichert werden kann. Alle Instanzvariablen von Objects mit Ausnahme von nicht serialisierbaren Objekten und solchen, die als flüchtig markiert sind, werden gespeichert.

Stellen Sie sich vor, Ihre Anwendung kann die Farbe optional ändern, ohne dass diese Einstellung extern bleibt. Sie müssten die Farbe jedes Mal ändern, wenn Sie sie ausführen.


5
Es ist kein "Flag für den Compiler". Es ist zur Laufzeit ein Flag für das Serialisierungssubsystem.
Marquis von Lorne

1
@ EJP - Danke, wusste das nicht
AphexMunky

Warum sollte man es mit Respekt schreiben, wenn man nicht weiß, dass es wahr ist? Sie haben auch "vorübergehend" ausgelassen. Alles in allem eine schlechte Antwort, sorry.
Marquis von Lorne

19
Wenn ich es nicht geschrieben hätte, wäre ich nicht korrigiert worden und wäre schlechter dran. Alle anderen Antworten haben auch vorübergehend aufgehört. Du hast nicht einmal eine Antwort geschrieben, du trollst nur andere Völker.
AphexMunky

4

Die Serialisierung ist eine Technik zum Speichern oder Schreiben der Objekte und Daten in Dateien. Mit ObjectOutputStreamund FileOutputStreamKlassen. Diese Klassen haben ihre spezifischen Methoden, um die Objekte beizubehalten. mögenwriteObject();

für eine klare Erklärung mit Zahlen. Weitere Informationen finden Sie hier


2

Aus einer anderen Perspektive präsentieren. Die Serialisierung ist eine Art Schnittstelle, die als "Marker-Schnittstelle" bezeichnet wird. Eine Markierungsschnittstelle ist eine Schnittstelle, die keine Methodendeklarationen enthält, sondern lediglich eine Klasse bezeichnet (oder „markiert“), die die Schnittstelle mit einer Eigenschaft implementiert. Wenn Sie Polymorphismus verstehen, ist dies sehr sinnvoll. Bei der Serializable-Marker-Schnittstelle schlägt die ObjectOutputStream.write (Object) -Methode fehl, wenn ihr Argument die Schnittstelle nicht implementiert. Dies ist ein möglicher Fehler in Java. Es könnte ObjectOutputStream.write (Serializable) gewesen sein.

Sehr zu empfehlen: Lesen Sie Punkt 37 aus Effective Java von Joshua Bloch , um mehr zu erfahren.


2

Serialisierung: Schreiben des Objektstatus in eine Datei / ein Netzwerk oder irgendwo anders. (Mittleres von Java Object unterstütztes Formular zu Dateiunterstütztes Formular oder Netzwerkunterstütztes Formular)

Deserialisierung: Lesen des Objektstatus aus Datei / Netzwerk oder irgendwo anders . (Mittleres von Dateien / Netzwerken unterstütztes Formular zum von Java Object unterstützten Formular)


0

Nur um die anderen Antworten und in Bezug auf die Allgemeinheit zu ergänzen. Serialisierung wird manchmal als Archivierung bezeichnet, beispielsweise in Objective-C.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.