Was ist eine serialVersionUID und warum sollte ich sie verwenden?

3000

Eclipse gibt Warnungen aus, wenn a serialVersionUIDfehlt.

Die serialisierbare Klasse Foo deklariert kein statisches endgültiges serialVersionUID-Feld vom Typ long

Was ist serialVersionUIDund warum ist es wichtig? Bitte zeigen Sie ein Beispiel, bei dem das Fehlen serialVersionUIDein Problem verursacht.

ashokgelal
quelle
1
Finden Sie eine gute Vorgehensweise für serialversionUID. dzone.com/articles/what-is-serialversionuid
ceyun

Antworten:

2290

Die Dokumente für java.io.Serializablesind wahrscheinlich eine so gute Erklärung, wie Sie bekommen werden:

Die Serialisierungslaufzeit ordnet jeder serialisierbaren Klasse eine Versionsnummer zu, die als a serialVersionUIDbezeichnet wird und 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, die hinsichtlich der Serialisierung kompatibel sind. Wenn der Empfänger eine Klasse für das Objekt geladen hat serialVersionUID, die sich von der Klasse des entsprechenden Absenders unterscheidet , führt die Deserialisierung zu einer InvalidClassException. Eine serialisierbare Klasse kann ihre eigene serialVersionUIDexplizit deklarieren, indem sie ein Feld mit dem Namen deklariert serialVersionUID, das statisch, endgültig und vom Typ sein muss long:

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

Wenn eine serialisierbare Klasse a nicht explizit deklariert serialVersionUID, berechnet die Serialisierungslaufzeit einen Standardwert serialVersionUIDfür diese Klasse basierend auf verschiedenen Aspekten der Klasse, wie in der Java (TM) -Objektserialisierungsspezifikation beschrieben. Es wird jedoch dringend empfohlen, dass alle serialisierbaren Klassen explizit serialVersionUIDWerte deklarieren , da die Standardberechnung serialVersionUIDsehr empfindlich auf Klassendetails reagiert, die je nach Compiler-Implementierungen variieren können und daher InvalidClassExceptionswährend der Deserialisierung zu unerwarteten Ergebnissen führen können . Um einen konsistenten serialVersionUIDWert für verschiedene Java-Compiler-Implementierungen zu gewährleisten , muss eine serialisierbare Klasse daher einen expliziten serialVersionUIDWert deklarieren . Es wird auch ausdrücklich darauf hingewiesenserialVersionUIDDeklarationen verwenden nach Möglichkeit den Modifikator private, da solche Deklarationen nur für die unmittelbar deklarierenden Klassenfelder serialVersionUIDgelten und als geerbte Mitglieder nicht nützlich sind.

Jon Skeet
quelle
326
Sie sagen also im Wesentlichen, dass ein Benutzer, der das oben genannte Material nicht verstanden hat, sich keine Gedanken über die Serialisierung machen muss? Ich glaube, Sie haben das "Wie?" anstatt das "Warum?" zu erklären. Zum einen verstehe ich nicht, warum ich mich mit SerializableVersionUID beschäftige.
Ziggy
366
Das Warum ist im zweiten Absatz: Wenn Sie serialVersionUID nicht explizit angeben, wird automatisch ein Wert generiert - aber das ist spröde, weil es von der Compiler-Implementierung abhängt.
Jon Skeet
14
Und warum sagt Eclipse, ich brauche "private static final long serialVersionUID = 1L;" Wann erweitere ich die Ausnahmeklasse?
John Merlino
21
@ JohnMerlino: Nun, ich würde nicht erwarten, dass Sie eine benötigen - aber es könnte eine vorschlagen , um Ausnahmen korrekt zu serialisieren. Wenn Sie sie nicht serialisieren möchten, benötigen Sie die Konstante wirklich nicht.
Jon Skeet
16
@JohnMerlino, um den Warum-Teil Ihrer Frage zu beantworten: Ausnahme implementiert Serializable und Eclipse warnt, dass Sie keine serialVersionUID festgelegt haben. Dies wäre eine gute Idee (wenn Sie die Klasse nicht serialisieren möchten), um die Probleme zu vermeiden, die JonSkeets Beitrag verursacht Umrisse.
Zpon
475

Wenn Sie nur serialisieren, weil Sie für die Implementierung serialisieren müssen (wen interessiert es, wenn Sie beispielsweise für ein HTTPSession... ob es gespeichert ist oder nicht, interessieren Sie sich wahrscheinlich nicht für de-serializingein Formularobjekt), können Sie dies ignoriere das.

Wenn Sie tatsächlich die Serialisierung verwenden, ist dies nur wichtig, wenn Sie Objekte direkt mithilfe der Serialisierung speichern und abrufen möchten. Das serialVersionUIDstellt Ihre Klassenversion dar, und Sie sollten es erhöhen, wenn die aktuelle Version Ihrer Klasse nicht abwärtskompatibel mit der vorherigen Version ist.

Meistens werden Sie die Serialisierung wahrscheinlich nicht direkt verwenden. Wenn dies der Fall ist, generieren Sie einen Standard, SerialVersionUIDindem Sie auf die Schnellkorrekturoption klicken, und machen Sie sich darüber keine Sorgen.

MetroidFan2002
quelle
78
Ich würde sagen, wenn Sie die Serialisierung nicht für die permanente Speicherung verwenden, sollten Sie @SuppressWarnings verwenden, anstatt einen Wert hinzuzufügen. Es überlastet die Klasse weniger und bewahrt die Fähigkeit des serialVersionUID-Mechanismus, um Sie vor inkompatiblen Änderungen zu schützen.
Tom Anderson
25
Ich sehe nicht, wie das Hinzufügen einer Zeile (@ SuppressWarnings-Annotation) im Gegensatz zu einer anderen Zeile (serialisierbare ID) "die Klasse weniger durcheinander bringt". Und wenn Sie die Serialisierung nicht für die dauerhafte Speicherung verwenden, warum sollten Sie dann nicht einfach "1" verwenden? In diesem Fall wäre Ihnen die automatisch generierte ID sowieso egal.
MetroidFan2002
71
@ MetroidFan2002: Ich denke, @ TomAndersons Punkt serialVersionUID, Sie vor inkompatiblen Änderungen zu schützen, ist gültig. Verwenden Sie @SuppressWarningsDokumente besser, wenn Sie die Klasse nicht für die dauerhafte Speicherung verwenden möchten.
AbdullahC
11
"Sie sollten es erhöhen, wenn die aktuelle Version Ihrer Klasse nicht abwärtskompatibel mit der vorherigen Version ist:" Sie sollten zunächst die umfassende Unterstützung der Serialisierung für die Objektversionierung untersuchen, (a) um sicherzustellen, dass die Klasse jetzt wirklich mit der Serialisierung nicht kompatibel ist. was laut Spezifikation ziemlich schwer zu erreichen ist; (b) um ein Schema wie benutzerdefinierte read / writeObject () -Methoden, readResolve / writeReplace () -Methoden, serializableFields-Deklarationen usw. auszuprobieren, um sicherzustellen, dass der Stream kompatibel bleibt. Das Ist zu ändern serialVersionUIDist ein letzter Ausweg, ein Rat der Verzweiflung.
user207421
4
Das @ EJP-Inkrement der serialVersionUID wird angezeigt, wenn der Erstautor der Klasse dies explizit eingeführt hat. Ich würde sagen, die von jvm generierte serielle ID sollte in Ordnung sein. Dies ist die beste Antwort , die ich bei der Serialisierung gesehen habe.
Überaustausch
307

