Java-Serialisierung und -Deserialisierung

JavaJavaBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

Serialisierung und Deserialisierung sind wichtige Prozesse in Java, die uns ermöglichen, ein Objekt in einen Byte-Strom umzuwandeln und es anschließend wieder in ein Objekt zurückherzustellen. Wir können Serialisierung und Deserialisierung verwenden, um den Zustand von Objekten zu speichern oder zu persistieren, oder um Objekte über ein Netzwerk zu übertragen. In diesem Lab werden wir lernen, wie man in Java Objekte mit den Klassen ObjectInputStream und ObjectOutputStream serialisiert und deserialisieren kann.

Implementieren der Serializable-Schnittstelle

Um unsere Objekte serialisierbar zu machen, müssen wir die Serializable-Schnittstelle implementieren. Dies ist eine Marker-Schnittstelle, die keine Methoden implementieren erfordert. Die Serializable-Schnittstelle wird verwendet, um der JVM anzuzeigen, dass die Objekte dieser Klasse serialisiert werden können.

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private int age;

    // Konstruktor und Getter/Setter-Methoden
}

Objekte zum Serialisieren erstellen

Erstellen Sie einige Objekte der Student-Klasse, die wir in den nächsten Schritten serialisieren werden.

Student student1 = new Student("Alice", 22);
Student student2 = new Student("Bob", 21);

Objekte serialisieren

Um ein Objekt zu serialisieren, müssen wir eine Instanz von ObjectOutputStream erstellen und seine writeObject()-Methode aufrufen, wobei wir das zu serialisierende Objekt als Parameter übergeben. Dies schreibt das Objekt als Byte-Strom in eine Datei, die wir später zur Deserialisierung verwenden können.

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;

public class SerializationDemo {
    public static void main(String[] args) {
        try {
            FileOutputStream fileOut = new FileOutputStream("students.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);

            out.writeObject(student1);
            out.writeObject(student2);

            out.close();
            fileOut.close();

            System.out.println("Serialized data is saved in students.ser file");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Objekte deserialisieren

Um ein Objekt zu deserialisieren, müssen wir eine Instanz von ObjectInputStream erstellen und seine readObject()-Methode aufrufen, um den Byte-Strom aus der Datei zu lesen, die wir zuvor serialisiert haben. Dies wird ein Objekt zurückgeben, das wir dann in unseren ursprünglichen Klassen-Typ umwandeln können.

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;

public class SerializationDemo {
    public static void main(String[] args) {
        try {
            FileInputStream fileIn = new FileInputStream("students.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);

            Student student1 = (Student) in.readObject();
            Student student2 = (Student) in.readObject();

            in.close();
            fileIn.close();

            // Drucken Sie die Studenten
            System.out.println(student1);
            System.out.println(student2);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Umgang mit transienten Feldern

Wenn unsere Klasse Felder hat, die wir nicht serialisieren möchten, können wir sie als transient deklarieren. Transiente Felder werden bei der Serialisierung und Deserialisierung ignoriert. Beispielsweise fügen wir ein transient-Feld zu unserer Student-Klasse hinzu, das wir nicht serialisieren möchten:

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private int age;
    private transient String password;

    //Konstruktor, Getter/Setter-Methoden
}

Anpassen der Serialisierung und Deserialisierung

Wir können auch den Serialisierungs- und Deserialisierungsprozess anpassen, indem wir die writeObject()- und readObject()-Methoden implementieren. Dies kann nützlich sein, wenn wir transienten Feldern gerecht werden möchten oder wenn wir zusätzliche Verarbeitung während der Serialisierung und Deserialisierung durchführen möchten.

private void writeObject(ObjectOutputStream oos) throws IOException {
    // Standard-Serialisierung
    oos.defaultWriteObject();

    // Passwort vor dem Schreiben in die Datei verschlüsseln
    String encryptedPassword = encrypt(password);
    oos.writeObject(encryptedPassword);
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    // Standard-Deserialisierung
    ois.defaultReadObject();

    // Passwort nach dem Lesen aus der Datei entschlüsseln
    String encryptedPassword = (String) ois.readObject();
    password = decrypt(encryptedPassword);
}

Umgang mit der Versionierung

Wenn wir unsere Klasse aktualisieren, indem wir Eigenschaften hinzufügen oder entfernen, ändert sich die Version der Klasse, was zu Fehlern bei der Deserialisierung älterer Objekte führen kann. Wir können die Versionierung behandeln, indem wir das Feld serialVersionUID verwenden, um eine eindeutige Kennung für unsere Klasse anzugeben. Dadurch wird sichergestellt, dass die Serialisierung und Deserialisierung auch dann korrekt funktioniert, wenn die Klassendefinition geändert wird.

import java.io.Serializable;

public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;

    //Konstruktor, Getter/Setter-Methoden
}

Führen Sie den Code aus

Kompilieren Sie die SerializationDemo-Klasse und führen Sie sie im Terminal mit dem folgenden Befehl aus:

$ javac SerializationDemo.java
$ java SerializationDemo

Die Ausgabe sollte die serialisierten Daten und die deserialisierten Objekte anzeigen.

Ändern Sie die Student-Klasse

Aktualisieren Sie die Student-Klasse, indem Sie ein Feld hinzufügen oder entfernen:

public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private String email; // Ein Feld hinzugefügt

    //Konstruktor, Getter/Setter-Methoden
}

Umgang mit der Versionierung mit serialVersionUID

Jetzt, nachdem wir unsere Klasse geändert haben, müssen wir die Versionierung behandeln, indem wir die serialVersionUID aktualisieren. Dadurch wird sichergestellt, dass wir weiterhin Objekte deserialisieren können, die vor der Änderung der Klasse serialisiert wurden.

public class Student implements Serializable {
    private static final long serialVersionUID = 2L;

    private String name;
    private int age;
    private String email; // Ein Feld hinzugefügt

    //Konstruktor, Getter/Setter-Methoden
}

Zusammenfassung

In diesem Lab haben wir gelernt, wie man in Java Objekte mit Hilfe von ObjectInputStream und ObjectOutputStream serialisiert und deserialisieren kann. Wir haben auch gelernt, wie man transiente Felder behandelt, den Prozess der Serialisierung und Deserialisierung anpasst und die Versionierung mit serialVersionUID behandelt. Serialisierung und Deserialisierung sind wichtige Prozesse zum Speichern und Übertragen von Daten in Java, und wir können sie verwenden, um den aktuellen Zustand unserer Objekte zu speichern und später nach Bedarf wiederherzustellen.