Was sind die Vor- und Nachteile der Verwendung von serialVersionUID und @SuppressWarnings ("serial") für Klassen, die Serializable implementieren?

8

Diese Frage war Gegenstand lebhafter Diskussionen in meinem Team. Meine persönliche Wahl ist es,

zu verwenden %Vor%

Meine Gedanken sind, dass es im Vergleich zur Verwendung von

weniger zu pflegen gibt %Vor%

Habe ich Recht, wenn ich denke, dass die Verwendung des Compilers die UID generiert und daher eher Änderungen an der Klasse übernimmt?

Meine größte Sorge ist, dass die Wahrscheinlichkeit, dass ein Entwickler die UID ändert, wenn er die Klasse ändert, eher zu unvorhergesehenen Fehlern führt.

Gibt es Fallen für meinen Ansatz? Hat jemand anderes gute oder schlechte Erfahrungen mit einem dieser Ansätze gemacht?

    
James DW 03.10.2011, 14:32
quelle

6 Antworten

6

Es läuft auf diese Fragen hinaus:

  • Sollen die serialisierten Streams mit genau demselben Code oder mit anderem Code gelesen und geschrieben werden?

"Unterschiedlicher Code" kann verschiedene Dinge bedeuten:

  • alte Versionen vs. neue Versionen
  • zwei unabhängige Programme mit vielleicht alten und neuen Bibliotheken
  • mehr von solchen Sachen.

In diesen Fällen sollten Sie stark die Serialisierungsverträge einhalten - und dies nicht, indem Sie einfach serialVersionUId setzen - normalerweise müssen Sie auch die Methoden für Serialisierung und Deserialisierung überschreiben, um mit verschiedenen Versionen fertig zu werden.

Wenn andererseits das gleiche Programm den Inhalt für einen internen Cache liest und schreibt und dieser Cache von Grund auf neu erstellt werden kann, wenn die Software aktualisiert wird, dann können Sie Ihr Leben so einfach wie Sie machen kann.

Zwischen diesen Extremen gibt es natürlich verschiedene Grautöne.

    
A.H. 03.10.2011, 14:48
quelle
4

Wie üblich, ist die definitive Antwort in einem eigenen Kapitel von Effektivem Java .

TL; DR. Die Verwendung von @SuppressWarnings("serial") ist in Ordnung (und gut zum Entfernen der Warnung), es sei denn, Sie möchten die Klasse tatsächlich serialisieren. In diesem Fall möchten Sie serialVersionUID tatsächlich implementieren und ordnungsgemäß ausführen, indem Sie es nach jeder Änderung in der Klasse neu generieren (oder zumindest ändern), was zu Problemen bei der Deserialisierung führen würde.

    
Daniel 03.10.2011 14:42
quelle
3

Wenn ein Objekt serialisiert wird, wenn es eine Seriennummer hat, wird es verwendet, andernfalls wird es erzeugt.

Wenn die serielle Kennung fehlt und die javac -Option -Xlint angegeben ist, wird eine Warnung generiert. Diese Warnung kann mit @SuppressWarnings("serial") stummgeschaltet werden. Der Zweck dieser Annotation besteht lediglich darin, die Warnung zu unterdrücken, da sie die Serialisierung nicht auf andere Weise beeinträchtigt.

Von Serialisierbar Javadoc:

  

Die Serialisierungslaufzeit verknüpft mit jeder serialisierbaren Klasse eine Versionsnummer namens serialVersionUID, die während der Deserialisierung verwendet wird, um zu überprüfen, ob der Sender und der Empfänger eines serialisierten Objekts Klassen für dieses Objekt geladen haben kompatibel in Bezug auf die Serialisierung.

und auch:

  

Wenn eine serialisierbare Klasse eine serialVersionUID nicht explizit deklariert, berechnet die Serialisierungslaufzeit einen standardmäßigen serialVersionUID-Wert für diese Klasse basierend auf verschiedenen Aspekten der Klasse, wie in Java (TM) beschrieben. Objekt Serialisierungsspezifikation. Es wird jedoch dringend empfohlen, dass alle serialisierbaren Klassen serialVersionUID-Werte ausdrücklich deklarieren, da die standardmäßige serialVersionUID-Berechnung sehr empfindlich auf Klassendetails reagiert, die je nach Compiler-Implementierung variieren und daher bei der Deserialisierung zu unerwarteten InvalidClassExceptions führen können .

