Der Artikel beinhaltet hauptsächlich die folgenden Themen:
1. Serialisierung von Java -Objekten
Die Java -Plattform ermöglicht es uns, wiederverwendbare Java -Objekte im Speicher zu erstellen, aber im Allgemeinen können diese Objekte nur dann existieren, wenn der JVM ausgeführt wird, d. H. Der Lebenszyklus dieser Objekte ist nicht länger als die des JVM. In realen Anwendungen kann es jedoch erforderlich sein, das angegebene Objekt zu speichern (bestehen), nachdem der JVM gestoppt wurde, und das gespeicherte Objekt in Zukunft erneut zu lesen. Die Serialisierung von Java -Objekten kann uns helfen, diese Funktion zu implementieren.
Mithilfe der Serialisierung von Java -Objekten wird beim Speichern eines Objekts sein Zustand als eine Reihe von Bytes gespeichert, und in Zukunft werden diese Bytes in ein Objekt zusammengestellt. Es muss angemerkt werden, dass die Objektserialisierung den "Zustand" des Objekts, dh seine Mitgliedsvariablen, rettet. Daraus können wir sehen, dass die Objekt -Serialisierung nicht auf statische Variablen in der Klasse liegt.
Zusätzlich zur Verwendung der Objekt -Serialisierung bei fortdauernden Objekten wird die Objekt -Serialisierung verwendet, wenn RMI (Remote -Methode -Aufruf) oder die Übergabe von Objekten im Netzwerk verwendet wird. Die Java -Serialisierungs -API bietet einen Standardmechanismus für die Serialisierung der Objekte. Diese API ist einfach und einfach zu bedienen und wird in den folgenden Kapiteln dieses Artikels diskutiert.
Public Class ArrayList <E> erweitert AbstractList <E> implementiert die Liste <E>, RandomAccess, klonbar, java.io.serializable {private statische endgültige lange Serialversionuid = 8683452581122892189l; transientes Objekt [] elementData; // nicht privat, um verschachtelte Klassenzugriff privat int zu vereinfachen;}2. wie man Java -Objekte serialisieren und deserialisiert
In Java kann eine Klasse, solange eine Klasse die Schnittstelle von Java.io.Serializable implementiert, serialisiert werden. Hier ist ein Stück Code:
Code 1 Erstellen Sie eine Benutzerklasse für Serialisierung und Deserialisierung
Paket com.hollis; import java.io.serializable; import Java.util.date;/*** Erstellt von Hollis am 16.02.2. */Public Class User implementiert serialisierbar {private Zeichenfolge Name; privates int Alter; Privatdatum Geburtstag; privates transientes String -Geschlecht; Private statische letzte lange Serialversionuid = -6849794470754667710L; public String getName () {return name; } public void setName (String -Name) {this.name = name; } public int getage () {return ay; } public void setage (int age) {this.age = älter; } public date getBirthday () {Return Birthday; } public void setBirthday (Datum Geburtstag) {this.birthday = Geburtstag; } public String getGerTer () {Return Gender; } public void setGender (String -Geschlecht) {this.gender = Gender; } @Override public String toString () {return "user {" + "name = '" + name +'/'' + ", ay" + aget + ", gender =" + gender + ", birthday =" + birthday + '}'; }}Code 2 Demo zum Serialisieren und Deserialisieren des Benutzers
Paket com.hollis; import org.apache.commons.io.fileutils; import org.apache.commons.io.ioutils; import Java.io. */public class Serializabledemo {public static void main (String [] args) {// initialisiert das Objekt user user = new user (); user.setName ("hollis"); user.setGender ("männlich"); user.Setage (23); user.setBirthday (neues Datum ()); System.out.println (Benutzer); // obj in Datei ObjectOutputStream OOS = NULL schreiben; try {OOS = new ObjectOutputStream (new FileOutputStream ("tempfile")); OOS.WriteObject (Benutzer); } catch (ioException e) {e.printstacktrace (); } endlich {ioutils.closequiet (OOS); } // OBJ aus Dateidatei lesen = neue Datei ("tempfile"); ObjectInputStream ois = null; try {ois = new ObjectInputStream (neuer FileInputStream (Datei)); User newUser = (user) ois.readObject (); System.out.println (Newuser); } catch (ioException e) {e.printstacktrace (); } catch (classNotFoundException e) {e.printstacktrace (); } endlich {ioutils.closequiet (ois); try {FileUtils.forcedelete (Datei); } catch (ioException e) {e.printstacktrace (); }}}}} // output // user {name = 'hollis', ay 23, gender = männlich, birthday = due 02 17:37:38 CST 2016} // Benutzer {name = 'hollis', Age = 23, Gender = Null, Geburtstag = TUE FEB 02 17:37:38}3.. Wissen im Zusammenhang mit Serialisierung und Deserialisierung
1. In Java kann eine Klasse die Schnittstelle von Java.io.Serializable implementiert, sie kann serialisiert werden.
2.. Objekte durch ObjektOutputStream und ObjectInputStream serialisieren und deserialisieren.
3. Ob die virtuelle Maschine die Deserialisierung ermöglicht, hängt nicht nur davon ab, ob der Klassenpfad und der Funktionscode konsistent sind. Ein sehr wichtiger Punkt ist, ob die Serialisierungs -IDs der beiden Klassen konsistent sind (dh private statische endgültige lange Serialversionuid)
4. Die Serialisierung speichert keine statischen Variablen.
5. Um das Objekt der übergeordneten Klassen zu serialisieren, müssen Sie die übergeordnete Klasse die serialisierbare Schnittstelle implementieren.
6. Die Funktion des transienten Schlüsselworts besteht darin, die Serialisierung von Variablen zu steuern. Durch das Hinzufügen dieses Schlüsselworts vor der Variablenerklärung kann verhindern, dass die Variable in die Datei serialisiert wird. Nach der Deserialisierung wird der Wert der transienten Variablen auf den Anfangswert festgelegt, z. B. der Int -Typ ist 0 und der Objekttyp ist null.
7. Der Server sendet serialisierte Objektdaten an den Client. Einige Daten im Objekt sind sensibel, z. B. Kennwortzeichenfolgen usw. Es ist zu hoffen, dass das Kennwortfeld beim Serialisierungskennwort verschlüsselt wird. Wenn der Kunde über einen entschlüsselten Schlüssel verfügt, kann er das Kennwort nur bei der Deserialisierung des Clients lesen, was die Datensicherheit des serialisierten Objekts bis zu einem gewissen Grad sicherstellen kann.
4. Serialisierung der ArrayList
Bevor Sie die Serialisierung der ArrayList einführen, sollten wir uns eine Frage in Betracht ziehen:
Wie man Serialisierungs- und Deserialisierungsstrategien anpassen
Schauen wir uns mit dieser Frage den Quellcode von Java.util.ArrayList an
Code 3
Public Class ArrayList <E> erweitert AbstractList <E> implementiert die Liste <E>, RandomAccess, klonbar, java.io.serializable {private statische endgültige lange Serialversionuid = 8683452581122892189l; transientes Objekt [] elementData; // nicht privat, um verschachtelte Klassenzugriff privat int zu vereinfachen;}Der Autor lässt andere Mitgliedsvariablen aus. Aus dem obigen Code können wir wissen, dass ArrayList die Schnittstelle java.io.serializable implementiert, sodass wir sie serialisieren und deserialisieren können. Da ElementData vorübergehend ist, glauben wir, dass diese Mitgliedsvariable nicht serialisiert und beibehalten wird. Schreiben wir eine Demo, um unsere Ideen zu überprüfen:
Code 4
public static void main (string [] args) löst IOException, classNotFoundException {list <string> stringlist = new ArrayList <string> () aus; StringList.add ("Hallo"); StringList.add ("Welt"); StringList.add ("Hollis"); StringList.add ("Chuang"); System.out.println ("init StringList" + StringList); ObjectOutputStream ObjectOutputStream = new ObjectOutputStream (new FileOutputStream ("StringList")); ObjectOutputStream.writeObject (StringList); Ioutils.close (ObjectOutputStream); Datei Datei = new Datei ("StringList"); ObjectInputStream ObjectInputStream = new ObjectInputStream (new FileInputStream (Datei)); List <String> NewStringList = (List <string>) ObjectInputStream.ReadObject (); Ioutils.close (ObjectInputStream); if (file.exists ()) {file.delete (); } System.out.println ("New StringList" + NewStringList); } // init StringList [Hallo, Welt, Hollis, Chang] // Neue StringList [Hallo, Welt, Hollis, Chang]Jeder, der arrayList kennt, weiß, dass die zugrunde liegende Ebene der ArrayList über Arrays implementiert wird. Dann wird das Array ElementData tatsächlich verwendet, um Elemente in der Liste zu speichern. Durch die Deklarationsmethode dieses Attributs wissen wir, dass es durch Serialisierung nicht bestehen kann. Warum behält das Ergebnis von Code 4 die Elemente in der Liste durch Serialisierung und Deserialisierung bei?
5. Methoden writeObject und readObject
In ArrayList wird eine Methode definiert: writeObject und readObject.
Hier ist eine Schlussfolgerung:
Während des Serialisierungsprozesses versucht die virtuelle Maschine während des Serialisierungsprozesses, wenn die Methoden "WriteObject" und "ReadObject in der serialisierten Klasse" definiert sind, um die Methoden "WriteObject" und "ReadObject" in der Objektklasse zu rufen, um die benutzerdefinierte Serialisierung und Deserialisierung durchzuführen.
Wenn es keine solche Methode gibt, sind die Standardaufrufe die StandardwriteObject -Methode von ObjectOutputStream und die DefaultreadObject -Methode von ObjectInputStream.
Benutzerdefinierte WriteObject- und ReadObject-Methoden können es Benutzern ermöglichen, den Serialisierungsprozess zu steuern, z. B. dynamisch den serialisierten Wert während des Serialisierungsprozesses.
Schauen wir uns die spezifische Implementierung dieser beiden Methoden an:
Code 5
private void readObject (java.io.objectinputStream s) löst java.io.ioException, classNotFoundException {elementData = leer_elementData aus; // Größe lesen und alle versteckten Sachen s.defaultreadObject (); // in Kapazität lesen s.readint (); // ignoriert if (size> 0) {// wie clone (), das Array basierend auf der Größe, nicht Kapazitäts -SicherungscoapacityInternal (Größe), zuweisen; Objekt [] a = elementData; // In allen Elementen in der richtigen Reihenfolge lesen. für (int i = 0; i <size; i ++) {a [i] = s.ReadObject (); }}}Code 6
private void writeObject (java.io.objectoutputStream s) löst Java.io.ioException {// Elementzahl und alle versteckten Dinge int erwarteteModcount = modcount aus; S.DefaultWriteObject (); // Größe als Kapazität für Verhaltenskompatibilität mit Clone () S.WriteInt (Größe) schreiben; // Schreiben Sie alle Elemente in der richtigen Reihenfolge auf. für (int i = 0; i <size; i ++) {S.WriteObject (elementData [i]); } if (modcount! }}Warum muss ArrayList diese Methode verwenden, um eine Serialisierung zu erreichen?
Warum vorübergehend
ArrayList ist eigentlich ein dynamisches Array. Jedes Mal, wenn es gefüllt ist, erhöht es automatisch den Wert der festgelegten Länge. Wenn die automatische Wachstumslänge des Arrays auf 100 eingestellt ist und tatsächlich nur ein Element platziert ist, werden 99 Nullelemente serialisiert. Um sicherzustellen, dass so viele Nulls während der Serialisierung nicht gleichzeitig serialisiert werden, legt ArrayList das Elementarray auf transient fest.
Warum WriteObject und ReadObject
Wie bereits erwähnt, verwendet ArrayList, um zu verhindern, dass ein Array mit einer großen Anzahl leerer Objekte serialisiert und um den Speicher zu optimieren, vorübergehend ElementData zu deklarieren.
Als Sammlung muss jedoch auch sichergestellt werden, dass die darin enthaltenen Elemente während des Serialisierungsprozesses bestehen können. Daher werden die Elemente darin erhalten, indem die WriteObject- und ReadObject -Methoden neu geschrieben werden.
Die WriteObject -Methode speichert die Elemente im ElementData -Array, das zum Ausgabestream (ObjectOutputStream) führt.
Die ReadObject -Methode liest das Objekt aus dem Eingabestream (ObjectInputStream) und speichert die Zuordnung zum ElementData -Array.
Versuchen wir an diesem Punkt, die gerade gestellte Frage zu beantworten:
1. wie man Serialisierungs- und Deserialisierungsstrategien anpassen
ANTWORT: Sie können der serialisierten Klasse WriteObject- und ReadObject -Methoden hinzufügen. 2. Dann kommt die Frage erneut:
Obwohl die WriteObject- und ReadObject -Methoden in ArrayList geschrieben sind, werden diese beiden Methoden nicht angezeigt und aufgerufen.
Wenn also eine Klasse WriteObject- und ReadObject -Methoden enthält, wie werden diese beiden Methoden dann aufgerufen?
6. ObjectOutputStream
Aus Code 4 können wir feststellen, dass der Serialisierungsprozess von Objekten über ObjectOutputStream und ObjectInputStream implementiert wird. Lassen Sie uns mit der Frage gerade analysieren, wie die Methoden für Schreib- und Read -Objekte in ArrayList aufgerufen werden?
Um Speicherplatz zu sparen, finden Sie hier den Anrufstapel von WriteObject von ObjectOutputStream:
writeObject ---> writeObject0 ---> schriftinaryObject ---> WriteSerialdata ---> InvokeWriteObject
Hier ist ein Blick auf InvokeWriteObject:
void InvokeWriteObject (Object OBJ, ObjectOutputStream Out) löst IOException, nicht unterstützte OperationException {if (writeObjectMethod! } catch (invocationTargetException ex) {throwable th = ex.gettargetException (); if (th Instance von ioException) {throw (ioException) th; } else {throwmiscexception (th); }} catch (illegalAccessException ex) {// sollte nicht auftreten, da zu Zugangsprüfungen unterdrückt wurden, neue InternalError (Ex) werfen; }} else {werfen neu nicht unterstützte OperationException (); }}wo writeObjectMethod.invoke (obj, neues Objekt [] {out}); ist der Schlüssel, und die WriteObjectMethod -Methode wird durch Reflexion aufgerufen. So erklärt der Beamte den WriteObjectMethod:
Klassendefinierte WriteObject-Methode oder null, wenn keine
In unserem Beispiel ist diese Methode die WriteObject -Methode, die wir in ArrayList definieren. Es wurde durch Reflexion gerufen.
Versuchen wir an diesem Punkt, die gerade gestellte Frage zu beantworten:
Wenn eine Klasse WriteObject- und ReadObject -Methoden enthält, wie werden diese beiden Methoden aufgerufen?
Antwort: Bei Verwendung der WriteObject -Methode von ObjectOutputStream und der ReadObject -Methode von ObjectInputStream wird sie in Reflexion aufgerufen.
Bisher haben wir die Serialisierungsmethode von ArrayList eingeführt. Ich frage mich also, ob jemand eine solche Frage aufgeworfen hat:
Serialisierbar ist offensichtlich eine leere Schnittstelle. Wie stellt es sicher, dass nur Methoden, die diese Schnittstelle implementieren, serialisiert und deserialisiert werden können?
Definition der serialisierbaren Schnittstelle:
öffentliche Schnittstelle serialisierbar {}Die Leser können versuchen, den in Code 1 ererbten Code aus serialisierbarem und dann Code 2 auszuführen, der eine Java.io.InotserializableException ausführt.
Tatsächlich ist diese Frage auch leicht zu beantworten. Kehren wir gerade jetzt zum Call -Stapel von WriteObject in ObjectOutputStream zurück:
writeObject ---> writeObject0 ---> schriftinaryObject ---> WriteSerialdata ---> InvokeWriteObject
In der WriteObject0 -Methode befindet sich ein Stück Code:
if (obj instanceof string) {writeString ((String) obj, ungeschützt); } else if (cl.isArray ()) {Writearray (obj, desc, ungeschherzt); } else if (obj instanceof enum) {writeNum ((enum <?>) obj, desc, ungeschherzt); } else if (obj instanceof serializable) {schriftinalObject (OBJ, Desc, ungeschherzt); } else {if (extendedDebuginfo) {Neue NotSerializableException (cl.getName () + "/n" + debuginfostack.toString ()); } else {neue NotSerializableException (cl.getName ()); }}Bei der Durchführung von Serialisierungsvorgängen wird festgelegt, ob die zu serialisierte Klasse aus Enum-, Array- und serialisierbaren Typen besteht. Wenn nicht, wird eine NotSerializableException direkt geworfen.
Zusammenfassen
1. Wenn eine Klasse serialisiert werden will, muss sie die serialisierbare Schnittstelle implementieren. Andernfalls wird eine NotSerializableException ausgeworfen, da der Typ während der Serialisierungsoperation überprüft wird, sodass die serialisierte Klasse zu einem der Enum-, Array- und serialisierbaren Typen gehört.
2. Hinzufügen dieses Schlüsselworts vor der Variablenerklärung kann verhindern, dass die Variable in die Datei serialisiert wird.
3. Durch Hinzufügen von WriteObject- und ReadObject -Methoden zur Klasse können benutzerdefinierte Serialisierungsstrategien implementiert werden
Das Obige dreht sich alles um diesen Artikel, ich hoffe, es wird für das Lernen aller hilfreich sein.