Ich kann diese Gelegenheit nicht verpassen, um Josh Blochs Buch Effective Java (2nd Edition) anzuschließen . 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. Wenn Sie diese in irgendeiner Weise ändern, ändert sich die serialVersionUID. Sie müssen sich also nicht nur mit ihnen herumschlagen, 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 auf irgendeine Weise ändern müssen, aber die Kompatibilität mit der alten Version der Klasse beibehalten müssen, können Sie mit dem JDK-Tool serialver die serialVersionUIDfür die alte Klasse generieren und diese explizit festlegen auf die neue Klasse. (Abhängig von Ihren Änderungen müssen Sie möglicherweise auch eine benutzerdefinierte Serialisierung durch Hinzufügen writeObjectund readObjectMethoden implementieren - siehe SerializableJavadoc oder das oben genannte Kapitel 11.)

Scott Bale
quelle
33
Man könnte sich also mit SerializableVersionUID beschäftigen, wenn man sich Gedanken über die Kompatibilität mit alten Versionen einer Klasse macht?
Ziggy
10
Ja, falls die neuere Version ein öffentliches Mitglied in "geschützt" ändert, ist die Standard-SerializableVersionUID anders und löst eine InvalidClassExceptions aus.
Chander Shivdasani
3
Klassenname, implementierte Schnittstellen, alle öffentlichen und geschützten Methoden, ALLE Instanzvariablen.
Achow
31
Es ist erwähnenswert, dass Joshua Bloch empfiehlt, für jede serialisierbare Klasse die serielle Versions-UID anzugeben. Zitat aus Kapitel 11: Unabhängig von der gewählten serialisierten Form deklarieren Sie in jeder serialisierbaren Klasse, die Sie schreiben, eine explizite UID der seriellen Version. Dadurch wird die UID der seriellen Version als potenzielle Inkompatibilitätsquelle eliminiert (Punkt 74). Es gibt auch einen kleinen Leistungsvorteil. Wenn keine UID der seriellen Version bereitgestellt wird, ist eine teure Berechnung erforderlich, um eine zur Laufzeit zu generieren.
Ashutosh Jindal
136

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 viele andere Warnungen, die Sie in diesem Abschnitt aktivieren können (oder die sogar als Fehler gemeldet werden). Viele sind sehr nützlich:

  • Mögliche Programmierprobleme: Mögliche versehentliche boolesche Zuweisung
  • Mögliche Programmierprobleme: Nullzeigerzugriff
  • Unnötiger Code: Lokale Variable wird nie gelesen
  • Unnötiger Code: Redundante Nullprüfung
  • Unnötiger Code: Unnötige Besetzung oder 'Instanz von'

und viele mehr.

matt b
quelle
21
Upvote, aber nur, weil das Originalplakat nichts zu serialisieren scheint. Wenn auf dem Plakat steht "Ich serialisiere dieses Ding und ...", erhalten Sie stattdessen eine Abstimmung: P
John Gardner
3
Richtig - ich ging davon aus, dass der Fragesteller einfach nicht gewarnt werden wollte
matt b
14
@ Gardner -> vereinbart! Der Fragesteller möchte aber auch wissen, warum er möglicherweise nicht gewarnt werden möchte.
Ziggy
8
Der Fragesteller kümmert sich offensichtlich darum, warum es eine UID geben sollte. Es sollte also abgelehnt werden, ihm einfach zu sagen, er solle die Warnung ignorieren.
cinqS
111

serialVersionUIDErleichtert die Versionierung serialisierter Daten. Sein Wert wird bei der Serialisierung mit den Daten gespeichert. Bei der De-Serialisierung wird dieselbe Version überprüft, um festzustellen, wie die serialisierten Daten mit dem aktuellen Code übereinstimmen.

Wenn Sie Ihre Daten versionieren möchten, beginnen Sie normalerweise mit einer serialVersionUID0 und stoßen sie bei jeder strukturellen Änderung Ihrer Klasse an, die die serialisierten Daten ändert (Hinzufügen oder Entfernen nicht vorübergehender Felder).

Der integrierte De-Serialisierungsmechanismus ( in.defaultReadObject()) verweigert die De-Serialisierung von alten Versionen der Daten. Wenn Sie möchten, können Sie Ihre eigene readObject () -Funktion definieren, mit der alte Daten zurückgelesen werden können. Dieser benutzerdefinierte Code kann dann überprüfen, serialVersionUIDin welcher Version sich die Daten befinden, und entscheiden, wie sie de-serialisiert werden sollen. Diese Versionierungstechnik ist nützlich, wenn Sie serialisierte Daten speichern, die mehrere Versionen Ihres Codes überleben.

Das Speichern von serialisierten Daten über einen so langen Zeitraum ist jedoch nicht sehr verbreitet. Es ist weitaus üblicher, den Serialisierungsmechanismus zu verwenden, um Daten vorübergehend in beispielsweise einen Cache zu schreiben oder ü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 Abwärtskompatibilität aufrechtzuerhalten. Sie müssen nur sicherstellen, dass die kommunizierenden Codebasen tatsächlich dieselben Versionen der relevanten Klassen haben. Um eine solche Überprüfung zu vereinfachen, müssen Sie das serialVersionUIDGleiche wie zuvor beibehalten 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 derselben serialVersionUID. In diesem Fall erkennt der Standardmechanismus ( in.defaultReadObject()) keinen Unterschied und versucht, inkompatible Daten zu de-serialisieren. Jetzt kann es zu einem kryptischen Laufzeitfehler oder einem stillen Fehler (Nullfelder) kommen. Diese Arten von Fehlern sind möglicherweise schwer zu finden.

