Frage Was ist eine serialVersionUID und warum sollte ich sie verwenden?


Eclipse gibt Warnungen aus, wenn a serialVersionUID wird vermisst.

Die serialisierbare Klasse Foo deklariert kein statisches Finale   serialVersionUID-Feld vom Typ long

Was ist serialVersionUID und warum ist es wichtig? Bitte zeigen Sie ein Beispiel, wo es fehlt serialVersionUID wird ein Problem verursachen.


2482
2017-11-12 23:24


Ursprung


Antworten:


Die Dokumente für java.io.Serializable sind wahrscheinlich ungefähr so ​​gut eine Erklärung wie du bekommen wirst:

Die Serialisierungslaufzeitassoziiert   mit jeder serialisierbaren Klasse eine Version   Nummer, eine serialVersionUID genannt,   welches während der Deserialisierung verwendet wird   um zu überprüfen, dass der Absender und der Empfänger   eines serialisierten Objekts geladen haben   Klassen für das Objekt, das sind   kompatibel in Bezug auf   Serialisierung. Wenn der Empfänger hat   eine Klasse für das Objekt geladen, das   eine andere serialVersionUID als das   der Klasse des entsprechenden Absenders,   dann führt die Deserialisierung zu einem    InvalidClassException. Ein serialisierbarer   Klasse kann ihre eigenen deklarieren   serialVersionUID explizit von   ein Feld mit dem Namen deklarieren   "serialVersionUID" das muss sein   statisch, endgültig und vom Typ long:

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

Wenn ein   Serialisierbare Klasse nicht explizit   deklarieren Sie eine serialVersionUID, dann die   Serialisierungslaufzeit berechnet a   Standardwert für serialVersionUID für   Diese Klasse basiert auf verschiedenen Aspekten von   die Klasse, wie in der   Java (TM) -Objektserialisierung   Spezifikation. Wie auch immer es ist stark   empfohlen das alles serialisierbar   Klassen deklarieren explizit   serialVersionUID-Werte, seit der   Standard-serialVersionUID-Berechnung   ist sehr empfindlich für Klassendetails   Das hängt vom Compiler ab   Implementierungen und kann somit resultieren   unerwartet InvalidClassExceptions   während der Deserialisierung. Daher zu   garantieren eine konsequente   serialVersionUID-Wert über   anderer Java-Compiler   Implementierungen, eine serialisierbare Klasse   muss explizit deklarieren   serialVersionUID-Wert Es ist auch   ausdrücklich darauf hingewiesen   serialVersionUID-Deklarationen verwenden das   Privater Modifikator wo möglich, da   solche Erklärungen gelten nur für die   sofort erklären   Klasse - serialVersionUID Felder sind nicht   nützlich als ererbte Mitglieder.


1910
2017-11-12 23:30



Wenn Sie serialisieren, nur weil Sie für die Implementierung serialisieren müssen (wen interessiert es, wenn Sie zB für eine HTTPSession serialisieren ... wenn es gespeichert ist oder nicht, dann interessieren Sie sich wahrscheinlich nicht für das Deinserialisieren eines Formularobjekts) , dann kannst du das ignorieren.

Wenn Sie die Serialisierung tatsächlich verwenden, spielt dies nur eine Rolle, wenn Sie beabsichtigen, Objekte mithilfe der Serialisierung direkt zu speichern und abzurufen. Die serialVersionUID steht für Ihre Klassenversion und sollte erhöht werden, wenn die aktuelle Version Ihrer Klasse nicht mit der vorherigen Version kompatibel ist.

In den meisten Fällen werden Sie die Serialisierung wahrscheinlich nicht direkt verwenden. Wenn dies der Fall ist, generieren Sie eine standardmäßige serialisierbare Benutzer-ID, indem Sie auf die Schnellkorrektur-Option klicken, und machen Sie sich keine Gedanken darüber.


415
2017-11-13 04:24



Ich kann diese Gelegenheit nicht verpassen, Josh Blochs Buch zu verstopfen Wirksames Java (2. Ausgabe). Kapitel 11 ist eine unverzichtbare Ressource für die Java-Serialisierung.

