2008-09-03 3 views
7

In Java werden statische und transiente Felder nicht serialisiert. Ich fand jedoch heraus, dass die Initialisierung von statischen Feldern bewirkt, dass die generierte serialVersionUID geändert wird. Beispiel: static int MYINT = 3; bewirkt, dass sich serialVersionUID ändert. In diesem Beispiel ist es sinnvoll, da verschiedene Versionen der Klasse unterschiedliche Anfangswerte erhalten. Warum ändert eine Initialisierung die serialVersionUID? Zum Beispiel bewirkt static String MYSTRING = System.getProperty("foo"); auch, dass sich die serialVersionUID ändert.Java-Serialisierung mit statischer Initialisierung

Um genau zu sein, ist meine Frage, warum die Initialisierung mit einer Methode die serialVersionUID ändert. Das Problem, das ich treffe, ist, dass ich ein neues statisches Feld hinzugefügt habe, das mit einem Systemeigenschaftswert (getProperty) initialisiert wurde. Diese Änderung verursachte eine Serialisierungsausnahme bei einem Remoteaufruf.

Antwort

5

Sie können einige Informationen darüber in der bug 4365406 und in der algorithm for computing serialVersionUID finden. Wenn Sie die Initialisierung Ihres Members static mit ändern, führt der Compiler eine neue static-Eigenschaft in Ihrer Klasse ein, die auf die System-Klasse verweist (ich nehme an, dass die System-Klasse zuvor in Ihrer Klasse nicht referenziert wurde) und seit dieser Eigenschaft vom Compiler eingeführt ist nicht privat, es nimmt an der serialVersionUID Berechnung teil.

Morality: Verwenden Sie immer explizit serialVersionUID, werden Sie einige CPU-Zyklen und einige Kopfschmerzen sparen :)

0

Wenn ich die Spezifikation richtig lese, sollte sich die automatische serialVersionUID nicht ändern, wenn Sie den Wert eines statischen Transientenfeldes ändern. Werfen Sie einen Blick auf Chapter 5.6 der Spec.

jedoch, wenn Sie diese ein wenig denken - Sie durch die Serialisierung ein Objekt starten, die static int MYINT = 3 hat, wenn man dann die Klasse Deserialisieren Sie erwarten, wieder das gleiche Objekt zu erhalten, das heißt, mit MYINT = 3. Wenn Sie also die statische Initialisierung ändern, würden Sie erwarten, dass sich die serialVersionUID ändert, weil Sie das gleiche Objekt nicht mehr zurückbekommen können.

Anyways, halten dies in allen serializable Klassen und Sie die serialVersionUID steuern:

private static final long serialVersionUID = 7526472295622776147L; 
0

ich die Frage aktualisiert, um mehr klar zu sein. Ich verstehe, warum die Initialisierung mit einem Literal die serialVersionUID ändert, aber nicht, warum dynamische Initialisierung es ändert. Wenn Sie mit einer Methode initialisieren, kann der Wert natürlich immer unterschiedlich sein.

Die Einstellung serialVersionUID ist explizit in einer nachfolgenden Version der Klasse nur dann möglich, wenn Sie sicher sind, dass es sich um eine sichere Änderung handelt.

2

Automatische serialVersionUID basierend auf Mitglieder einer Klasse berechnet wird. Diese können für eine Klassendatei mit dem javap-Tool im Sun JDK angezeigt werden.

In dem in der Frage erwähnten Fall ist das Element, das hinzugefügt/entfernt wird, der statische Initialisierer. Dies erscheint als() V in Klassendateien. Der Inhalt der Methode kann mit javap -c demontiert werden. Sie sollten den Aufruf von System.getProperty ("foo") und die Zuweisung zu MYSTRING erkennen können. Eine Zuweisung mit einem Zeichenfolgenliteral (oder einer beliebigen Kompilierzeitkonstante, wie in der Java-Sprachspezifikation definiert) wird jedoch direkt von der Klassendatei unterstützt, wodurch die Notwendigkeit eines statischen Initialisierers entfällt.

Ein häufiger Fall für Code Targeting J2SE 1.4 (verwenden Sie -source 1.4 -target 1.4) oder früher ist statische Felder zu alten Klasseninstanzen, die als Klassenliterale im Quellcode (MyClass.class) angezeigt werden. Die Klasseninstanz wird bei Class.forName nach Bedarf gesucht und in einem statischen Feld gespeichert. Es ist dieses statische Feld, das die serialVersionUID stört. Ab J2SE 5.0 bietet eine Variante des LDC-Opcodes direkte Unterstützung für Klassenliterale, wodurch das synthetische Feld überflüssig wird. Auch dies kann mit javap -c angezeigt werden.