Um diesen Anwendungsfall zu erleichtern, bietet Ihnen die Java-Plattform die Möglichkeit, die Einstellung nicht serialVersionUIDmanuell vorzunehmen . Stattdessen wird zur Kompilierungszeit ein Hash der Klassenstruktur generiert und als ID verwendet. Dieser Mechanismus stellt sicher, dass Sie niemals unterschiedliche Klassenstrukturen mit derselben ID haben, sodass diese oben erwähnten schwer nachvollziehbaren Laufzeit-Serialisierungsfehler nicht auftreten.

Die automatisch generierte ID-Strategie hat jedoch einen Nachteil. Das heißt, dass sich die generierten IDs für dieselbe Klasse zwischen den Compilern unterscheiden können (wie oben von Jon Skeet erwähnt). Wenn Sie also serialisierte Daten zwischen Code kommunizieren, der mit verschiedenen Compilern kompiliert wurde, wird empfohlen, die IDs ohnehin manuell zu verwalten.

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

Alexander Torstling
quelle
4
Das Hinzufügen oder Entfernen nicht vorübergehender Felder macht die Serialisierung der Klasse nicht inkompatibel. Es gibt daher keinen Grund, solche Änderungen zu ändern.
user207421
4
@EJP: Huh? Das Hinzufügen von Daten ändert definitiv die Serialisierungsdaten in meiner Welt.
Alexander Torstling
3
@AlexanderTorstling Lesen Sie, was ich geschrieben habe. Ich habe nicht gesagt, dass es die Serialisierungsdaten nicht ändert. Ich sagte, es macht die Klassenserialisierung nicht inkompatibel. Es ist nicht dasselbe. Sie müssen das Kapitel Versionierung der Objektserialisierungsspezifikation lesen.
user207421
3
@EJP: Mir ist klar, dass das Hinzufügen eines nicht vorübergehenden Feldes nicht unbedingt bedeutet, dass Sie die Klassenserialisierung inkompatibel machen, aber es ist eine strukturelle Änderung, die die serialisierten Daten ändert, und Sie möchten normalerweise die Version stoßen, wenn Sie dies tun, es sei denn, Sie behandeln Abwärtskompatibilität, die ich auch später in der Post erklärt habe. Was genau ist dein Punkt?
Alexander Torstling
4
Mein Punkt bleibt genau das, was ich gesagt habe. Das Hinzufügen oder Entfernen nicht vorübergehender Felder macht die Klasse Serialization nicht inkompatibel. Sie müssen daher die serialVersionUID nicht jedes Mal anstoßen, wenn Sie dies tun.
user207421
72

Was ist eine serialVersionUID und warum sollte ich sie verwenden?

SerialVersionUIDist eine eindeutige Kennung für jede Klasse, JVMmit der die Versionen der Klasse verglichen werden, um sicherzustellen, dass dieselbe Klasse während der Serialisierung verwendet wurde und während der Deserialisierung geladen wird.

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

Die JavadocsSerializable sagen zum Beispiel :

Die standardmäßige serialVersionUID-Berechnung reagiert sehr empfindlich auf Klassendetails, die je nach Compiler-Implementierung variieren können, und kann daher InvalidClassExceptionwährend der Deserialisierung zu unerwarteten s führen.

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

Dieser Artikel enthält einige gute Punkte zum Thema.

Thalaivar
quelle
3
@Vinothbabu, aber serialVersionUID ist statisch, sodass statische Variablen nicht serialisiert werden können. Wie kommt es dann, dass JVM die Version überprüft, ohne zu wissen, was die Version des deserialisierenden Objekts ist
Kranthi Sama
3
Die eine Sache, die in dieser Antwort nicht erwähnt wird, ist, dass Sie unbeabsichtigte Konsequenzen haben können, indem Sie blind einschließen, serialVersionUIDohne zu wissen warum. Tom Andersons Kommentar zur Antwort von MetroidFan2002 lautet wie folgt: "Ich würde sagen, wenn Sie die Serialisierung nicht für die dauerhafte Speicherung verwenden, sollten Sie @SuppressWarnings verwenden, anstatt einen Wert hinzuzufügen. Dadurch wird die Klasse weniger überladen, und die Fähigkeit der serialVersionUID-Mechanismus zum Schutz vor inkompatiblen Änderungen. "
Kirby
7
serialVersionUIDist keine "eindeutige Kennung für jede Klasse". Der vollqualifizierte Klassenname ist das. Es ist ein Versionsindikator .
user207421
58

In der ursprünglichen Frage wurde nach "Warum ist es wichtig" und "Beispiel" gefragt, wo dies Serial Version IDnützlich wäre. Nun, ich habe einen gefunden.

Angenommen, Sie erstellen eine CarKlasse, instanziieren sie und schreiben sie in einen Objektstrom. Das abgeflachte Autoobjekt befindet sich einige Zeit im Dateisystem. In der Zwischenzeit, wenn die CarKlasse durch Hinzufügen eines neuen Feldes geändert wird. Wenn Sie später versuchen, das abgeflachte CarObjekt zu lesen (dh zu deserialisieren) , erhalten Sie das java.io.InvalidClassException- weil alle serialisierbaren Klassen automatisch eine eindeutige Kennung erhalten. Diese Ausnahme wird ausgelöst, wenn der Bezeichner der Klasse nicht dem Bezeichner des abgeflachten Objekts entspricht. Wenn Sie wirklich darüber nachdenken, wird die Ausnahme aufgrund des Hinzufügens des neuen Felds ausgelöst. Sie können diese Ausnahme vermeiden, indem Sie die Versionierung selbst steuern, indem Sie eine explizite serialVersionUID deklarieren. Es gibt auch einen kleinen Leistungsvorteil, wenn Sie Ihre explizit angebenserialVersionUID(weil nicht berechnet werden muss). Es wird daher empfohlen, Ihren serialisierbaren Klassen eine eigene serialVersionUID hinzuzufügen, sobald Sie sie wie unten gezeigt erstellen:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}
Rupesh
quelle
Und man sollte jeder UID eine zufällige lange Zahl zuweisen, nicht 1L.
Abbas
4
@abbas 'Man sollte' das tun warum? Bitte erklären Sie, welchen Unterschied es macht.
user207421
Wie der Name schon sagt, handelt es sich um die Version der Klasse, mit der das Objekt serialisiert wurde. Wenn Sie ihm jedes Mal dieselbe Nummer zuweisen, finden Sie nicht die richtige Klasse, um sie zu de-serialisieren. Wenn Sie also eine Änderung in der Klasse vornehmen, ist es besser, auch die Version zu ändern.
Abbas
2
@abbas, diese Absicht kollidiert nicht mit der Verwendung von inkrementierenden natürlichen Zahlen von 1und so weiter.
Vadzim
2
@ BillK, ich dachte, die Serialisierungsprüfung ist an das Paar aus Klassenname und serialVersionUID gebunden. Daher können unterschiedliche Nummerierungsschemata verschiedener Klassen und Bibliotheken in keiner Weise stören. Oder haben Sie Code-generierende Bibliotheken impliziert?
Vadzim
44