Per Josh wird die automatisch generierte UID basierend auf einem Klassennamen, implementierten Schnittstellen und allen öffentlichen und geschützten Mitgliedern generiert. Änderungen in irgendeiner Weise ändern die serialVersionUID. Sie müssen sich also nicht nur mit ihnen anlegen, wenn Sie sicher sind, dass nicht mehr als eine Version der Klasse jemals serialisiert wird (entweder über Prozesse hinweg 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 müssen, können Sie das JDK-Tool verwenden Seriell das generieren serialVersionUID auf der alt Klasse und explizit für die neue Klasse. (Abhängig von Ihren Änderungen müssen Sie möglicherweise auch benutzerdefinierte Serialisierung implementieren, indem Sie hinzufügen writeObject und readObject Methoden - siehe Serializable Javadoc oder das vorher erwähnte Kapitel 11.)


264
2017-11-12 23:37



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

Fenster> Einstellungen> Java> Compiler> Fehler / Warnungen> Mögliche Programmierprobleme

Falls Sie es nicht wussten, gibt es eine Menge anderer Warnungen, die Sie in diesem Abschnitt aktivieren können (oder sogar einige als Fehler gemeldet haben), viele davon sind sehr nützlich:

  • Mögliche Programmierprobleme: Mögliche zufällige boolesche Zuweisung
  • Mögliche Programmierprobleme: Nullzeigerzugriff
  • Unnötiger Code: Lokale Variable wird nie gelesen
  • Unnötiger Code: Redundanter Null-Check
  • Unnötiger Code: Unnötige Besetzung oder 'instanceof'

und viele mehr.


124
2017-11-13 01:17



serialVersionUID erleichtert die Versionierung von serialisierten Daten. Sein Wert wird mit den Daten beim Serialisieren gespeichert. Beim Deserialisieren wird dieselbe Version überprüft, um zu sehen, wie die serialisierten Daten mit dem aktuellen Code übereinstimmen.

Wenn Sie Ihre Daten versionieren möchten, beginnen Sie normalerweise mit einem serialVersionUID von 0, und stoßen Sie mit jeder strukturellen Änderung zu Ihrer Klasse, die die serialisierten Daten ändert (das Hinzufügen oder das Entfernen von nicht-transienten Feldern).

Der eingebaute De-Serialisierungsmechanismus (in.defaultReadObject()) wird die Deserialisierung von alten Versionen der Daten verweigern. Aber wenn Sie möchten, können Sie Ihre eigenen definieren readObject ()-Funktion, die alte Daten zurücklesen kann. Dieser benutzerdefinierte Code kann dann die serialVersionUID um zu wissen, in welcher Version sich die Daten befinden und wie sie entserialisiert werden soll. Diese Versionierungstechnik ist nützlich, wenn Sie serialisierte Daten speichern, die mehrere Versionen Ihres Codes überstehen.

Das Speichern von serialisierten Daten für solch eine lange Zeitspanne ist jedoch nicht sehr üblich. Es ist weit üblicher, den Serialisierungsmechanismus zu verwenden, um Daten temporär beispielsweise in einen Cache zu schreiben oder sie über das Netzwerk an ein anderes Programm mit derselben Version der relevanten Teile der Codebasis zu senden.

In diesem Fall sind Sie nicht daran interessiert, die Rückwärtskompatibilität aufrechtzuerhalten. Es geht Ihnen nur darum, sicherzustellen, dass die Code-Basen, die kommunizieren, tatsächlich die gleichen Versionen relevanter Klassen haben. Um eine solche Prüfung zu erleichtern, müssen Sie die serialVersionUIDgenau wie vorher und nicht vergessen, es zu aktualisieren, wenn Sie Änderungen an Ihren Klassen vornehmen.

Wenn Sie vergessen, das Feld zu aktualisieren, erhalten Sie möglicherweise zwei verschiedene Versionen einer Klasse mit unterschiedlicher Struktur, aber mit derselben Struktur serialVersionUID. Wenn dies geschieht, wird der Standardmechanismus (in.defaultReadObject()) erkennt keinen Unterschied und versucht, inkompatible Daten zu deserialisieren. Jetzt können Sie einen kryptischen Laufzeitfehler oder einen stillen Fehler (Nullfelder) haben. Diese Arten von Fehlern können schwer zu finden sein.

Um diesen Usecase zu unterstützen, bietet Ihnen die Java-Plattform die Möglichkeit, die Einstellungen nicht zu ändern serialVersionUID manuell. Stattdessen wird ein Hash der Klassenstruktur zur Kompilierzeit generiert und als ID verwendet. Dieser Mechanismus stellt sicher, dass Sie nie unterschiedliche Klassenstrukturen mit der gleichen ID haben, und daher werden Sie diese schwer zu protokollierenden Runtime-Serialisierungsfehler nicht erhalten.

Aber es gibt eine Rückseite der automatisch generierten ID-Strategie. Nämlich, dass die generierten IDs für die gleiche Klasse zwischen Compilern unterschiedlich sein können (wie von Jon Skeet oben erwähnt). Wenn Sie also serialisierte Daten zwischen Code teilen, der mit verschiedenen Compilern kompiliert wurde, wird empfohlen, die IDs trotzdem manuell zu pflegen.

Und wenn Sie wie im ersten erwähnten Anwendungsfall rückwärtskompatibel mit Ihren Daten sind, 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.


96
2017-10-03 06:05



Was ist ein? serialVersionUID und warum sollte ich es benutzen?

SerialVersionUID ist eine eindeutige Kennung für jede Klasse, JVM verwendet es, um die Versionen der Klasse zu vergleichen, um sicherzustellen, dass die gleiche Klasse verwendet wurde, während die Serialisierung während der Deserialisierung geladen wurde.

Die Angabe von einer gibt mehr Kontrolle, obwohl JVM eine generiert, wenn Sie nicht angeben. Der generierte Wert kann zwischen verschiedenen Compilern unterschiedlich sein. Außerdem möchten Sie manchmal aus irgendeinem Grund die Deserialisierung alter serialisierter Objekte verbieten [backward incompatibility], und in diesem Fall müssen Sie nur die serialVersionUID ändern.

Das Javadocs für Serializable sagen:

Die standardmäßige serialVersionUID-Berechnung ist sehr sensitiv für die Klasse   Details, die abhängig von Compiler-Implementierungen variieren können und können   daher unerwartet InvalidClassExceptions während   Deserialisierung.

Daher müssen Sie serialVersionUID deklarieren, da es uns mehr Kontrolle gibt.

Dieser Artikel hat ein paar gute Punkte zum Thema.


62
2017-10-17 04:28



Die ursprüngliche Frage hat gefragt: "Warum ist es wichtig?" Serial Version ID wäre nützlich. Nun, ich habe einen gefunden.

Angenommen, Sie erstellen ein Car Klasse, instanziieren Sie es und schreiben Sie es in einen Objektstrom. Das abgeplattete Autoobjekt sitzt für einige Zeit im Dateisystem. Inzwischen, wenn die Car Die Klasse wird geändert, indem ein neues Feld hinzugefügt wird. Später, wenn Sie versuchen, die abgeflachten zu lesen (d. H. Deserialisieren) Car Objekt, du bekommst das java.io.InvalidClassException - Weil alle serialisierbaren Klassen automatisch eine eindeutige Kennung erhalten. Diese Ausnahme wird ausgelöst, wenn der Bezeichner der Klasse nicht mit dem Bezeichner des abgeflachten Objekts übereinstimmt. Wenn Sie wirklich darüber nachdenken, wird die Ausnahme ausgelöst, weil das neue Feld hinzugefügt wird. Sie können vermeiden, dass diese Ausnahme ausgelöst wird, indem Sie die Versionierung selbst steuern, indem Sie eine explizite serialVersionUID deklarieren. Es gibt auch einen kleinen Leistungsvorteil bei der ausdrücklichen Erklärung Ihrer serialVersionUID(weil muss nicht berechnet werden). Daher ist es die beste Vorgehensweise, Ihren serialisierbaren Klassen Ihre eigene serialVersionUID hinzuzufügen, sobald Sie sie wie folgt erstellen:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

41
2018-04-07 10:43



Wenn Sie diese Warnung in einer Klasse erhalten, denken Sie niemals über das Serialisieren nach, und Sie haben sich nicht selbst deklariert implements SerializableEs liegt oft daran, dass Sie von einer Oberklasse geerbt haben, die Serializable implementiert. Oft wäre es dann besser, ein solches Objekt zu delegieren anstatt die Vererbung zu verwenden.

Also, statt

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

machen

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

und in den relevanten Methoden aufrufen myList.foo() Anstatt von this.foo() (oder super.foo()). (Dies passt nicht in allen Fällen, aber immer noch ziemlich oft.)

Ich sehe oft Leute, die JFrame oder ähnliches erweitern, wenn sie wirklich nur dazu delegieren müssen. (Dies hilft auch beim automatischen Vervollständigen in einer IDE, da JFrame über Hunderte von Methoden verfügt, die Sie nicht benötigen, wenn Sie Ihre eigenen Klassen aufrufen möchten.)

Ein Fall, in dem die Warnung (oder die serialVersionUID) unvermeidbar ist, ist, wenn Sie von AbstractAction aus, normalerweise in einer anonymen Klasse, nur die actionPerformed-Methode hinzufügen. Ich denke, dass es in diesem Fall keine Warnung geben sollte (da Sie solche anonymen Klassen normalerweise nicht seriell vereinheitlichen und deserialisieren können, je nach Version Ihrer Klasse), aber ich bin mir nicht sicher, wie der Compiler das erkennen könnte.


33
2018-02-03 00:32



Wenn Sie Ihre Objekte nie in ein Byte-Array serialisieren und senden / speichern müssen, müssen Sie sich keine Gedanken darüber machen. Wenn Sie dies tun, müssen Sie Ihre serialVersionUID berücksichtigen, da der Deserializer des Objekts sie mit der Version des Objekts, das der Klassenlader hat, abgleicht. Lesen Sie mehr darüber in der Java-Sprachspezifikation.


30
2017-11-12 23:30