3426 Stimmen

Was ist eine serialVersionUID und warum sollte ich sie verwenden?

Eclipse gibt Warnungen aus, wenn ein serialVersionUID fehlt.

Die serialisierbare Klasse Foo deklariert keine statische finale serialVersionUID-Feld vom Typ long

¿Qué es? serialVersionUID und warum ist sie wichtig? Bitte zeigen Sie ein Beispiel, bei dem fehlende serialVersionUID wird ein Problem verursachen.

7 Stimmen

Finden Sie eine gute Praxis über serialversionUID; dzone.com/articles/what-is-serialversionuid

2577voto

Jon Skeet Punkte 1325502

Die Dokumentationen für java.io.Serializable sind wahrscheinlich die beste Erklärung, die Sie bekommen können:

Die Serialisierungs-Laufzeit assoziiert mit jeder serialisierbaren Klasse eine Versionsnummer, eine sogenannte serialVersionUID die während der Deserialisierung verwendet wird, um zu überprüfen, ob Sender und Empfänger eines serialisierten Objekts Klassen für dieses Objekt geladen haben, die im Hinblick auf die Serialisierung kompatibel sind. Wenn der Empfänger eine Klasse für das Objekt geladen hat, die eine andere serialVersionUID als die der entsprechenden Absenderklasse, dann führt die Deserialisierung zu einem InvalidClassException . Eine serialisierbare Klasse kann ihre eigene serialVersionUID explizit durch Deklaration eines Feldes namens serialVersionUID die statisch und endgültig sein müssen und vom Typ long :

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Wenn eine serialisierbare Klasse nicht explizit eine serialVersionUID wird die Serialisierungslaufzeit eine Standard serialVersionUID Wert für diese Klasse auf der Grundlage verschiedener Aspekte der Klasse, wie in der Java(TM) Object Serialization Specification beschrieben. Es ist jedoch dringend empfohlen dass alle serialisierbaren Klassen ausdrücklich deklarieren serialVersionUID Werte, da der Standardwert serialVersionUID Berechnung ist sehr empfindlich gegenüber Klassendetails, die je nach Compiler-Implementierung variieren können, und kann daher zu unerwarteten InvalidClassExceptions während der Deserialisierung. Um daher eine konsistente serialVersionUID Wert über verschiedene Java-Compiler-Implementierungen hinweg zu erhalten, muss eine serialisierbare Klasse eine explizite serialVersionUID Wert. Es wird auch dringend empfohlen, dass explizit serialVersionUID Deklarationen verwenden nach Möglichkeit den Modifikator private, da solche Deklarationen nur für die unmittelbar deklarierende Klasse gelten - serialVersionUID Felder sind als geerbte Mitglieder nicht sinnvoll.

384 Stimmen

Sie sagen also im Wesentlichen, dass ein Benutzer, der das oben genannte Material nicht verstanden hat, sich nicht um die Serialisierung kümmern sollte? Ich glaube, Sie haben eher das "Wie?" beantwortet, als das "Warum?" zu erklären. Ich für meinen Teil verstehe nicht, warum ich mich mit SerializableVersionUID beschäftigen sollte.

409 Stimmen

Der Grund dafür ist im zweiten Absatz zu finden: Wenn Sie serialVersionUID nicht explizit angeben, wird automatisch ein Wert generiert - aber das ist brüchig, weil es von der Compiler-Implementierung abhängig ist.

19 Stimmen

Und warum sagt Eclipse, ich brauche "private static final long serialVersionUID = 1L;", wenn ich die Klasse Exception erweitere?

522voto

MetroidFan2002 Punkte 28293

Wenn Sie nur serialisieren, weil Sie um der Implementierung willen serialisieren müssen (wen interessiert es, ob Sie für eine HTTPSession zum Beispiel... ob es gespeichert ist oder nicht, ist Ihnen wahrscheinlich egal de-serializing ein Formularobjekt), dann können Sie dies ignorieren.

Wenn Sie die Serialisierung tatsächlich verwenden, ist dies nur dann von Bedeutung, wenn Sie planen, Objekte direkt über die Serialisierung zu speichern und abzurufen. Die serialVersionUID steht für die Version Ihrer Klasse, und Sie sollten sie erhöhen, wenn die aktuelle Version Ihrer Klasse nicht abwärtskompatibel mit der vorherigen Version ist.

In den meisten Fällen werden Sie die Serialisierung wahrscheinlich nicht direkt verwenden. Wenn dies der Fall ist, erzeugen Sie eine Standard SerialVersionUID indem Sie auf die Schnellbehebungsoption klicken und sich nicht darum kümmern.

88 Stimmen

