Warum muss die serialisierbare Marker-Schnittstelle für die Serialisierung implementiert werden? [Duplikat]

8

Technisch weiß ich, warum Klasse serializable implementieren muss. Grund ist die writeObject-Methode von ObjectOutputStream, die intern die "instance of serializable" vor dem Schreiben des Zustands des Objekts prüft.

Aber meine Frage ist, was ist das nötig? writeObject-Methode kann einfach den Objektzustand schreiben ob Objekt (dessen Zustand geschrieben werden muss) serialisierbar implementiert oder nicht?

Gemäß Wiki implementiert eine Klasse diese Schnittstelle, um anzuzeigen, dass ihre nicht-vorübergehenden Datenelemente in eine geschrieben werden können ObjectOutputStream. Aber wieder Frage ist, warum Klasse serializable nur um zu bestimmen, ob Feld transient ist oder nicht implementieren muss. Auch eine Klasse, die keine Serialisierung implementiert, sollte serialisiert werden (außer den als transient markierten Feldern).

Das Markieren eines Objekts als serialisierbar (mit einer Schnittstelle) macht dieses Objekt nicht magisch serialisierbar, es war die ganze Zeit serialisierbar, nur dass Sie jetzt etwas ausgedrückt haben, das das System selbst gefunden haben könnte, also ich sehe keinen wirklichen guten Grund für die Serialisierung, wie sie jetzt ist.

Warum muss eine serialisierbare Markerschnittstelle implementiert werden, um die Klasse zu serialisieren?

    
M Sach 16.11.2013, 12:10
quelle

3 Antworten

4

Mit der Marker-Schnittstelle können Benutzer auswählen, ob eine Klasse Serializable erstellt werden soll. Manchmal möchten Sie das vielleicht nicht! (Und sicherlich wäre es nicht gut, dies zum Standard zu machen: Siehe zum Beispiel die Antworten auf diese Frage: Warum benötigt Java eine serialisierbare Schnittstelle? )

    
ljgw 16.11.2013, 12:27
quelle
2

Bei der Verkapselung geben wir vor, dass nichts über die interne Repräsentation eines Objekts offenbart wird, und wir interagieren mit unseren Komponenten nur über ihre öffentlichen Schnittstellen; ein wünschenswertes Attribut, das wir normalerweise später ausnutzen, wenn wir die interne Repräsentation von Daten in einer Komponente ändern wollen, ohne Code von seinen Benutzern zu brechen.

Umgekehrt bedeutet Serialisierung, dass der interne Zustand eines Objekts offengelegt wird, indem der Zustand des Objekts in ein anderes Format umgewandelt wird, das später gespeichert und wiederbelebt werden kann. Dies bedeutet, dass die interne Struktur eines Objekts, nachdem es einmal serialisiert wurde, nicht geändert werden kann, ohne den Erfolg dieses Auferstehungsprozesses zu riskieren.

Die Probleme mit der Serialisierung können nicht nur bei offenen Systemen auftreten, sondern auch bei verteilten Systemen, die sich irgendwie darauf verlassen. Wenn wir beispielsweise unseren Anwendungsserver stoppen, kann er die Objekte in der aktuellen Sitzung serialisieren, um sie später wieder auferstehen zu lassen, wenn der Server neu gestartet wird. Aber wenn wir unsere Anwendung mithilfe neuer Versionen unserer serialisierbaren Objekte erneut bereitstellen, werden sie weiterhin bestehen kompatibel, wenn der Server versucht, sie wiederzubeleben? In einem verteilten System ist es üblich, Code-Mobilität zu verwenden, nämlich Klassen von Klassen befinden sich in einem zentralen Repository, das für Clients und Server, um gemeinsamen Code zu teilen. Da bei dieser Methode Objekte serialisiert werden, damit sie von Clients und Servern gemeinsam genutzt werden können, besteht die Gefahr, dass bei der Aktualisierung der serialisierbaren Klassen in diesem gemeinsamen Repository Fehler auftreten.

Betrachten wir zum Beispiel, dass wir eine Klassenperson wie folgt hatten:

%Vor%

Nehmen wir an, wir haben unsere erste Version unserer API mit dieser Abstraktion einer Person veröffentlicht. Für die zweite Version möchten wir jedoch zwei Änderungen einführen: Erstens haben wir entdeckt, dass es besser wäre, wenn wir das Geburtsdatum einer Person anstatt des Alters als Ganzzahl speichern könnten, und zweitens unsere Definition der Die Klasse Person ist möglicherweise aufgetreten, als Java keine Aufzählungen hatte, aber jetzt möchten wir sie verwenden, um das Geschlecht einer Person darzustellen.

Da die Felder korrekt gekapselt sind, können wir offensichtlich die inneren Abläufe der Klasse ändern, ohne die öffentliche Schnittstelle zu beeinflussen. Etwas so:

%Vor%

Indem wir diese Änderungen wie oben gezeigt ausführen, können wir sicherstellen, dass bereits existierende Clients nicht brechen, denn selbst wenn wir die interne Repräsentation des Zustands des Objekts geändert haben, haben wir die öffentliche Schnittstelle unverändert gelassen.

Beachten Sie jedoch, dass die Klasse Person standardmäßig serialisierbar war. Wenn unser System ein offenes System ist, kann es Tausende von Codezeilen geben, die darauf angewiesen sind, dass serialisierte Objekte basierend auf dem System wiederbelebt werden können ursprüngliche Klasse oder vielleicht sogar Clients, die erweiterte Klassen basierend auf der ursprünglichen Version der Klasse als ihre Eltern serialisiert haben. Einige dieser Objekte wurden möglicherweise von den Benutzern unserer API in Binärform oder in einem anderen Format serialisiert, die sich nun zu unserer zweiten Version des Codes entwickeln möchten.

Wenn wir dann, wie in unserem zweiten Beispiel, einige Änderungen vornehmen wollten, würden wir sofort einige von ihnen brechen; alle diejenigen, die auf der ursprünglichen Version der Klasse basierende Objekte serialisiert haben, die Objekte gespeichert haben, die ein Feld namens Alter des Typs int enthalten, das das Alter einer Person enthält, und ein Feld mit dem Namen isMale vom Typ boolean, das Informationen über das Geschlecht enthält, scheitern wahrscheinlich Deserialisierung dieser Objekte, da die neue Klassendefinition neue Felder und neue Datentypen verwendet.

Offensichtlich besteht unser Problem hier darin, dass die Serialisierung sensible Informationen über unsere Objekte enthüllte, und jetzt können wir nicht einfach irgendetwas ändern, nicht einmal das, was wir für eingekapselt hielten, weil durch die Serialisierung alles öffentlich gemacht wurde.

Betrachten Sie nun ein Szenario, in dem jede einzelne Klasse in der JDK-API standardmäßig serialisierbar ist. Die Entwickler von Java konnten einfach nicht die APIs von Java entwickeln, ohne zu riskieren, viele Anwendungen zu knacken . Sie wären gezwungen anzunehmen, dass irgendjemand da draußen eine serialisierte Version einer der Klassen im JDK haben könnte.

Es gibt Möglichkeiten, mit der Entwicklung von serialisierbaren Klassen umzugehen, aber der wichtige Punkt hier ist, dass wir, wenn es um die Kapselung geht, unsere serialisierbaren Klassen so klein wie möglich halten wollen und für die Klassen, die wir tatsächlich brauchen serialisieren, dann müssen wir vielleicht über die Implikationen jedes möglichen Szenarios nachdenken, in dem wir versuchen könnten, ein Objekt unter Verwendung einer weiterentwickelten Version seiner Klasse wiederzubeleben.

Trotz all dem hat die Serialisierung auch Auswirkungen auf die Sicherheit, da wichtige, sensible Informationen über unsere Objekte leicht zugänglich gemacht werden können.

Dadurch, dass die Klassen, die serialisierbar sind, markiert sind, erleichtert es den Entwicklern von APIs, mit ihnen umzugehen.

    
Edwin Dalorzo 16.11.2013 12:28
quelle
0

Serializable heißt Marker-Interface wie Cloneable. Wenn Sie eine Marker-Schnittstelle (keine Methodenimplementierung) verwenden, möchten Sie jvm oder dem Compiler mitteilen, dass Sie während der Laufzeit oder der Kompilierzeit etwas hinzufügen oder überprüfen möchten.

Marker-Schnittstellendefinition:

"Eine Schnittstelle wird Marker-Schnittstelle genannt, wenn sie von Java-Interpreter als Handle zur Verfügung gestellt wird, um eine Klasse so zu markieren, dass sie ihr zur Laufzeit spezielles Verhalten geben kann und sie keine Methodendeklarationen haben."

Auch Marker-Schnittstelle ist eine gute Möglichkeit, Code zu klassifizieren. Sie können eine Markierungsschnittstelle erstellen, um Ihren Code logisch zu teilen, und wenn Sie ein eigenes Werkzeug haben, können Sie einige Vorverarbeitungsoperationen für diese Klassen durchführen. Besonders nützlich für die Entwicklung von API und Framework wie Spring oder Struts.

Marker-Schnittstelle kann auch Code-Coverage oder Code-Review-Tool helfen, um Fehler basierend auf spezifizierten Verhalten von Marker-Schnittstellen zu finden.

siehe marker interface im wiki http://en.wikipedia.org/wiki/Marker_Interface_pattern

    
jdev 16.11.2013 12:33
quelle