Zuerst muss ich erklären, was Serialisierung ist.

Durch die Serialisierung kann ein Objekt in einen Stream konvertiert werden, um dieses Objekt über das Netzwerk zu senden ODER in einer Datei zu speichern ODER zur Verwendung in Briefen in der Datenbank zu speichern.

Es gibt einige Regeln für die Serialisierung .

  • Ein Objekt ist nur dann serialisierbar, wenn seine Klasse oder seine Oberklasse die Schnittstelle Serializable implementiert

  • Ein Objekt ist serialisierbar (selbst implementiert die serialisierbare Schnittstelle), auch wenn seine Oberklasse dies nicht ist. Die erste Oberklasse in der Hierarchie der serialisierbaren Klasse, die keine serialisierbare Schnittstelle implementiert, MUSS jedoch einen Konstruktor ohne Argumente haben. Wenn dies verletzt wird, erzeugt readObject () zur Laufzeit eine java.io.InvalidClassException

  • Alle primitiven Typen sind serialisierbar.

  • Übergangsfelder (mit Übergangsmodifikator) werden NICHT serialisiert (dh nicht gespeichert oder wiederhergestellt). Eine Klasse, die Serializable implementiert, muss vorübergehende Felder von Klassen markieren, die keine Serialisierung unterstützen (z. B. einen Dateistream).

  • Statische Felder (mit statischem Modifikator) werden nicht serialisiert.

Bei der ObjectSerialisierung verknüpft Java Runtime die Serienversionsnummer aka, the serialVersionID.

Wo wir serialVersionID benötigen: Während der Deserialisierung, um zu überprüfen, ob Sender und Empfänger in Bezug auf die Serialisierung kompatibel sind. Wenn der Empfänger die Klasse mit einem anderen geladen hat,serialVersionIDendet die Deserialisierung mitInvalidClassCastException.
Eine serialisierbare Klasse kann ihre eigeneserialVersionUIDexplizit deklarieren, indem sie ein Feld mit dem Namen deklariertserialVersionUID, das statisch, endgültig und vom Typ long sein muss.

Versuchen wir dies anhand eines Beispiels.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Serialisierungsobjekt erstellen

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserialisieren Sie das Objekt

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

HINWEIS: Ändern Sie nun die serialVersionUID der Employee-Klasse und speichern Sie:

private static final long serialVersionUID = 4L;

Und führen Sie die Reader-Klasse aus. Wenn Sie die Writer-Klasse nicht ausführen, wird die Ausnahme angezeigt.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
JegsVala
quelle
Korrigieren Sie mich, wenn ich falsch liege - die lokale Klasse ist diejenige, die Sie derzeit im Klassenpfad haben / verwenden, und die Stream-Klasse ist diejenige, die von einer anderen Partei verwendet wird (z. B. einem Server, der Ihnen eine Antwort zurückgibt und die serialisiert hat Antwort). Diese Situation kann auftreten, wenn Sie mit einem Server kommunizieren, der die Bibliotheken von Drittanbietern aktualisiert hat, dies jedoch nicht getan hat.
Victor
37

Wenn Sie Ihre Objekte niemals in ein Byte-Array serialisieren und senden / speichern müssen, müssen Sie sich darüber keine Gedanken machen. Wenn Sie dies tun, müssen Sie Ihre serialVersionUID berücksichtigen, da der Deserializer des Objekts sie an die Version des Objekts anpasst, über das der Klassenlader verfügt. Weitere Informationen finden Sie in der Java-Sprachspezifikation.

eishay
quelle
10
Wenn Sie die Objekte nicht serialisieren möchten, warum sind sie dann serialisierbar?
erickson
7
@erickson - Die übergeordnete Klasse ist möglicherweise serialisierbar, z. B. ArrayList. Sie möchten jedoch, dass Ihr eigenes Objekt (z. B. eine geänderte Array-Liste) es als Basis verwendet, die von Ihnen erstellte Sammlung jedoch niemals serialisiert.
MetroidFan2002
5
Es wird nirgendwo in der Java-Sprachspezifikation erwähnt. Es wird in der Objektversionierungsspezifikation erwähnt.
user207421
4
Hier ist der Link zur Java 8- Objektversionierungsspezifikation .
Basil Bourque
34

Wenn Sie diese Warnung für eine Klasse erhalten, an die Sie nie gedacht haben und die Sie nicht deklariert haben implements Serializable, liegt dies häufig daran, dass Sie von einer Oberklasse geerbt haben, die Serializable implementiert. Oft ist es dann besser, an ein solches Objekt zu delegieren, als die Vererbung zu verwenden.

Also statt

