Heim >Java >javaLernprogramm >Ausführliche Erläuterung grundlegender Beispiele für die Verwendung der Objektserialisierung im Java-Tutorial
Dieser Prozess kann auch über das Netzwerk implementiert werden. Sie können zunächst ein Objekt auf einem Windows-Computer erstellen, es serialisieren und es dann über das Netzwerk an einen Unix-Computer senden und es dort dann wieder präzise „zusammensetzen“. Einer davon, wie RMI, Socket, JMS und EJB, warum sie Java-Objekte untereinander übertragen können, liegt natürlich am Objektserialisierungsmechanismus.
Der Java-Objektserialisierungsmechanismus hat im Allgemeinen zwei Verwendungszwecke:
Java-Beans: Die Statusinformationen von Bean werden normalerweise zur Entwurfszeit konfiguriert, und die Statusinformationen von Bean müssen gespeichert werden, um diese Statusinformationen wiederherzustellen Wenn das Programm ausgeführt wird, muss der Status des Objekts in einer Datei gespeichert werden. Anschließend kann das Objekt rekonstruiert und der Programmstatus durch Lesen des Objektstatus wiederhergestellt werden.
Mit RMI können Sie Objekte auf einem Remote-Computer so bedienen, als wären sie auf dem lokalen Computer. Für Programme, die Sockets zum Übertragen von Objekten über das Netzwerk verwenden, ist die Implementierung des Serialisierungsmechanismus erforderlich.
Wir können eine Klasse serialisieren, indem wir die Klasse die Java.io.Serializable-Schnittstelle implementieren lassen. Bei dieser Schnittstelle handelt es sich um eine Marker-Schnittstelle. Das heißt, die Schnittstelle muss keine Methoden implementieren, damit die Klasse sie implementieren kann. Es wird hauptsächlich verwendet, um der Java Virtual Machine (JVM) mitzuteilen, dass ein Objekt serialisiert werden muss.
Dazu müssen wir uns über einige Dinge im Klaren sein:
Nicht alle Klassen können serialisiert werden. Unter cmd geben wir serialver Java.net.Socket ein, um zu erfahren, ob der Socket vorhanden ist Informationen können serialisiert werden. Tatsächlich ist der Socket nicht serialisierbar.
Java verfügt über viele Basisklassen, die die serialisierbare Schnittstelle implementiert haben, z. B. String, Vektor usw. Hashtable implementiert jedoch beispielsweise nicht die serialisierbare Schnittstelle.
Es gibt zwei Hauptklassen zum Lesen oder Schreiben von Objekten in Streams: ObjectOutputStream und ObjectInputStream. ObjectOutputStream stellt die writeObject-Methode zum Schreiben von Objekten in den Ausgabestream bereit, und ObjectInputStream stellt die readObject-Methode zum Lesen von Objekten aus dem Eingabestream bereit. Objekte, die diese Methoden verwenden, müssen bereits serialisiert sein. Das heißt, die Serializable-Schnittstelle muss implementiert sein. Wenn Sie writeobject ein Hashtabellenobjekt schreiben möchten, erhalten Sie eine Ausnahme.
Der Prozess der Serialisierung besteht darin, Objekte in den Bytestream zu schreiben und Objekte aus dem Bytestream zu lesen. Nachdem Sie den Objektstatus in einen Bytestream konvertiert haben, können Sie verschiedene Bytestreamklassen im Java.io-Paket verwenden, um ihn in einer Datei zu speichern, ihn an einen anderen Thread weiterzuleiten oder die Objektdaten über eine Netzwerkverbindung an einen anderen Host zu senden. Die Objektserialisierungsfunktion ist sehr einfach und leistungsstark und kann in RMI, Socket, JMS und EJB eingesetzt werden. Das Problem der Objektserialisierung ist nicht das spannendste Thema in der Netzwerkprogrammierung, aber es ist durchaus wichtig und hat viele praktische Auswirkungen.
Objektserialisierung kann verteilte Objekte implementieren. Zu den Hauptanwendungen gehören: RMI nutzt die Objektserialisierung, um Dienste auf dem Remote-Host auszuführen, genau wie beim Ausführen von Objekten auf dem lokalen Computer.
Die Java-Objektserialisierung behält nicht nur die Daten eines Objekts bei, sondern speichert auch rekursiv die Daten jedes Objekts, auf das das Objekt verweist. Die gesamte Objekthierarchie kann in einen Bytestream geschrieben werden, der in einer Datei gespeichert oder über eine Netzwerkverbindung übertragen werden kann. Die Objektserialisierung kann verwendet werden, um eine „tiefe Kopie“ des Objekts durchzuführen, d. h. das Objekt selbst und das referenzierte Objekt selbst zu kopieren. Durch die Serialisierung eines Objekts kann die gesamte Objektsequenz entstehen.
Die Java-Serialisierung ist relativ einfach und erfordert normalerweise kein Schreiben von benutzerdefiniertem Code zum Speichern und Wiederherstellen des Objektstatus. Klassenobjekte, die die Java.io.Serializable-Schnittstelle implementieren, können in einen Bytestream konvertiert oder aus einem Bytestream wiederhergestellt werden, ohne der Klasse Code hinzuzufügen. Nur in seltenen Fällen ist benutzerdefinierter Code erforderlich, um den Objektstatus zu speichern oder wiederherzustellen. Beachten Sie hier: Nicht jede Klasse kann serialisiert werden und einige Klassen können beispielsweise nicht serialisiert werden. Klassen mit Threads haben beispielsweise eine sehr komplexe Beziehung zu einer bestimmten JVM.
Serialisierungsmechanismus:
Serialisierung ist in zwei Teile unterteilt: Serialisierung und Deserialisierung. Die Serialisierung ist der erste Teil des Prozesses, bei dem die Daten in einen Bytestrom aufgeteilt werden, sodass sie in einer Datei gespeichert oder über das Netzwerk übertragen werden können. Bei der Deserialisierung geht es darum, den Bytestrom zu öffnen und das Objekt zu rekonstruieren. Die Objektserialisierung wandelt nicht nur grundlegende Datentypen in Bytedarstellungen um, sondern stellt manchmal auch die Daten wieder her. Für die Wiederherstellung von Daten ist eine Objektinstanz der wiederhergestellten Daten erforderlich. Der Serialisierungsprozess in ObjectOutputStream ist mit dem Bytestream verbunden, einschließlich Objekttyp- und Versionsinformationen. Beim Deserialisieren verwendet die JVM die Header-Informationen, um eine Objektinstanz zu generieren, und kopiert dann die Daten im Objektbyte-Stream in die Objektdatenelemente. Im Folgenden erklären wir es in zwei Teilen:
Verarbeitung von Objektströmen: (Serialisierungsprozess und Deserialisierungsprozess)
Das Java.io-Paket verfügt über zwei Klassen zum Serialisieren von Objekten. ObjectOutputStream ist für das Schreiben von Objekten in Bytestreams verantwortlich, und ObjectInputStream rekonstruiert Objekte aus Bytestreams.
Lassen Sie uns zunächst die ObjectOutputStream-Klasse verstehen. Die ObjectOutputStream-Klasse erweitert die DataOutput-Schnittstelle.
Die Methode writeObject() ist die wichtigste Methode und wird für die Objektserialisierung verwendet. Wenn das Objekt Verweise auf andere Objekte enthält, serialisiert die Methode writeObject() diese Objekte rekursiv. Jeder ObjectOutputStream verwaltet eine serialisierte Objektreferenztabelle, um das Senden mehrerer Kopien desselben Objekts zu verhindern. (Dies ist wichtig) Da writeObject() einen gesamten Satz von Objekten mit Querverweisen serialisieren kann, kann es sein, dass dieselbe ObjectOutputStream-Instanz versehentlich aufgefordert wird, dasselbe Objekt zu serialisieren. Zu diesem Zeitpunkt wird eine Dereferenzierungsserialisierung durchgeführt, anstatt den Objektbyte-Stream erneut zu schreiben.
Lassen Sie uns nun anhand eines Beispiels etwas über die ObjectOutputStream-Klasse lernen.
// 序列化 today's date 到一个文件中. FileOutputStream f = new FileOutputStream ("tmp" ); ObjectOutputStream s = new ObjectOutputStream (f); s.writeObject("Today" ); s.writeObject(new Date ()); s.flush();
Lassen Sie uns nun die ObjectInputStream-Klasse verstehen. Es ähnelt ObjectOutputStream. Es erweitert die DataInput-Schnittstelle. Die Methoden in ObjectInputStream spiegeln die öffentlichen Methoden in DataInputStream zum Lesen von Java-Basisdatentypen wider. Die Methode readObject() deserialisiert ein Objekt aus einem Bytestream. Bei jedem Aufruf der readObject()-Methode wird das nächste Objekt im Stream zurückgegeben. Der Objektbytestream überträgt nicht den Bytecode der Klasse, sondern enthält den Klassennamen und seine Signatur. Wenn readObject() das Objekt empfängt, lädt die JVM die im Header angegebene Klasse. Wenn diese Klasse nicht gefunden wird, löst readObject() eine ClassNotFoundException aus. Wenn Sie Objektdaten und Bytecode übertragen müssen, können Sie das RMI-Framework verwenden. Die verbleibenden Methoden von ObjectInputStream werden zum Anpassen des Deserialisierungsprozesses verwendet.
Ein Beispiel ist wie folgt:
//从文件中反序列化 string 对象和 date 对象 FileInputStream in = new FileInputStream ("tmp" ); ObjectInputStream s = new ObjectInputStream (in); String today = (String )s.readObject(); Date date = (Date )s.readObject();Anpassen des Serialisierungsprozesses:
Beispiel: Eine sehr einfache Serialisierungsklasse.
public class simpleSerializableClass implements Serializable { String sToday="Today:" ; transient Date dtToday=new Date (); }
Beim Serialisieren sollten alle Datenmitglieder der Klasse serialisierbar sein, mit Ausnahme der als transient oder statisch deklarierten Mitglieder. Durch die Deklaration einer Variablen als transient wird der JVM mitgeteilt, dass wir für die Serialisierung der Variablen verantwortlich sind. Nachdem ein Datenelement als transient deklariert wurde, kann der Serialisierungsprozess es nicht zum Objektbyte-Stream hinzufügen. Es werden keine Daten vom transienten Datenelement gesendet. Wenn die Daten später deserialisiert werden, muss das Datenelement neu erstellt werden (da es Teil der Klassendefinition ist), es enthält jedoch keine Daten, da dieses Datenelement keine Daten in den Stream schreibt. Denken Sie daran, dass Objektströme keine statischen oder transienten Objekte serialisieren. Unsere Klasse verwendet die Methoden writeObject() und readObject(), um diese Datenelemente zu verarbeiten. Wenn Sie die Methoden writeObject() und readObject() verwenden, achten Sie darauf, diese Datenelemente in der Reihenfolge zu lesen, in der sie geschrieben werden.
Ein Teil des Codes zur Verwendung der benutzerdefinierten Serialisierung lautet wie folgt
//重写writeObject()方法以便处理transient的成员。 public void writeObject(ObjectOutputStream outputStream) throws IOException { outputStream.defaultWriteObject();//使定制的writeObject()方法可以 //利用自动序列化中内置的逻辑。 outputStream.writeObject(oSocket.getInetAddress()); outputStream.writeInt(oSocket.getPort()); } //重写readObject()方法以便接收transient的成员。 private void readObject(ObjectInputStream inputStream) throws IOException , ClassNotFoundException { inputStream.defaultReadObject();//defaultReadObject()补充自动序列化 InetAddress oAddress=(InetAddress )inputStream.readObject(); int iPort =inputStream.readInt(); oSocket = new Socket (oAddress,iPort); iID=getID(); dtToday =new Date (); }
Passen Sie den Serialisierungsprozess vollständig an:
Wenn eine Klasse vollständig für ihre eigene Serialisierung verantwortlich sein soll, implementieren Sie Externalizable Schnittstelle anstelle der Serializable-Schnittstelle. Die Externalizable-Schnittstellendefinition umfasst zwei Methoden: writeExternal() und readExternal(). Diese Methoden können verwendet werden, um zu steuern, wie die Objektdatenelemente in den Bytestream geschrieben werden. Wenn eine Klasse Externalizable implementiert, wird der Header in den Objektstream geschrieben, und dann ist die Klasse vollständig für die Serialisierung und Wiederherstellung der Datenelemente verantwortlich Für den Header gibt es überhaupt keine automatische Serialisierung. Hier gibt es etwas zu beachten. Die Deklaration einer Klasse zur Implementierung der Externalizable-Schnittstelle stellt ein erhebliches Sicherheitsrisiko dar. Die Methoden writeExternal() und readExternal() werden als öffentlich deklariert, und böswillige Klassen können diese Methoden zum Lesen und Schreiben von Objektdaten verwenden. Seien Sie äußerst vorsichtig, wenn das Objekt vertrauliche Informationen enthält. Dazu gehört die Verwendung sicherer Sockets oder die Verschlüsselung des gesamten Bytestroms. Bisher haben wir die Grundlagen der Serialisierung gelernt.
Ausführlichere Erläuterungen zu grundlegenden Beispielen der Objektserialisierung in Java-Tutorials und verwandten Artikeln finden Sie auf der chinesischen PHP-Website!