Ich würde sagen, wenn Sie die Serialisierung nicht für die permanente Speicherung verwenden, sollten Sie @SuppressWarnings verwenden, anstatt einen Wert hinzuzufügen. Dadurch wird die Klasse weniger unübersichtlich und der SerialVersionUID-Mechanismus bleibt erhalten, um Sie vor inkompatiblen Änderungen zu schützen.

29 Stimmen

Ich verstehe nicht, wie das Hinzufügen einer Zeile (@SuppressWarnings-Anmerkung) im Gegensatz zu einer anderen Zeile (serialisierbare ID) "die Klasse weniger unübersichtlich macht". Und wenn Sie die Serialisierung nicht für die dauerhafte Speicherung verwenden, warum sollten Sie nicht einfach "1" verwenden? In diesem Fall wäre die automatisch generierte ID sowieso egal.

77 Stimmen

@MetroidFan2002: Ich denke, @TomAnderson's Standpunkt zu serialVersionUID Sie vor unvereinbaren Änderungen zu schützen, ist gültig. Verwendung von @SuppressWarnings dokumentiert die Absicht besser, wenn Sie die Klasse nicht für die dauerhafte Speicherung verwenden wollen.

367voto

Scott Bale Punkte 10399

Ich kann mir die Gelegenheit nicht entgehen lassen, das Buch von Josh Bloch vorzustellen Leistungsfähiges Java (2. Auflage). Kapitel 10 ist eine unverzichtbare Ressource zur Java-Serialisierung.

Bei Josh wird die automatisch generierte UID auf der Grundlage des Klassennamens, der implementierten Schnittstellen und aller öffentlichen und geschützten Mitglieder generiert. Wird eine dieser Angaben in irgendeiner Weise geändert, ändert sich die serialVersionUID . Sie brauchen sich also nur dann nicht mit ihnen herumzuschlagen, wenn Sie sicher sind, dass nicht mehr als eine Version der Klasse jemals serialisiert wird (entweder prozessübergreifend oder zu einem späteren Zeitpunkt aus dem Speicher abgerufen).

Wenn Sie sie vorerst ignorieren und später feststellen, dass Sie die Klasse in irgendeiner Weise ändern müssen, aber die Kompatibilität mit der alten Version der Klasse beibehalten wollen, können Sie das JDK-Tool serialver zur Erzeugung der serialVersionUID über die alt Klasse, und setzen Sie diese explizit auf die neue Klasse. (Je nach Ihren Änderungen müssen Sie möglicherweise auch eine benutzerdefinierte Serialisierung implementieren, indem Sie writeObject y readObject Methoden - siehe Serializable javadoc oder das bereits erwähnte Kapitel 10).

41 Stimmen

So könnte man mit SerializableVersionUID stören, wenn man über die Kompatibilität w / alte Versionen einer Klasse besorgt waren?

15 Stimmen

Ja, falls die neuere Version ein öffentliches Mitglied in ein geschütztes ändert, wird die standardmäßige SerializableVersionUID anders sein und eine InvalidClassExceptions auslösen.

3 Stimmen

Klassenname, implementierte Schnittstellen, alle öffentlichen und geschützten Methoden, ALLE Instanzvariablen.

146voto

matt b Punkte 135206

Sie können Eclipse anweisen, diese serialVersionUID-Warnungen zu ignorieren:

Fenster > Einstellungen > Java > Compiler > Fehler/Warnungen > Potenzielle Programmierprobleme

Falls Sie es noch nicht wussten, es gibt noch viele andere Warnungen, die Sie in diesem Abschnitt aktivieren können (oder sogar als Fehler melden lassen können), viele davon sind sehr nützlich:

  • Mögliche Probleme bei der Programmierung: Mögliche versehentliche boolesche Zuweisung
  • Mögliche Probleme bei der Programmierung: Null-Zeiger-Zugriff
  • Unnötiger Code: Lokale Variable wird nie gelesen
  • Unnötiger Code: Redundante Nullprüfung
  • Unnötiger Code: Unnötiger Cast oder 'instanceof'

und viele mehr.

26 Stimmen

Upvote, aber nur, weil der ursprüngliche Poster nicht den Eindruck macht, irgendetwas zu serialisieren. Wenn der Poster sagen würde: "Ich stelle diese Sache in Serie her und ...", dann würdest du stattdessen eine Ablehnung bekommen :P

15 Stimmen

@Gardner -> einverstanden! Aber der Fragesteller möchte auch wissen, warum er vielleicht nicht gewarnt werden möchte.

11 Stimmen

Der Fragesteller interessiert sich offensichtlich dafür, warum es eine UID geben sollte. Ihm einfach zu sagen, er solle die Warnung ignorieren, sollte daher heruntergestuft werden.

126voto

Alexander Torstling Punkte 17776