public class MyExample extends ArrayList<String> {

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

tun

public class MyExample {
    private List<String> myList;

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

und in den entsprechenden Methoden myList.foo()anstelle von this.foo()(oder super.foo()) aufrufen . (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 an dieses delegieren müssen. (Dies hilft auch bei der automatischen Vervollständigung in einer IDE, da JFrame über Hunderte von Methoden verfügt, die Sie nicht benötigen, wenn Sie Ihre benutzerdefinierten Methoden in Ihrer Klasse aufrufen möchten.)

Ein Fall, in dem die Warnung (oder die serialVersionUID) unvermeidbar ist, besteht darin, dass Sie von AbstractAction aus, normalerweise in einer anonymen Klasse, nur die actionPerformed-Methode hinzufügen. Ich denke, in diesem Fall sollte es keine Warnung geben (da Sie solche anonymen Klassen normalerweise ohnehin nicht zuverlässig für verschiedene Versionen Ihrer Klasse serialisieren und deserialisieren können), aber ich bin mir nicht sicher, wie der Compiler dies erkennen könnte.

Paŭlo Ebermann
quelle
4
Ich denke, Sie haben Recht, dass Komposition über Inhneritance sinnvoller ist, insbesondere wenn Sie Klassen wie ArrayList diskutieren. Bei vielen Frameworks müssen Benutzer jedoch von abstrakten Superklassen ausgehen, die serialisierbar sind (z. B. die ActionForm-Klasse von Struts 1.2 oder die ExtensionFunctionDefinition von Saxon). In diesem Fall ist diese Lösung nicht durchführbar. Ich denke, Sie haben Recht, es wäre schön, wenn die Warnung in bestimmten Fällen ignoriert würde (z. B. wenn Sie von einer abstrakten serialisierbaren Klasse ausgehen)
piepera
2
Wenn Sie eine Klasse als Mitglied hinzufügen, anstatt von ihr zu erben, müssten Sie sicherlich eine Wrapper-Methode für JEDE Methode der Mitgliedsklasse schreiben, die Sie verwenden möchten, was es in einer Vielzahl von Situationen unmöglich machen würde. Es sei denn, Java hat eine ähnliche Funktion wie Perl __AUTOLOAD, von der ich nichts weiß.
M_M
4
@M_M: Wenn Sie viele Methoden an Ihr umschlossenes Objekt delegieren würden, wäre es natürlich nicht angebracht, die Delegierung zu verwenden. Aber ich nehme an, dass dieser Fall ein Zeichen für einen Entwurfsfehler ist - die Benutzer Ihrer Klasse (z. B. "MainGui") sollten nicht viele Methoden des umschlossenen Objekts (z. B. JFrame) aufrufen müssen.
Paŭlo Ebermann
1
Was ich an der Delegation nicht mag, ist die Notwendigkeit, einen Verweis auf den Delegierten zu halten. Und jede Referenz bedeutet mehr Speicher. Korrigiere mich, wenn ich falsch liege. Wenn ich eine CustomizedArrayList mit 100 Objekten benötige, ist dies nicht besonders wichtig. Wenn ich jedoch Hunderte von CustomizdeArrayLists mit wenigen Objekten benötige, steigt die Speichernutzung erheblich an.
WVrock
2
Throwable ist serialisierbar und nur Throwable ist Throwable. Daher kann keine Ausnahme definiert werden, die nicht serialisierbar ist. Eine Delegierung ist nicht möglich.
Phil
22

Um die Bedeutung des Feldes serialVersionUID zu verstehen, sollte man verstehen, wie Serialisierung / Deserialisierung funktioniert.

Wenn ein serialisierbares Klassenobjekt serialisiert wird, ordnet Java Runtime diesem serialisierten Objekt eine serielle Versionsnummer (als serialVersionUID bezeichnet) zu. Zum Zeitpunkt der Deserialisierung dieses serialisierten Objekts stimmt Java Runtime die serialVersionUID des serialisierten Objekts mit der serialVersionUID der Klasse ab. Wenn beide gleich sind, wird nur der weitere Deserialisierungsprozess fortgesetzt, andernfalls wird InvalidClassException ausgelöst.

Wir schließen daraus, dass die serialVersionUID des serialisierten Objekts der serialVersionUID der Klasse entsprechen muss, um den Serialisierungs- / Deserialisierungsprozess erfolgreich zu machen. Wenn der Programmierer den serialVersionUID-Wert explizit im Programm angibt, wird der serialisierte Objekt und die Klasse unabhängig von der Serialisierungs- und Deserialisierungsplattform derselbe Wert zugeordnet (z. B. kann die Serialisierung auf einer Plattform wie Windows mithilfe von sun oder erfolgen MS JVM und Deserialization befinden sich möglicherweise auf einer anderen Linux-Plattform (unter Verwendung von Zing JVM).

Wenn jedoch serialVersionUID vom Programmierer nicht angegeben wird, verwendet die Java-Laufzeit während der Serialisierung \ DeSerialisierung eines Objekts einen eigenen Algorithmus, um es zu berechnen. Dieser SerialVersionUID-Berechnungsalgorithmus variiert von JRE zu JRE. Es ist auch möglich, dass die Umgebung, in der das Objekt serialisiert wird, eine JRE verwendet (z. B. SUN JVM) und die Umgebung, in der die Deserialisierung erfolgt, Linux Jvm (zing) verwendet. In solchen Fällen unterscheidet sich die dem serialisierten Objekt zugeordnete serialVersionUID von der serialVersionUID der Klasse, die in der Deserialisierungsumgebung berechnet wurde. Die Deserialisierung wird wiederum nicht erfolgreich sein. Um solche Situationen / Probleme zu vermeiden, muss der Programmierer immer die serialVersionUID der Klasse Serializable angeben.

Nitesh Soni
quelle
2
Der Algorithmus variiert nicht, ist jedoch leicht unterbestimmt.
user207421
... der Algorithmus variiert nicht, aber er ist leicht unterbestimmt ... was bedeutet, dass jeder JVM variieren kann ..... @ user207421
AnthonyJClink
18

Keine Sorge, die Standardberechnung ist wirklich gut und reicht für 99.9999% der Fälle aus. Und wenn Sie auf Probleme stoßen, können Sie - wie bereits erwähnt - UIDs als Bedarfsermittlung einführen (was höchst unwahrscheinlich ist).

Grand Johnson
quelle
2
Müll. Dies ist ausreichend, wenn sich die Klasse nicht geändert hat. Sie haben keine Beweise für die Unterstützung von '99 .9999% '.
user207421
18

Ein Beispiel, bei dem die fehlende serialVersionUID ein Problem verursachen könnte:

Ich arbeite an dieser Java EE-Anwendung, die aus einem Webmodul besteht, das ein EJBModul verwendet. Das Webmodul ruft das EJBModul remote auf und übergibt ein POJO, das Serializableals Argument implementiert wird .

Diese POJO'sKlasse wurde in das EJB-JAR und in das eigene JAR in der WEB-INF / lib des Webmoduls gepackt. Sie sind eigentlich die gleiche Klasse, aber wenn ich das EJB-Modul verpacke, entpacke ich das Glas dieses POJO, um es zusammen mit dem EJB-Modul zu verpacken.

Der Anruf bei der schlug EJBmit der folgenden Ausnahme fehl, weil ich nicht erklärt hatte serialVersionUID:

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52
Henrique Ordine
quelle
16

Ich verwende serialVersionUIDim Allgemeinen in einem Kontext: Wenn ich weiß, dass es den Kontext der Java-VM verlässt.

Ich würde dies wissen, wenn ich es verwenden möchte ObjectInputStreamund ObjectOutputStreamfür meine Anwendung oder wenn ich weiß, dass eine Bibliothek / ein Framework, das ich verwende, es verwenden wird. Die serialVersionID stellt sicher, dass verschiedene Java-VMs unterschiedlicher Versionen oder Anbieter ordnungsgemäß zusammenarbeiten. Wenn sie beispielsweise außerhalb der VM gespeichert und abgerufen HttpSessionwerden, können die Sitzungsdaten auch während eines Neustarts und eines Upgrades des Anwendungsservers erhalten bleiben.

Für alle anderen Fälle verwende ich

@SuppressWarnings("serial")

da die meiste Zeit die Standardeinstellung serialVersionUIDausreicht. Dies beinhaltet Exception, HttpServlet.

Archimedes Trajano
quelle
HttpServlet ist nicht in Containern enthalten, in denen sie ausgetauscht werden können, oder beispielsweise Ausnahmen in RMI.
user207421
14

Felddaten repräsentieren einige in der Klasse gespeicherte Informationen. Die Klasse implementiert die SerializableSchnittstelle, sodass Eclipse automatisch anbietet, das serialVersionUIDFeld zu deklarieren . Beginnen wir mit dem dort eingestellten Wert 1.

Wenn diese Warnung nicht angezeigt werden soll, verwenden Sie Folgendes:

@SuppressWarnings("serial")
Mukti
quelle
11

Es wäre schön, wenn CheckStyle überprüfen könnte, ob die serialVersionUID für eine Klasse, die Serializable implementiert, einen guten Wert hat, dh mit dem übereinstimmt, was der ID-Generator für die serielle Version erzeugen würde. Wenn Sie beispielsweise ein Projekt mit vielen serialisierbaren DTOs haben und daran denken, die vorhandene serialVersionUID zu löschen und neu zu generieren, ist dies ein Problem. Derzeit ist die einzige (mir bekannte) Möglichkeit, dies zu überprüfen, die Regenerierung für jede Klasse und der Vergleich mit das Alte. Das ist sehr sehr schmerzhaft.


quelle
8
Wenn Sie die serialVersionUID immer auf den gleichen Wert einstellen, den der Generator erzeugen würde, brauchen Sie ihn überhaupt nicht. Schließlich ist es das Ziel, nach Änderungen gleich zu bleiben, wenn die Klasse noch kompatibel ist.
Paŭlo Ebermann
4
Der Grund dafür ist, dass verschiedene Compiler denselben Wert für dieselbe Klasse liefern. Wie in den Javadocs (ebenfalls oben beantwortet) erläutert, ist die generierte Version spröde und kann variieren, selbst wenn die Klasse ordnungsgemäß deserialisierbar ist. Solange Sie diesen Test jedes Mal auf demselben Compiler ausführen, sollte er sicher sein. Gott helfe dir, wenn du das JDK aktualisierst und eine neue Regel herauskommt, obwohl sich dein Code nicht geändert hat.
Andrew Backer
2
Es muss nicht übereinstimmen, was serialverproduzieren würde. -1
user207421
Im Allgemeinen ist es überhaupt nicht erforderlich. @ AndrewBackers Fall würde zwei verschiedene Compiler in derselben .java-Datei erfordern, wobei beide Versionen der .class-Dateien miteinander kommunizieren - meistens erstellen Sie nur die Klasse und verteilen sie. Wenn dies der Fall ist, würde es gut funktionieren, keine SUID zu haben.
Bill K
1
Personen, die die Serialisierung wirklich zum Speichern / Abrufen verwenden, setzen im Allgemeinen den Wert serialVersionUIDauf 1. Wenn eine neuere Version der Klasse nicht kompatibel ist, aber dennoch in der Lage sein muss, mit den alten Daten umzugehen, erhöhen Sie die Versionsnummer und fügen speziellen Code hinzu beschäftigen sich mit älteren Formaten. Ich weine jedes Mal, wenn ich eine serialVersionUIDZiffer größer als 1 sehe , entweder weil es eine Zufallszahl war (nutzlos) oder weil die Klasse anscheinend mit mehr als 10 verschiedenen Versionen umgehen muss.
John16384
11

SerialVersionUID wird zur Versionskontrolle des Objekts verwendet. Sie können serialVersionUID auch in Ihrer Klassendatei angeben. Wenn Sie die serialVersionUID nicht angeben, kann die bereits serialisierte Klasse beim Hinzufügen oder Ändern eines Felds in der Klasse nicht wiederhergestellt werden, da die für die neue Klasse und das alte serialisierte Objekt generierte serialVersionUID unterschiedlich ist. Der Java-Serialisierungsprozess basiert auf der korrekten serialVersionUID, um den Status des serialisierten Objekts wiederherzustellen, und löst bei Nichtübereinstimmung von serialVersionUID die Ausnahme java.io.InvalidClassException aus

Lesen Sie mehr: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ

Neethu
quelle
9

Warum SerialVersionUIDInside SerializableClass in Java verwenden?

Während der serializationJava-Laufzeit wird eine Versionsnummer für eine Klasse erstellt, damit diese später de-serialisiert werden kann. Diese Versionsnummer ist SerialVersionUIDin Java bekannt.

SerialVersionUIDwird verwendet, um serialisierte Daten zu versionieren. Sie können eine Klasse nur de-serialisieren, wenn sie SerialVersionUIDmit der serialisierten Instanz übereinstimmt. Wenn wir SerialVersionUIDin unserer Klasse nicht deklarieren , generiert die Java-Laufzeit es für uns, aber es wird nicht empfohlen. Es wird empfohlen, SerialVersionUIDals private static final longVariable zu deklarieren , um den Standardmechanismus zu vermeiden.

Wenn Sie eine Klasse wie Serializabledurch Implementieren der Markierungsschnittstelle deklarieren, java.io.Serializablebleibt die Java-Laufzeitinstanz dieser Klasse mithilfe des Standard-Serialisierungsmechanismus auf der Festplatte erhalten, sofern Sie den Prozess nicht über die ExternalizableSchnittstelle angepasst haben .

Siehe auch Warum SerialVersionUID in der Serializable-Klasse in Java verwenden?

Roottraveller
quelle
8

Wenn Sie eine große Anzahl von Klassen ändern möchten, für die zunächst keine serialVersionUID festgelegt wurde, und gleichzeitig die Kompatibilität mit den alten Klassen beibehalten möchten, sind Tools wie IntelliJ Idea und Eclipse nicht ausreichend, da sie Zufallszahlen generieren und nicht für eine Reihe von Dateien funktionieren auf einmal. Ich rufe das folgende Bash-Skript auf (es tut mir leid für Windows-Benutzer, erwäge, einen Mac zu kaufen oder auf Linux zu konvertieren), um das Problem mit serialVersionUID mühelos zu ändern:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    perl -ni.bak -e "print $_; printf qq{%s\n}, q{    private $seruidstr} if /public class/" $src_dir/$f
done

Wenn Sie dieses Skript speichern, sagen Sie add_serialVersionUID.sh zu Ihnen ~ / bin. Anschließend führen Sie es im Stammverzeichnis Ihres Maven- oder Gradle-Projekts wie folgt aus:

add_serialVersionUID.sh < myJavaToAmend.lst

Diese .lst enthält die Liste der Java-Dateien zum Hinzufügen der serialVersionUID im folgenden Format:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

Dieses Skript verwendet das JDK serialVer-Tool unter der Haube. Stellen Sie also sicher, dass sich Ihr $ JAVA_HOME / bin im PATH befindet.

schnell18
quelle
2
Gibt mir eine Idee: Generieren Sie die Serien-UID immer mit einem Tool wie diesem neu, niemals von Hand, bevor Sie eine Veröffentlichung vornehmen. Auf diese Weise vergessen Sie nicht, Änderungen an einer Klasse vorzunehmen, deren Serien-UID aufgrund einer tatsächlichen Version hätte geändert werden müssen inkompatible Änderung. Das manuell zu verfolgen ist sehr schwierig.
Ignazio
6

Diese Frage ist in Effective Java von Joshua Bloch sehr gut dokumentiert. Ein sehr gutes Buch und ein Muss. Ich werde einige der folgenden Gründe skizzieren:

Die Serialisierungslaufzeit enthält für jede serialisierbare Klasse eine Nummer namens Serial version. Diese Nummer heißt serialVersionUID. Jetzt steckt etwas Mathematik hinter dieser Zahl und sie basiert auf den Feldern / Methoden, die in der Klasse definiert sind. Für dieselbe Klasse wird jedes Mal dieselbe Version generiert. Diese Nummer wird während der Deserialisierung verwendet, um zu überprüfen, ob der Sender und der Empfänger eines serialisierten Objekts Klassen für dieses Objekt geladen haben, die hinsichtlich der Serialisierung kompatibel sind. Wenn der Empfänger eine Klasse für das Objekt geladen hat, das eine andere serialVersionUID als die der entsprechenden Absenderklasse hat, führt die Deserialisierung zu einer InvalidClassException.

Wenn die Klasse serialisierbar ist, können Sie Ihre eigene serialVersionUID auch explizit deklarieren, indem Sie ein Feld mit dem Namen "serialVersionUID" deklarieren, das statisch, endgültig und vom Typ long sein muss. Die meisten IDEs wie Eclipse helfen Ihnen dabei, diese lange Zeichenfolge zu generieren.

Geek
quelle
6

Jedes Mal, wenn ein Objekt serialisiert wird, wird das Objekt mit einer Versions-ID-Nummer für die Klasse des Objekts versehen. Diese ID heißt serialVersionUID und wird basierend auf Informationen über die Klassenstruktur berechnet. Angenommen, Sie haben eine Employee-Klasse erstellt und sie hat die Versions-ID # 333 (von JVM zugewiesen). Wenn Sie nun das Objekt dieser Klasse serialisieren (Angenommen, Employee-Objekt), weist JVM ihr die UID als # 333 zu.

Stellen Sie sich eine Situation vor - in Zukunft müssen Sie Ihre Klasse bearbeiten oder ändern. In diesem Fall weist JVM ihr beim Ändern eine neue UID zu (Angenommen, Nr. 444). Wenn Sie nun versuchen, das Mitarbeiterobjekt zu deserialisieren, vergleicht JVM die Versions-ID (# 333) des serialisierten Objekts (Mitarbeiterobjekt) mit der der Klasse, dh # 444 (da es geändert wurde). Im Vergleich stellt JVM fest, dass beide UID-Versionen unterschiedlich sind und die Deserialisierung daher fehlschlägt. Daher, wenn die serialVersionID für jede Klasse vom Programmierer selbst definiert wird. Dies gilt auch dann, wenn die Klasse in Zukunft weiterentwickelt wird. Daher stellt JVM immer fest, dass die Klasse mit serialisierten Objekten kompatibel ist, obwohl die Klasse geändert wird. Weitere Informationen finden Sie in Kapitel 14 von HEAD FIRST JAVA.

Naved Ali
quelle
1
Jedes Mal, wenn die Klasse eines Objekts serialisiert serialVersionUIDwird, wird das übertragen. Es wird nicht mit jedem Objekt gesendet.
user207421
3

Eine einfache Erklärung:

  1. Serialisieren Sie Daten?

    Bei der Serialisierung werden im Grunde Klassendaten in eine Datei / einen Stream / etc. Geschrieben. Bei der De-Serialisierung werden diese Daten in eine Klasse zurückgelesen.

  2. Beabsichtigen Sie, in Produktion zu gehen?

    Wenn Sie nur etwas mit unwichtigen / gefälschten Daten testen, machen Sie sich darüber keine Sorgen (es sei denn, Sie testen die Serialisierung direkt).

  3. Ist das die erste Version?

    Wenn ja, setzen Sie serialVersionUID=1L.

  4. Ist dies die zweite, dritte usw. Produktversion?

    Jetzt müssen Sie sich Sorgen machen serialVersionUIDund sollten sich eingehend damit befassen.

Wenn Sie die Version beim Aktualisieren einer Klasse, die Sie schreiben / lesen müssen, nicht korrekt aktualisieren, wird im Grunde eine Fehlermeldung angezeigt, wenn Sie versuchen, alte Daten zu lesen.

gagarwa
quelle
2

'serialVersionUID' ist eine 64-Bit-Nummer, mit der eine Klasse während des Deserialisierungsprozesses eindeutig identifiziert wird. Wenn Sie ein Objekt serialisieren, wird auch die serialVersionUID der Klasse in die Datei geschrieben. Wenn Sie dieses Objekt deserialisieren, extrahiert die Java-Laufzeit diesen serialVersionUID-Wert aus den serialisierten Daten und vergleicht denselben Wert, der der Klasse zugeordnet ist. Wenn beide nicht übereinstimmen, wird 'java.io.InvalidClassException' ausgelöst.

Wenn eine serialisierbare Klasse eine serialVersionUID nicht explizit deklariert, berechnet die Serialisierungslaufzeit den serialVersionUID-Wert für diese Klasse basierend auf verschiedenen Aspekten der Klasse wie Feldern, Methoden usw. ,, Sie können diesen Link für eine Demoanwendung verwenden .

Hari Krishna
quelle
1

Um es kurz zu machen, dieses Feld wird verwendet, um zu überprüfen, ob serialisierte Daten korrekt deserialisiert werden können. Serialisierung und Deserialisierung werden häufig von verschiedenen Programmkopien durchgeführt. Beispielsweise konvertiert der Server das Objekt in eine Zeichenfolge und der Client konvertiert die empfangene Zeichenfolge in ein Objekt. Dieses Feld gibt an, dass beide mit derselben Vorstellung davon arbeiten, was dieses Objekt ist. Dieses Feld hilft, wenn:

  • Sie haben viele verschiedene Kopien Ihres Programms an verschiedenen Orten (wie 1 Server und 100 Clients). Wenn Sie Ihr Objekt ändern, Ihre Versionsnummer ändern und vergessen, einen dieser Clients zu aktualisieren, wird er wissen, dass er nicht in der Lage ist, zu deserialisieren

  • Sie haben Ihre Daten in einer Datei gespeichert und versuchen später, sie mit einer aktualisierten Version Ihres Programms mit geändertem Objekt zu öffnen. Sie werden wissen, dass diese Datei nicht kompatibel ist, wenn Sie Ihre Version richtig halten

Wann ist es wichtig

Am offensichtlichsten: Wenn Sie Ihrem Objekt einige Felder hinzufügen, können ältere Versionen diese nicht verwenden, da sie diese Felder nicht in ihrer Objektstruktur haben.

Weniger offensichtlich - Wenn Sie ein Objekt deserialisieren, werden Felder, die in der Zeichenfolge nicht vorhanden sind, als NULL beibehalten. Wenn Sie ein Feld aus Ihrem Objekt entfernt haben, behalten ältere Versionen dieses Feld als immer NULL bei, was zu Fehlverhalten führen kann, wenn ältere Versionen auf Daten in diesem Feld angewiesen sind (trotzdem haben Sie es für etwas erstellt, nicht nur zum Spaß :-)).

Am wenigsten offensichtlich - Manchmal ändern Sie die Idee, die Sie in die Bedeutung eines Feldes einfügen. Wenn Sie beispielsweise 12 Jahre alt sind, meinen Sie "Fahrrad" unter "Fahrrad", aber wenn Sie 18 Jahre alt sind, meinen Sie "Motorrad" - wenn Ihre Freunde Sie zu einer "Radtour durch die Stadt" einladen und Sie der einzige sind, der dies tut Wenn Sie mit dem Fahrrad gekommen sind, werden Sie verstehen, wie wichtig es ist, die gleiche Bedeutung über alle Felder hinweg beizubehalten :-)

Stanislav Orlov
quelle
1

Um Ihre Frage zu beantworten: Wenn wir SerialVersionUID in unserer Klasse nicht deklarieren, generiert die Java-Laufzeit diese für uns. Dieser Prozess reagiert jedoch empfindlich auf viele Klassen-Metadaten, einschließlich Anzahl der Felder, Feldtyp, Zugriffsmodifikator für Felder und implementierte Schnittstelle nach Klasse usw. Daher wird empfohlen, es selbst zu deklarieren, und Eclipse warnt Sie davor.

Serialisierung: Wir arbeiten häufig mit wichtigen Objekten, deren Status (Daten in den Variablen des Objekts) so wichtig ist, dass wir nicht riskieren können, sie aufgrund von Strom- / Systemfehlern (oder Netzwerkfehlern) zu verlieren, wenn der Objektstatus an andere gesendet wird Maschine. Die Lösung für dieses Problem heißt "Persistenz", was einfach bedeutet, dass die Daten beibehalten (gehalten / gespeichert) werden. Die Serialisierung ist eine von vielen anderen Möglichkeiten, um Persistenz zu erreichen (durch Speichern von Daten auf Festplatte / Speicher). Beim Speichern des Objektstatus ist es wichtig, eine Identität für das Objekt zu erstellen, um es ordnungsgemäß zurücklesen zu können (De-Serialisierung). Diese eindeutige Identifikation lautet ID ist SerialVersionUID.

Schäfte D Shiva
quelle
0

Was ist SerialVersionUID? Antwort: - Nehmen wir an, es gibt zwei Personen, eine vom Hauptquartier und eine vom ODC. Beide werden eine Serialisierung bzw. Deserialisierung durchführen. In diesem Fall erstellt JVM eine eindeutige ID, die als SerialVersionUID bezeichnet wird, um zu authentifizieren, dass der Empfänger in ODC die authentifizierte Person ist.

Hier ist eine schöne Erklärung basierend auf dem Szenario:

Warum SerialVersionUID?

Serialisierung : Zum Zeitpunkt der Serialisierung speichert JVM mit jeder Objektsenderseite eine eindeutige Kennung. JVM ist dafür verantwortlich, diese eindeutige ID basierend auf der entsprechenden .class-Datei zu generieren, die im Absendersystem vorhanden ist.

Deserialisierung : Zum Zeitpunkt der Deserialisierung vergleicht die empfängerseitige JVM die dem Objekt zugeordnete eindeutige ID mit der lokalen Klasse. Eindeutige ID, dh JVM erstellt auch eine eindeutige ID basierend auf der entsprechenden .class-Datei, die im Empfängersystem vorhanden ist. Wenn beide eindeutigen IDs übereinstimmen, wird nur eine Deserialisierung durchgeführt. Andernfalls erhalten wir eine Laufzeitausnahme mit der Aufschrift InvalidClassException. Diese eindeutige Kennung ist nichts anderes als SerialVersionUID

Forkdbloke
quelle