Was ist Objektserialisierung?

Antworten:

400

Bei der Serialisierung wird ein Objekt in eine Reihe von Bytes konvertiert, sodass das Objekt problemlos in einem dauerhaften Speicher gespeichert oder über eine Kommunikationsverbindung gestreamt werden kann. Der Bytestream kann dann deserialisiert und in eine Replik des ursprünglichen Objekts konvertiert werden.

TarkaDaal
quelle
16
ist das obligatorisch? Muss ich Daten serialisieren, bevor ich sie sende? In welches Format wird es konvertiert?
Francisco Corrales Morales
15
@FranciscoCorralesMorales - Hinter den Kulissen werden alle Daten serialisiert, bevor sie über einen Stream gesendet werden. Wie viel Sie tun müssen und in welchem ​​Format es sein wird, hängt davon ab, welche Plattform und welche Bibliotheken Sie verwenden.
TarkaDaal
3
@FranciscoCorralesMorales Wie sagst du das? Ich meine, Sie sagen, das Format hängt von der Plattform und den Bibliotheken ab. Ich möchte das Format wirklich wissen.
JAVA
1
Gilt es nur für Objekte? Können wir Variablen serialisieren (ohne Verwendung von Objekten deklariert)?
Rumado
@Rumado Objekte nur
anKotliner
395

Sie können sich Serialisierung als den Prozess des Konvertierens einer Objektinstanz in eine Folge von Bytes vorstellen (die je nach Implementierung binär sein können oder nicht).

Dies ist sehr nützlich, wenn Sie Objektdaten über das Netzwerk übertragen möchten, beispielsweise von einer JVM zu einer anderen.

In Java ist der Serialisierungsmechanismus in die Plattform integriert, Sie müssen jedoch die serialisierbare Schnittstelle implementieren , um ein Objekt serialisierbar zu machen.

Sie können auch verhindern, dass einige Daten in Ihrem Objekt serialisiert werden, indem Sie das Attribut als vorübergehend markieren .

Schließlich können Sie den Standardmechanismus überschreiben und Ihren eigenen bereitstellen. Dies kann in einigen besonderen Fällen geeignet sein. Dazu verwenden Sie eine der versteckten Funktionen in Java .

Es ist wichtig zu beachten, dass der "Wert" des Objekts oder des Inhalts und nicht die Klassendefinition serialisiert wird. Daher werden Methoden nicht serialisiert.

Hier ist ein sehr einfaches Beispiel mit Kommentaren, um das Lesen zu erleichtern:

import java.io.*;
import java.util.*;

// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the "value" of the object.

    // These two will be serialized;
    private String aString = "The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  { 

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The "ObjectOutputStream" class has the default 
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream( 
                               // By using "FileOutputStream" we will 
                               // Write it to a File in the file system
                               // It could have been a Socket to another 
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

Wenn wir dieses Programm ausführen, wird die Datei "o.ser" erstellt und wir können sehen, was dahinter passiert ist.

Wenn wir den Wert von: someInteger in beispielsweise Integer.MAX_VALUE ändern , können wir die Ausgabe vergleichen , was der Unterschied ist.

Hier ist ein Screenshot, der genau diesen Unterschied zeigt:

Alt-Text

Kannst du die Unterschiede erkennen? ;)

Es gibt ein zusätzliches relevantes Feld in der Java-Serialisierung: Die serialversionUID, aber ich denke, dies ist bereits zu lang, um sie abzudecken.

OscarRyz
quelle
1
@ raam86- Instanz ist das Objekt, das serialisiert wird. Sie können in der Hauptmethode als separates Programm denken, das ein Objekt vom Typ erstelltSerializationSample
OscarRyz
2
@ raam86 ist die erste Anweisung in der Hauptmethode: SerializationSample instance = new SerializationSample();Dann wird die Ausgabe erstellt und das Objekt in diese Ausgabe geschrieben.
OscarRyz
1
Oh. Nicht nah genug gefolgt. Großartig!!
raam86
1
@jacktrades Warum versuchst du es nicht? Kopieren Sie einfach das Beispiel / fügen Sie es ein und sehen Sie, wie "NotSerializableException" ausgelöst wird :)
OscarRyz
1
@jacktrades, weil dem Computer nicht mitgeteilt wurde, dass das Objekt serialisiert werden darf :) Was ist mit oos gemeint?
Chris Bennett
101

