Anleitung zur externisierbaren Oberfläche in Java

1. Einleitung

In diesem Tutorial werfen wir einen kurzen Blick auf die java.io.Externalizable- Oberfläche von Java . Das Hauptziel dieser Schnittstelle besteht darin, die benutzerdefinierte Serialisierung und Deserialisierung zu erleichtern.

Bevor wir fortfahren, lesen Sie unbedingt die Serialisierung im Java-Artikel. Im nächsten Kapitel erfahren Sie, wie Sie ein Java-Objekt mit dieser Schnittstelle serialisieren.

Danach werden wir die wichtigsten Unterschiede zur java.io.Serializable- Schnittstelle diskutieren .

2. Die externisierbare Schnittstelle

Externalizable erstreckt sich über die Schnittstelle java.io.Serializable Marker. Jede Klasse , die implementiert Externalizable Schnittstelle soll die außer Kraft setzen writeExternal () , readExternal () Methoden . Auf diese Weise können wir das Standard-Serialisierungsverhalten der JVM ändern.

2.1. Serialisierung

Schauen wir uns dieses einfache Beispiel an:

public class Country implements Externalizable { private static final long serialVersionUID = 1L; private String name; private int code; // getters, setters @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); out.writeInt(code); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.name = in.readUTF(); this.code = in.readInt(); } }

Hier haben wir eine Klasse Country definiert , die die Externalizable- Schnittstelle und die beiden oben genannten Methoden implementiert.

In der writeExternal () -Methode fügen wir dem ObjectOutput- Stream die Eigenschaften des Objekts hinzu . Dies hat Standardmethoden wie writeUTF () für String und writeInt () für die int-Werte.

Als Nächstes lesen wir zum Deserialisieren des Objekts aus dem ObjectInput- Stream mit den Methoden readUTF (), readInt () , um die Eigenschaften in derselben Reihenfolge zu lesen, in der sie geschrieben wurden.

Es wird empfohlen , die serialVersionUID manuell hinzuzufügen . Wenn dies nicht vorhanden ist, fügt die JVM automatisch eine hinzu.

Die automatisch generierte Nummer ist vom Compiler abhängig. Dies bedeutet, dass dies eine unwahrscheinliche InvalidClassException verursachen kann .

Testen wir das oben implementierte Verhalten:

@Test public void whenSerializing_thenUseExternalizable() throws IOException, ClassNotFoundException { Country c = new Country(); c.setCode(374); c.setName("Armenia"); FileOutputStream fileOutputStream = new FileOutputStream(OUTPUT_FILE); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); c.writeExternal(objectOutputStream); objectOutputStream.flush(); objectOutputStream.close(); fileOutputStream.close(); FileInputStream fileInputStream = new FileInputStream(OUTPUT_FILE); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Country c2 = new Country(); c2.readExternal(objectInputStream); objectInputStream.close(); fileInputStream.close(); assertTrue(c2.getCode() == c.getCode()); assertTrue(c2.getName().equals(c.getName())); }

In diesem Beispiel erstellen wir zuerst ein Country- Objekt und schreiben es in eine Datei. Anschließend deserialisieren wir das Objekt aus der Datei und überprüfen, ob die Werte korrekt sind.

Die Ausgabe des gedruckten c2- Objekts:

Country{name='Armenia', code=374}

Dies zeigt, dass wir das Objekt erfolgreich deserialisiert haben.

2.2. Erbe

Wenn eine Klasse von der Schnittstelle Serializable erbt , sammelt die JVM automatisch auch alle Felder von Unterklassen und macht sie serialisierbar.

Denken Sie daran, dass wir dies auch auf Externalizable anwenden können . Wir müssen nur die Lese- / Schreibmethoden für jede Unterklasse der Vererbungshierarchie implementieren.

Schauen wir uns die Region- Klasse an, die unsere Country- Klasse aus dem vorherigen Abschnitt erweitert:

public class Region extends Country implements Externalizable { private static final long serialVersionUID = 1L; private String climate; private Double population; // getters, setters @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeUTF(climate); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); this.climate = in.readUTF(); } }

Hier haben wir zwei zusätzliche Eigenschaften hinzugefügt und die erste serialisiert.

Beachten Sie, dass wir innerhalb der Serializer-Methoden auch super.writeExternal (out), super.readExternal (in) aufgerufen haben, um auch die übergeordneten Klassenfelder zu speichern / wiederherzustellen .

Lassen Sie uns den Komponententest mit den folgenden Daten ausführen:

Region r = new Region(); r.setCode(374); r.setName("Armenia"); r.setClimate("Mediterranean"); r.setPopulation(120.000);

Hier ist das deserialisierte Objekt:

Region{ country="Country{ name="Armenia', code=374}' climate="Mediterranean", population=null }

Beachten Sie, dass der Wert dieser Eigenschaft null ist , da wir das Populationsfeld in der Region- Klasse nicht serialisiert haben .

3. Externalisierbar vs Serialisierbar

Lassen Sie uns die wichtigsten Unterschiede zwischen den beiden Schnittstellen durchgehen:

  • Serialisierungsverantwortung

Der Hauptunterschied besteht darin, wie wir mit dem Serialisierungsprozess umgehen. Wenn eine Klasse die Schnittstelle java.io.Serializable implementiert, übernimmt die JVM die volle Verantwortung für die Serialisierung der Klasseninstanz. Im Falle von Externalizable ist es der Programmierer, der sich um den gesamten Serialisierungs- und Deserialisierungsprozess kümmert.

  • Anwendungsfall

Wenn wir das gesamte Objekt serialisieren müssen , passt die serialisierbare Schnittstelle besser. Auf der anderen Seite können wir für die benutzerdefinierte Serialisierung den Prozess mithilfe von Externalizable steuern .

  • Performance

Die Schnittstelle java.io.Serializable verwendet Reflektion und Metadaten, was zu einer relativ langsamen Leistung führt. Im Vergleich dazu gibt Ihnen die Externalizable- Schnittstelle die volle Kontrolle über den Serialisierungsprozess.

  • Lesereihenfolge

Bei Verwendung von Externalizable müssen alle Feldzustände in der genauen Reihenfolge gelesen werden, in der sie geschrieben wurden. Andernfalls erhalten wir eine Ausnahme.

Zum Beispiel, wenn wir die Lesereihenfolge der Änderung Code und Namen Eigenschaften in der Land - Klasse, ein java.io.EOFException wird geworfen.

In der Zwischenzeit hat die serialisierbare Schnittstelle diese Anforderung nicht.

  • Benutzerdefinierte Serialisierung

Wir können eine benutzerdefinierte Serialisierung mit der Serializable- Schnittstelle erreichen, indem wir das Feld mit einem vorübergehenden Schlüsselwort markieren . Die JVM serialisiert das bestimmte Feld nicht, addiert es jedoch zum Dateispeicher mit dem Standardwert . Aus diesem Grund empfiehlt es sich, bei benutzerdefinierter Serialisierung Externalizable zu verwenden .

4. Fazit

In dieser kurzen Anleitung zur externisierbaren Benutzeroberfläche haben wir die wichtigsten Funktionen, Vorteile und Beispiele für die einfache Verwendung erläutert. Wir haben auch einen Vergleich mit der Serializable- Schnittstelle durchgeführt.

Wie üblich ist der vollständige Quellcode des Tutorials auf GitHub verfügbar.