serialVersionUID erleichtert die Versionierung von serialisierten Daten. Sein Wert wird bei der Serialisierung zusammen mit den Daten gespeichert. Bei der De-Serialisierung wird dieselbe Version geprüft, um zu sehen, wie die serialisierten Daten mit dem aktuellen Code übereinstimmen.

Wenn Sie Ihre Daten versionieren wollen, beginnen Sie normalerweise mit einer serialVersionUID von 0, und erhöhen Sie sie bei jeder strukturellen Änderung Ihrer Klasse, die die serialisierten Daten verändert (Hinzufügen oder Entfernen nicht transienter Felder).

Der eingebaute De-Serialisierungsmechanismus ( in.defaultReadObject() ) weigert sich, alte Versionen der Daten zu de-serialisieren. Aber wenn Sie wollen, können Sie Ihre eigene readObject() -Funktion, die alte Daten zurücklesen kann. Dieser benutzerdefinierte Code kann dann die serialVersionUID um zu wissen, in welcher Version die Daten vorliegen, und um zu entscheiden, wie sie de-serialisiert werden sollen. Diese Versionierungstechnik ist nützlich, wenn Sie serialisierte Daten speichern, die mehrere Versionen Ihres Codes überdauern.

Die Speicherung von serialisierten Daten über einen so langen Zeitraum ist jedoch nicht sehr verbreitet. Viel häufiger wird der Serialisierungsmechanismus verwendet, um Daten vorübergehend z.B. in einen Zwischenspeicher zu schreiben oder sie über das Netz an ein anderes Programm mit derselben Version der relevanten Teile der Codebasis zu senden.

In diesem Fall sind Sie nicht an der Aufrechterhaltung der Abwärtskompatibilität interessiert. Es geht Ihnen nur darum, sicherzustellen, dass die Codebasen, die miteinander kommunizieren, tatsächlich die gleichen Versionen der relevanten Klassen haben. Um eine solche Prüfung zu ermöglichen, müssen Sie die serialVersionUID wie bisher und vergessen Sie nicht, sie zu aktualisieren, wenn Sie Änderungen an Ihren Klassen vornehmen.

Wenn Sie vergessen, das Feld zu aktualisieren, haben Sie am Ende möglicherweise zwei verschiedene Versionen einer Klasse mit unterschiedlicher Struktur, aber mit der gleichen serialVersionUID . Wenn dies geschieht, wird der Standardmechanismus ( in.defaultReadObject() ) wird keinen Unterschied feststellen und versuchen, inkompatible Daten zu de-serialisieren. Nun kann es zu einem kryptischen Laufzeitfehler oder einem stillen Fehler (Nullfelder) kommen. Diese Arten von Fehlern können schwer zu finden sein.

Um diesen Anwendungsfall zu unterstützen, bietet die Java-Plattform die Möglichkeit, die serialVersionUID manuell. Stattdessen wird zur Kompilierzeit ein Hash der Klassenstruktur erzeugt und als id verwendet. Dieser Mechanismus stellt sicher, dass Sie niemals verschiedene Klassenstrukturen mit der gleichen ID haben, so dass die oben erwähnten, schwer zu verfolgenden Laufzeit-Serialisierungsfehler nicht auftreten.

Die Strategie der automatisch generierten IDs hat jedoch auch eine Kehrseite. Nämlich, dass die generierten IDs für dieselbe Klasse von Compiler zu Compiler unterschiedlich sein können (wie von Jon Skeet oben erwähnt). Wenn Sie also serialisierte Daten zwischen Code kommunizieren, der mit verschiedenen Compilern kompiliert wurde, sollten Sie die IDs auf jeden Fall manuell pflegen.

Und wenn Sie mit Ihren Daten rückwärtskompatibel sind, wie im ersten genannten Anwendungsfall, möchten Sie wahrscheinlich auch die ID selbst pflegen. Dies, um lesbare IDs zu erhalten und eine bessere Kontrolle darüber zu haben, wann und wie sie sich ändern.

5 Stimmen

Das Hinzufügen oder Entfernen von nicht-transienten Feldern macht die Klasse nicht serialisierungsinkompatibel. Es gibt daher keinen Grund, sie bei solchen Änderungen zu "stoßen".

4 Stimmen

@EJP: Hm? Das Hinzufügen von Daten ändert definitiv die Serialisierungsdaten in meiner Welt.

3 Stimmen

@AlexanderTorstling Lesen Sie, was ich geschrieben habe. Ich habe nicht gesagt, dass es "die Serialisierungsdaten nicht ändert". Ich sagte, es macht die Klasse nicht serialisierungsinkompatibel. Das ist nicht das Gleiche. Sie müssen das Kapitel Versionierung in der Spezifikation der Objektserialisierung lesen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X