Ich wage es, die 6-jährige Frage zu beantworten, und füge nur ein sehr hohes Verständnis für Leute hinzu, die neu in Java sind

Was ist Serialisierung?

Konvertieren eines Objekts in Bytes

Was ist Deserialisierung?

Bytes zurück in ein Objekt konvertieren (Deserialisierung).

Wann wird die Serialisierung verwendet?

Wenn wir das Objekt beibehalten wollen. Wenn wir möchten, dass das Objekt über die Lebensdauer der JVM hinaus existiert.

Beispiel aus der realen Welt:

Geldautomat: Wenn der Kontoinhaber versucht, Geld über einen Geldautomaten vom Server abzuheben, werden die Kontoinhaberinformationen wie Auszahlungsdaten serialisiert und an den Server gesendet, wo die Daten deserialisiert und zur Durchführung von Vorgängen verwendet werden.

Wie die Serialisierung in Java durchgeführt wird.

  1. Implementieren java.io.Serializable (Markierungsschnittstelle, daher keine zu implementierende Methode).

  2. Behalten Sie das Objekt bei: Verwenden Sie java.io.ObjectOutputStream class, einen Filterstrom, der einen Wrapper um einen Byte-Stream niedrigerer Ebene darstellt (um Objekt in Dateisysteme zu schreiben oder ein abgeflachtes Objekt über eine Netzwerkleitung zu übertragen und auf der anderen Seite neu zu erstellen).

    • writeObject(<<instance>>) - um ein Objekt zu schreiben
    • readObject() - um ein serialisiertes Objekt zu lesen

Merken:

Wenn Sie ein Objekt serialisieren, wird nur der Status des Objekts gespeichert, nicht die Klassendatei oder Methoden des Objekts.

Wenn Sie ein 2-Byte-Objekt serialisiert haben, wird eine serialisierte 51-Byte-Datei angezeigt.

Schritte, wie das Objekt serialisiert und de-serialisiert wird.

Antwort für: Wie wurde es in eine 51-Byte-Datei konvertiert?

  • Schreibt zuerst die magischen Daten des Serialisierungsstroms (STREAM_MAGIC = "AC ED" und STREAM_VERSION = Version der JVM).
  • Anschließend werden die Metadaten der einer Instanz zugeordneten Klasse (Länge der Klasse, Name der Klasse, serialVersionUID) geschrieben.
  • Dann schreibt es rekursiv die Metadaten der Oberklasse aus, bis es gefunden wird java.lang.Object .
  • Beginnt dann mit den tatsächlichen Daten, die der Instanz zugeordnet sind.
  • Schließlich werden die Daten der mit der Instanz verknüpften Objekte beginnend mit den Metadaten in den eigentlichen Inhalt geschrieben.

Wenn Sie an detaillierteren Informationen zur Java-Serialisierung interessiert sind, klicken Sie auf diesen Link .

Bearbeiten : Noch ein guter Link zum Lesen.

Dies wird einige häufige Fragen beantworten:

  1. So serialisieren Sie kein Feld in der Klasse.
    Antwort: Verwenden Sie ein vorübergehendes Schlüsselwort

  2. Wenn die untergeordnete Klasse serialisiert wird, wird die übergeordnete Klasse serialisiert?
    Antwort: Nein, wenn ein übergeordnetes Element das übergeordnete Feld der serialisierbaren Schnittstelle nicht erweitert, wird es nicht serialisiert.

  3. Wenn ein Elternteil serialisiert wird, wird die untergeordnete Klasse serialisiert?
    Antwort: Ja, standardmäßig wird die untergeordnete Klasse auch serialisiert.

  4. Wie kann verhindert werden, dass Kinderklassen serialisiert werden?
    Ans: a. Überschreiben Sie die writeObject- und readObject-Methode und werfen Sie NotSerializableException.

    b. Sie können auch alle Felder markieren, die in der untergeordneten Klasse vorübergehend sind.

  5. Einige Klassen auf Systemebene wie Thread, OutputStream und seine Unterklassen sowie Socket sind nicht serialisierbar.
VdeX
quelle
3
Vielen Dank für diese prägnante Antwort, sie war sehr hilfreich!
Nobi
21