Beispiel: Serialisierung einer Klasse mit @SuppressWarnings("serial")

Test.java: Die zu serialisierende Klasse

%Vor%

Writer.java: Die Klasse, die eine Instanz von Test in die Datei test.serial

schreibt %Vor%     
stivlo 03.10.2011 14:42
quelle
2

Die Verwendung von serialVersionUID ist nicht der konservative Ansatz. Jede Änderung im serialisierten Format wird als inkompatible Änderung betrachtet. Das bedeutet, dass Sie Fehler beim Deserialisieren von Objekten finden, die von einer älteren Version geschrieben wurden, die tatsächlich zur Deserialisierung sinnvoll sind, wenn Sie benutzerdefinierten Deserialisierungscode geschrieben und serialVersionUID verwendet haben.

Die Verwendung hat den Vorteil, die Kompatibilität zwischen mehreren Versionen des serialisierten Objekts beizubehalten, führt aber zu einem neuen potenziellen Fehler: Wenn Sie vergessen haben, serialVersionUID nach dem Ändern einer Klasse auf inkompatible Weise zu aktualisieren, wird Das Beste, was passieren kann, ist, dass Sie zur Laufzeit einen Fehler bekommen, weil die Daten nicht sinnvoll gelesen werden können. Aber es könnte im Stillen gelingen, vielleicht indem serialisierte Daten in diesem Prozess ignoriert oder falsch interpretiert werden.

Also, entscheiden Sie sich zuerst, welchen Sie wollen: benutzen Sie es oder nicht? Ich verwende definitiv serialVersionUID nicht, es sei denn es ist eindeutig erforderlich, und es gibt eine Verpflichtung, es richtig zu halten.

Wenn Sie es nicht verwenden, können Sie Warnungen mit @SuppressWarnings deaktivieren, aber Sie können es auch in javac mit -Xlint:-serial global deaktivieren. Das ist ein grober Ansatz - praktisch vielleicht, aber stellen Sie sicher, dass Sie das wirklich wollen. Es ist angemessen, wenn Sie zum Beispiel serialVersionUID auf keinen Fall verwenden.

    
Sean Owen 03.10.2011 15:16
quelle
1

Wenn Sie der Meinung sind, dass Sie in Zukunft etwas zu dieser Klasse hinzufügen müssen, dann schreiben Sie serialVersionUID auf 1L, wenn Sie noch keine serialisierten Objekte haben. Wenn Sie bereits serialisierte Objekte haben und mit ihnen kompatibel bleiben müssen, verwenden Sie das serialver-Tool, um herauszufinden, worauf Java eingestellt ist, und verwenden Sie diesen Wert.

Auf diese Weise können Sie der Klasse in Zukunft weitere Attribute hinzufügen und automatisch kompatibel bleiben. Wenn Sie das oben beschriebene nicht tun, wird dies nicht automatisch gehandhabt und Sie müssen Code schreiben, um jedes Mal, wenn Sie der Klasse ein Feld hinzufügen, von den alten Klassen in die neuen Klassen zu konvertieren.

    
Sarel Botha 03.10.2011 15:08
quelle
0

Ich muss sagen, Ihre Wahl von SuppressWarning ist schlecht. Sie sollten serialVersionUID explizit definieren. Es zu behalten ist nicht so viel Arbeit, während es Ihr Leben in der Zukunft speichert.

Irgendwann in der Zukunft möchten Sie die Klassendefinition ändern (unumgänglich, wenn Ihre Arbeit ernst ist), während serialVersionUID beim Erreichen der Rückwärtskompatibilität Ihr Leben retten wird. Wenn Sie es nicht definieren, berechnet Java basierend auf der Klassensignatur (?) Die serialVersionUID für Sie. Einfaches Umordnen der Variablen würde die Signatur ändern und die Kompatibilität zerstören (oder sogar eine Hilfsfunktion hinzufügen). Im Ernst, die Definition von serialVersionUID wird dein Leben retten.

Sie sollten den Abschnitt "Serialisierung" in Effektivem Java lesen, wie von anderen Leuten vorgeschlagen.

    
oVo 15.07.2013 06:42
quelle

Tags und Links