Bei der Serialisierung wird ein "lebendes" Objekt in den Speicher genommen und in ein Format konvertiert, das irgendwo gespeichert werden kann (z. B. im Speicher, auf der Festplatte) und später wieder in ein lebendes Objekt "deserialisiert" werden kann.

Kent Boogaart
quelle
14

Mir hat die Art und Weise gefallen, wie @OscarRyz präsentiert. Obwohl ich hier die Geschichte der Serialisierung fortsetze, die ursprünglich von @amitgupta geschrieben wurde.

Obwohl die Wissenschaftler der Erde über die Struktur der Roboterklasse Bescheid wussten und Daten serialisiert hatten, waren sie nicht in der Lage, die Daten zu deserialisieren, die Roboter zum Funktionieren bringen können.

Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:

Die Wissenschaftler des Mars warteten auf die vollständige Zahlung. Sobald die Zahlung erfolgt war, teilten die Mars-Wissenschaftler die serialversionUID mit den Wissenschaftlern der Erde. Der Erdwissenschaftler stellte es auf Roboterklasse und alles wurde gut.

noquery
quelle
9

Serialisierung bedeutet, dass Objekte in Java beibehalten werden. Wenn Sie den Status des Objekts speichern und den Status später neu erstellen möchten (möglicherweise in einer anderen JVM), kann die Serialisierung verwendet werden.

Beachten Sie, dass die Eigenschaften eines Objekts nur gespeichert werden. Wenn Sie das Objekt erneut beleben möchten, sollten Sie über die Klassendatei verfügen, da nur die Elementvariablen gespeichert werden und nicht die Elementfunktionen.

z.B:

ObjectInputStream oos = new ObjectInputStream(                                 
                                 new FileInputStream(  new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();

Das Searializable ist eine Markierungsschnittstelle, die markiert, dass Ihre Klasse serialisierbar ist. Markierungsschnittstelle bedeutet, dass es sich nur um eine leere Schnittstelle handelt. Wenn Sie diese Schnittstelle verwenden, wird die JVM benachrichtigt, dass diese Klasse serialisierbar gemacht werden kann.

Sathesh
quelle
9

Meine zwei Cent aus meinem eigenen Blog:

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

Serialisierung:

Bei der Serialisierung wird der Status eines Objekts beibehalten. Es wird in Form einer Folge von Bytes dargestellt und gespeichert. 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.

Dazu 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 der entsprechenden Absenderklasse 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 markiert als vorübergehend 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.

Wir haben bereits in Teil I dieses Artikels die Grundlagen der Java-Serialisierung erörtert.

Lassen Sie uns nun ausführlich darüber diskutieren und wie es funktioniert.

Beginnen wir zunächst mit der Serienversion.

Die serialVersionUID wird als Versionskontrolle in einer serialisierbaren Klasse verwendet.

Wenn Sie eine serialVersionUID nicht explizit deklarieren, erledigt JVM dies automatisch für Sie, basierend auf verschiedenen Eigenschaften der Serializable-Klasse.

Javas Algorithmus zur Berechnung der Serialversionuid (Weitere Details finden Sie hier)

  1. Der Klassenname.
    1. Die Klassenmodifikatoren werden als 32-Bit-Ganzzahl geschrieben.
    2. Der Name jeder Schnittstelle, sortiert nach Namen.
    3. Für jedes Feld der Klasse, sortiert nach Feldnamen (außer privaten statischen und privaten transienten Feldern: Der Name des Feldes. Die Modifikatoren des Feldes, geschrieben als 32-Bit-Ganzzahl. Der Deskriptor des Feldes.
    4. Wenn ein Klasseninitialisierer vorhanden ist, schreiben Sie Folgendes aus: Der Name der Methode ,.
    5. Der Modifikator der Methode java.lang.reflect.Modifier.STATIC, geschrieben als 32-Bit-Ganzzahl.
    6. Der Deskriptor der Methode, () V.
    7. Für jeden nicht privaten Konstruktor, sortiert nach Methodenname und Signatur: Der Name der Methode ,. Die Modifikatoren der Methode werden als 32-Bit-Ganzzahl geschrieben. Der Deskriptor der Methode.
    8. Für jede nicht private Methode, sortiert nach Methodenname und Signatur: Der Name der Methode. Die Modifikatoren der Methode werden als 32-Bit-Ganzzahl geschrieben. Der Deskriptor der Methode.
    9. Der SHA-1-Algorithmus wird für den von DataOutputStream erzeugten Bytestrom ausgeführt und erzeugt fünf 32-Bit-Werte sha [0..4]. Der Hash-Wert wird aus den ersten und zweiten 32-Bit-Werten des SHA-1-Nachrichtenauszugs zusammengestellt. Wenn sich das Ergebnis des Nachrichtenauszugs, die fünf 32-Bit-Wörter H0 H1 H2 H3 H4, in einem Array von fünf int-Werten mit dem Namen sha befindet, wird der Hash-Wert wie folgt berechnet:
    long hash = ((sha[0] >>> 24) & 0xFF) |
>            ((sha[0] >>> 16) & 0xFF) << 8 |
>            ((sha[0] >>> 8) & 0xFF) << 16 |
>            ((sha[0] >>> 0) & 0xFF) << 24 |
>            ((sha[1] >>> 24) & 0xFF) << 32 |
>            ((sha[1] >>> 16) & 0xFF) << 40 |
>            ((sha[1] >>> 8) & 0xFF) << 48 |
>        ((sha[1] >>> 0) & 0xFF) << 56;

Javas Serialisierungsalgorithmus

Der Algorithmus zum Serialisieren eines Objekts wird wie folgt beschrieben:
1. Er schreibt die Metadaten der einer Instanz zugeordneten Klasse aus.
2. Die Beschreibung der Oberklasse wird rekursiv ausgeschrieben, bis java.lang.object gefunden wird .
3. Sobald das Schreiben der Metadateninformationen abgeschlossen ist, beginnt es mit den tatsächlichen Daten, die der Instanz zugeordnet sind. Aber diesmal geht es von der obersten Oberklasse aus.
4. Es schreibt rekursiv die der Instanz zugeordneten Daten, beginnend von der kleinsten Oberklasse bis zur am meisten abgeleiteten Klasse.

Dinge, die Sie beachten sollten:

  1. Statische Felder in einer Klasse können nicht serialisiert werden.

    public class A implements Serializable{
         String s;
         static String staticString = "I won't be serializable";
    }
  2. Wenn sich die serialversionuid in der Leseklasse unterscheidet, wird eine InvalidClassExceptionAusnahme ausgelöst .

  3. Wenn eine Klasse serialisierbar implementiert, sind auch alle ihre Unterklassen serialisierbar.

    public class A implements Serializable {....};
    
    public class B extends A{...} //also Serializable
  4. Wenn eine Klasse eine Referenz einer anderen Klasse hat, müssen alle Referenzen serialisierbar sein, da sonst kein Serialisierungsprozess durchgeführt wird. In diesem Fall wird NotSerializableException zur Laufzeit ausgelöst.

Z.B:

public class B{
     String s,
     A a; // class A needs to be serializable i.e. it must implement Serializable
}
Pritam Banerjee
quelle
1
'Serialisierung ist der Prozess der Serialisierung des Zustands eines Objekts, das in Form einer Folge von Bytes dargestellt und gespeichert wird' ist bedeutungslos. Wenn das serialVersionUIDanders ist, wird es ein werfen InvalidClassException, nicht ein ClassCastException. Es ist nicht notwendig, den gesamten Speicherplatz für die serialVersionUIDBerechnung zu verschwenden . Die Dokumentation wird zu ausführlich zitiert, jedoch nicht verlinkt oder ordnungsgemäß zitiert. Zu viel Flaum hier und zu viele Fehler.
Marquis von Lorne
"Serialisierung ist der Prozess der Serialisierung" bleibt bedeutungslos.
Marquis von Lorne
6

Bei der Serialisierung wird der Status eines Objekts in Bits konvertiert, damit es auf einer Festplatte gespeichert werden kann. Wenn Sie dasselbe Objekt deserialisieren, behält es später seinen Status bei. Sie können Objekte neu erstellen, ohne die Eigenschaften der Objekte manuell speichern zu müssen.

http://en.wikipedia.org/wiki/Serialization

Käse Daneish
quelle
"... damit es auf einer Festplatte gespeichert werden kann." Oder über ein Binärprotokoll übertragen.
Jim Anderson
4

Java Object Serialization

Geben Sie hier die Bildbeschreibung ein

Serializationist ein Mechanismus zum Transformieren eines Diagramms von Java-Objekten in ein Array von Bytes zur Speicherung ( to disk file) oder Übertragung ( across a network). Durch Deserialisierung können wir dann das Diagramm von Objekten wiederherstellen. Diagramme von Objekten werden mithilfe eines Referenzfreigabemechanismus korrekt wiederhergestellt. Überprüfen Sie jedoch vor dem Speichern, ob die serialVersionUID aus der Eingabedatei / dem Netzwerk und die .class-Datei serialVersionUID identisch sind. Wenn nicht, werfen Sie eine java.io.InvalidClassException.

Jede versionierte Klasse muss die ursprüngliche Klassenversion identifizieren, für die sie Streams schreiben und von der sie lesen kann. Beispielsweise muss eine versionierte Klasse Folgendes deklarieren:

serialVersionUID Syntax

// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L;
private static final long serialVersionUID = 3487495895819393L;

serialVersionUID ist für den Serialisierungsprozess von wesentlicher Bedeutung. Für den Entwickler ist es jedoch optional, es der Java-Quelldatei hinzuzufügen. Wenn eine serialVersionUID nicht enthalten ist, generiert die Serialisierungslaufzeit eine serialVersionUID und ordnet sie der Klasse zu. Das serialisierte Objekt enthält diese serialVersionUID zusammen mit anderen Daten.

Hinweis - Es wird dringend empfohlen, dass alle serialisierbaren Klassen explizit eine serialVersionUID deklarieren. Dies since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementationskann zu unerwarteten Konflikten zwischen serialVersionUID während der Deserialisierung führen, wodurch die Deserialisierung fehlschlägt.

Überprüfen serialisierbarer Klassen

Geben Sie hier die Bildbeschreibung ein


Ein Java-Objekt ist nur serialisierbar. Wenn eine Klasse oder eine ihrer Oberklassen entweder die Schnittstelle java.io.Serializable oder ihre Unterschnittstelle java.io.Externalizable implementiert .

  • Eine Klasse muss die Schnittstelle java.io.Serializable implementieren, um ihr Objekt erfolgreich zu serialisieren. Serializable ist eine Markierungsschnittstelle, mit der der Compiler darüber informiert wird, dass der Klasse, die sie implementiert, ein serialisierbares Verhalten hinzugefügt werden muss. Hier ist Java Virtual Machine (JVM) für die automatische Serialisierung verantwortlich.

    vorübergehendes Schlüsselwort: java.io.Serializable interface

    Wenn wir beim Serialisieren eines Objekts nicht möchten, dass bestimmte Datenelemente des Objekts serialisiert werden, können wir den Transientenmodifikator verwenden. Das Schlüsselwort transient verhindert, dass dieses Datenelement serialisiert wird.

    • Als transient oder statisch deklarierte Felder werden vom Serialisierungsprozess ignoriert.

    TRANSIENT & VOLATIL

    +--------------+--------+-------------------------------------+
    |  Flag Name   |  Value | Interpretation                      |
    +--------------+--------+-------------------------------------+
    | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
    +--------------+--------+-------------------------------------+
    |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
    |              |        | read by a persistent object manager.|
    +--------------+--------+-------------------------------------+
    class Employee implements Serializable {
        private static final long serialVersionUID = 2L;
        static int id;
    
        int eno; 
        String name;
        transient String password; // Using transient keyword means its not going to be Serialized.
    }
  • Durch die Implementierung der Externalizable-Schnittstelle kann das Objekt die vollständige Kontrolle über Inhalt und Format der serialisierten Form des Objekts übernehmen. Die Methoden der Externalizable-Schnittstelle writeExternal und readExternal werden aufgerufen, um den Objektstatus zu speichern und wiederherzustellen. Wenn sie von einer Klasse implementiert werden, können sie mit allen Methoden von ObjectOutput und ObjectInput ihren eigenen Status schreiben und lesen. Es liegt in der Verantwortung der Objekte, die auftretende Versionierung durchzuführen.

    class Emp implements Externalizable {
        int eno; 
        String name;
        transient String password; // No use of transient, we need to take care of write and read.
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(eno);
            out.writeUTF(name);
            //out.writeUTF(password);
        }
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            this.eno = in.readInt();
            this.name = in.readUTF();
            //this.password = in.readUTF(); // java.io.EOFException
        }
    }
  • Nur Objekte, die die Schnittstelle java.io.Serializable oder java.io.Externalizable unterstützen, können written to/read from Streams sein. Die Klasse jedes serialisierbaren Objekts wird codiert, einschließlich des Klassennamens und der Signatur der Klasse, der Werte der Felder und Arrays des Objekts und des Schließens aller anderen Objekte, auf die von den ursprünglichen Objekten verwiesen wird.

Serialisierbares Beispiel für Dateien

public class SerializationDemo {
    static String fileName = "D:/serializable_file.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Employee emp = new Employee( );
        Employee.id = 1; // Can not Serialize Class data.
        emp.eno = 77;
        emp.name = "Yash";
        emp.password = "confidential";
        objects_WriteRead(emp, fileName);

        Emp e = new Emp( );
        e.eno = 77;
        e.name = "Yash";
        e.password = "confidential";
        objects_WriteRead_External(e, fileName);

        /*String stubHost = "127.0.0.1";
        Integer anyFreePort = 7777;
        socketRead(anyFreePort); //Thread1
        socketWrite(emp, stubHost, anyFreePort); //Thread2*/

    }
    public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );
        objectOut.writeObject( obj );
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");

        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

            Employee emp = (Employee) readObject;
            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void objects_WriteRead_External( Emp 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.
            Emp emp = new Emp();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            emp.readExternal(ois);

            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Serialisierbares Beispiel über Netzwerk

Objekt verteilen auf verschiedene Adressräume, entweder in verschiedenen Prozessen auf demselben Computer oder sogar auf mehreren Computern, die über ein Netzwerk verbunden sind, aber zusammenarbeiten, indem Daten gemeinsam genutzt und Methoden aufgerufen werden.

/**
 * Creates a stream socket and connects it to the specified port number on the named host. 
 */
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
    try { // CLIENT - Stub[marshalling]
        Socket client = new Socket(stubHost, anyFreePort);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(objectToSend);
        out.flush();
        client.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Creates a server socket, bound to the specified port. 
public static void socketRead(  Integer anyFreePort ) {
    try { // SERVER - Stub[unmarshalling ]
        ServerSocket serverSocket = new ServerSocket( anyFreePort );
        System.out.println("Server serves on port and waiting for a client to communicate");
            /*System.in.read();
            System.in.read();*/

        Socket socket = serverSocket.accept();
        System.out.println("Client request to communicate on port server accepts it.");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        Employee objectReceived = (Employee) in.readObject();
        System.out.println("Server Obj : "+ objectReceived.name );

        socket.close();
        serverSocket.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@sehen

Yash
quelle
1
Wenn Sie eine Antwort auf eine sechs Jahre alte Frage hinzufügen, die bereits mehrere sehr gute Antworten enthält, müssen Sie viel besser abschneiden als eine Kakophonie von Rechtschreibfehlern.
Marquis von Lorne
@ejp Downvoting ist das Werkzeug, um Ihre negative Meinung zu äußern. Beleidigend und grenzwertig unhöflich zu sein, ist inakzeptabel.
Konstantinos Chertouras
1
@KonstantinosChertouras Die Angabe von Gründen für die Ablehnung ist hilfreich für das Poster, und das sind meine Gründe, ob sie Ihnen gefallen oder nicht, wie Sie wollen.
Marquis von Lorne
Sie müssen auch Fehler vermeiden, z. B. die Behauptung, dass die Serialisierung einen Sicherheitszweck hat. Das tut es nicht.
Marquis von Lorne
@EJP Ich habe meinen Beitrag aktualisiert und korrigiert, dass die Serialisierung nicht aus Sicherheitsgründen erfolgt. Sie wird jedoch verwendet, um den Status eines Objekts in einen beliebigen Speicher umzuwandeln und den ursprünglichen Status eines Objekts mithilfe von SUID durch Deserialisierungsmechanismen wiederherzustellen. JVM to JVM
Yash
3

Bei der Serialisierung wird ein Objekt auf einem Speichermedium (z. B. einer Datei oder einem Speicherpuffer) gespeichert oder über eine Netzwerkverbindung in binärer Form übertragen. Die serialisierten Objekte sind JVM-unabhängig und können von jeder JVM erneut serialisiert werden. In diesem Fall wird der Java-Objektstatus "im Speicher" in einen Bytestream konvertiert. Dieser Dateityp kann vom Benutzer nicht verstanden werden. Es handelt sich um einen speziellen Objekttyp, der von der JVM (Java Virtual Machine) wiederverwendet wird. Dieser Prozess des Serialisierens eines Objekts wird auch als Entleeren oder Marshalling eines Objekts bezeichnet.

Das zu serialisierende Objekt muss die java.io.SerializableSchnittstelle implementieren . Der Standard-Serialisierungsmechanismus für ein Objekt schreibt die Klasse des Objekts, die Klassensignatur und die Werte aller nicht transienten und nicht statischen Felder.

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

ObjectOutputinterface erweitert die DataOutputSchnittstelle und fügt Methoden zum Serialisieren von Objekten und Schreiben von Bytes in die Datei hinzu. Die ObjectOutputStreamerweitert java.io.OutputStreamund implementiert die ObjectOutput Schnittstelle. Es serialisiert Objekte, Arrays und andere Werte in einen Stream. Der Konstruktor von ObjectOutputStreamlautet also wie folgt:

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

Der obige Code wurde verwendet, um die Instanz der ObjectOutputKlasse mit dem ObjectOutputStream( )Konstruktor zu erstellen, der die Instanz von FileOuputStreamals Parameter verwendet.

Die ObjectOutputSchnittstelle wird durch Implementieren der ObjectOutputStreamKlasse verwendet. Das ObjectOutputStreamist so konstruiert, dass es das Objekt serialisiert.

Deserialisieren eines Objekts in Java

Die entgegengesetzte Operation der Serialisierung wird als Deserialisierung bezeichnet, dh das Extrahieren der Daten aus einer Reihe von Bytes wird als Deserialisierung bezeichnet, die auch als Aufblasen oder Entmarshalling bezeichnet wird.

ObjectInputStreamerweitert java.io.InputStreamund implementiert die ObjectInput Schnittstelle. Es deserialisiert Objekte, Arrays und andere Werte aus einem Eingabestream. Der Konstruktor von ObjectInputStreamlautet also wie folgt:

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

Der obige Code des Programms erstellt die Instanz der ObjectInputStreamKlasse, um die von der ObjectInputStreamKlasse serialisierte Datei zu deserialisieren . Der obige Code erstellt die Instanz unter Verwendung der Instanz der FileInputStreamKlasse, die das angegebene Dateiobjekt enthält, das deserialisiert werden muss, da der ObjectInputStream()Konstruktor den Eingabestream benötigt.

Sindu
quelle
2

Bei der Serialisierung wird ein Java-Objekt in ein Byte-Array und dann wieder in ein Objekt mit seinem beibehaltenen Status umgewandelt. Nützlich für verschiedene Dinge wie das Senden von Objekten über das Netzwerk oder das Zwischenspeichern von Dingen auf die Festplatte.

Lesen Sie mehr aus diesem kurzen Artikel, in dem die Programmierung eines Teils des Prozesses recht gut erklärt wird, und wechseln Sie dann zu Serializable javadoc . Möglicherweise möchten Sie auch diese verwandte Frage lesen .

Esko
quelle
2

Geben Sie die Datei als Objekt zurück: http://www.tutorialspoint.com/java/java_serialization.htm

        import java.io.*;

        public class SerializeDemo
        {
           public static void main(String [] args)
           {
              Employee e = new Employee();
              e.name = "Reyan Ali";
              e.address = "Phokka Kuan, Ambehta Peer";
              e.SSN = 11122333;
              e.number = 101;

              try
              {
                 FileOutputStream fileOut =
                 new FileOutputStream("/tmp/employee.ser");
                 ObjectOutputStream out = new ObjectOutputStream(fileOut);
                 out.writeObject(e);
                 out.close();
                 fileOut.close();
                 System.out.printf("Serialized data is saved in /tmp/employee.ser");
              }catch(IOException i)
              {
                  i.printStackTrace();
              }
           }
        }

    import java.io.*;
    public class DeserializeDemo
    {
       public static void main(String [] args)
       {
          Employee e = null;
          try
          {
             FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (Employee) in.readObject();
             in.close();
             fileIn.close();
          }catch(IOException i)
          {
             i.printStackTrace();
             return;
          }catch(ClassNotFoundException c)
          {
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
          }
          System.out.println("Deserialized Employee...");
          System.out.println("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
        }
    }
Ran Adler
quelle
Dies beantwortet nicht die Teile der Frage "Was ist" oder "Bitte erklären".
Marquis von Lorne
1

| * | Serialisieren einer Klasse: Konvertieren eines Objekts in Bytes und Bytes zurück in ein Objekt (Deserialisierung).

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

| => Objekt-Serialisierung ist ein Prozess zum Konvertieren des Status eines Objekts in Dampf von Bytes.

  • | -> Implementieren, wenn das Objekt über die Lebensdauer der JVM hinaus existieren soll.
  • | -> Serialisiertes Objekt kann in der Datenbank gespeichert werden.
  • | -> Serialisierbare Objekte können von Menschen nicht gelesen und verstanden werden, damit wir Sicherheit erreichen können.

| => Objekt-Deserialisierung ist der Prozess, bei dem der Status eines Objekts abgerufen und in einem Objekt (java.lang.Object) gespeichert wird.

  • | -> Vor dem Speichern des Status wird überprüft, ob die serialVersionUID aus der Eingabedatei / dem Netzwerk und die .class-Datei serialVersionUID identisch sind.
    & nbsp & nbspWenn nicht java.io.InvalidClassException ausgelöst wird.

| => Ein Java-Objekt ist nur dann serialisierbar, wenn seine Klasse oder eine seiner Oberklassen

  • implementiert entweder die Schnittstelle java.io.Serializable oder
  • seine Subschnittstelle, java.io.Externalizable.

| => Statische Felder in einer Klasse können nicht serialisiert werden.

class NamCls implements Serializable
{
    int NumVar;
    static String NamVar = "I won't be serializable";;
}

| => Wenn Sie eine Variable einer Klasse nicht serialisieren möchten, verwenden Sie das Schlüsselwort transient

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

| => Wenn eine Klasse serialisierbar implementiert, sind auch alle ihre Unterklassen serialisierbar.

| => Wenn eine Klasse eine Referenz einer anderen Klasse hat, müssen alle Referenzen serialisierbar sein, da sonst kein Serialisierungsprozess durchgeführt wird. In diesem Fall wird
NotSerializableException zur Laufzeit ausgelöst.

Sujay UN
quelle
0

Ich werde eine Analogie anbieten, die möglicherweise dazu beiträgt, den konzeptionellen Zweck / die Praktikabilität der Objektserialisierung / -deserialisierung zu festigen .

Ich stelle mir die Serialisierung / Deserialisierung von Objekten im Zusammenhang mit dem Versuch vor, ein Objekt durch einen Sturmabfluss zu bewegen. Das Objekt wird im Wesentlichen "zerlegt" oder in modularere Versionen von sich selbst - in diesem Fall eine Reihe von Bytes - serialisiert , um effektiv den Durchgang durch ein Medium zu erhalten. In rechnerischer Hinsicht könnten wir den Pfad, den die Bytes durch den Sturmabfluss zurücklegen, als ähnlich wie Bytes betrachten, die sich durch ein Netzwerk bewegen. Wir wandeln unser Objekt um, um es einem wünschenswerteren Transportmittel oder Format anzupassen. Das serialisierte Objekt wird normalerweise in einer Binärdatei gespeichert, aus der später gelesen, geschrieben oder beides geschrieben werden kann.

Sobald unser Objekt in der Lage ist, als zerlegte Folge von Bytes durch den Drain zu rutschen, möchten wir diese Darstellung des Objekts möglicherweise als Binärdaten in einer Datenbank oder einem Festplattenlaufwerk speichern. Der wichtigste Aspekt ist jedoch, dass wir bei der Serialisierung / Deserialisierung die Option haben, unser Objekt nach der Serialisierung in seiner binären Form zu belassen oder die ursprüngliche Form des Objekts durch Deserialisierung "abzurufen".

Benjamin Westburg
quelle