web-dev-qa-db-de.com

Was ist eine serialVersionUID und warum sollte ich sie verwenden?

Eclipse gibt Warnungen aus, wenn eine serialVersionUID fehlt. 

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

Was ist serialVersionUID und warum ist es wichtig? Bitte zeigen Sie ein Beispiel, bei dem das Fehlen von serialVersionUID ein Problem verursacht.

2664
ashokgelal

Die Dokumente für Java.io.Serializable sind wahrscheinlich so gut wie möglich:

Die Serialisierungslaufzeit ordnet jeder serialisierbaren Klasse eine Versionsnummer namens serialVersionUID zu. Diese 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, die eine andere serialVersionUID-Klasse als die Klasse des entsprechenden Senders hat, führt die Deserialisierung zu einer InvalidClassException . Eine serialisierbare Klasse kann ihre eigene serialVersionUID explizit deklarieren, indem sie ein Feld mit dem Namen serialVersionUID deklariert, das statisch, endgültig und vom Typ long sein muss:

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

Wenn eine serialisierbare Klasse einen serialVersionUID nicht explizit deklariert, berechnet die Serialisierungslaufzeit einen serialVersionUID-Standardwert für diese Klasse basierend auf verschiedenen Aspekten der Klasse, wie in der Java (TM) Object Serialization Specification beschrieben. Es ist jedoch dringend empfohlen, dass alle serialisierbaren Klassen explizit serialVersionUID-Werte deklarieren, da die Standardberechnung serialVersionUID sehr empfindlich auf Klassendetails reagiert, die je nach Implementierung des Compilers variieren können und daher während der Deserialisierung zu unerwarteten InvalidClassExceptions-Werten führen kann. Um einen konsistenten serialVersionUID-Wert über verschiedene Java-Compiler-Implementierungen hinweg zu gewährleisten, muss eine serialisierbare Klasse einen expliziten serialVersionUID-Wert deklarieren. Es wird außerdem dringend empfohlen, dass explizite serialVersionUID-Deklarationen soweit möglich den privaten Modifizierer verwenden, da solche Deklarationen nur für die sofort deklarierenden Klassen serialVersionUID-Felder gelten, die als geerbte Member nicht nützlich sind.

2039
Jon Skeet

Wenn Sie serialisieren, nur weil Sie aus Gründen der Implementierung serialisieren müssen (wen kümmert es, wenn Sie beispielsweise für ein HTTPSession serialisieren ... wenn es gespeichert ist oder nicht, ist de-serializing wahrscheinlich kein Formularobjekt) Sie können das ignorieren.

Wenn Sie die Serialisierung tatsächlich verwenden, ist es nur wichtig, wenn Sie Objekte direkt unter Verwendung der Serialisierung speichern und abrufen möchten. serialVersionUID steht für Ihre Klassenversion und Sie sollten diese erhöhen, wenn die aktuelle Version Ihrer Klasse nicht rückwärtskompatibel mit der vorherigen Version ist.

In den meisten Fällen verwenden Sie die Serialisierung wahrscheinlich nicht direkt. Wenn dies der Fall ist, generieren Sie einen Standardwert SerialVersionUID, indem Sie auf die Schnellkorrekturoption klicken, und machen Sie sich keine Sorgen.

431
MetroidFan2002

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.

Pro Josh wird die automatisch generierte UID basierend auf einem Klassennamen, implementierten Schnittstellen und allen öffentlichen und geschützten Mitgliedern generiert. Wenn Sie eines dieser Elemente auf irgendeine Weise ändern, wird serialVersionUID geändert. 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, können Sie das JDK-Tool serialver verwenden, um serialVersionUID auf dem alte-Klasse, und legen Sie dies explizit für die neue Klasse fest. (Abhängig von Ihren Änderungen müssen Sie möglicherweise auch eine benutzerdefinierte Serialisierung implementieren, indem Sie die Methoden writeObject und readObject hinzufügen - siehe Serializable javadoc oder zuvor genanntes Kapitel 11.)

279
Scott Bale

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

Fenster> Voreinstellungen> 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 sogar einige als Fehler gemeldet haben). Viele sind sehr nützlich:

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

und viele mehr.

126
matt b

serialVersionUID erleichtert die Versionierung serialisierter Daten. Ihr Wert wird beim Serialisieren mit den Daten gespeichert. Bei der Deserialisierung 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 einer serialVersionUID von 0 und ordnen diese bei jeder strukturellen Änderung Ihrer Klasse an, wodurch die serialisierten Daten geändert werden (nicht transiente Felder hinzufügen oder entfernen). 

Der eingebaute De-Serialisierungsmechanismus (in.defaultReadObject()) lehnt die Deserialisierung von alten Versionen der Daten ab. Wenn Sie möchten, können Sie jedoch eine eigene readObject () - Funktion definieren, die alte Daten zurücklesen kann. Dieser benutzerdefinierte Code kann dann die Variable serialVersionUID überprüfen, um herauszufinden, in welcher Version sich die Daten befinden, und zu entscheiden, wie sie deserialisiert werden sollen. Diese Versionierungstechnik ist nützlich, wenn Sie serialisierte Daten speichern, die mehrere Versionen Ihres Codes überleben.

Das Speichern serialisierter Daten für eine so lange Zeitspanne ist jedoch nicht sehr üblich. Es ist weitaus üblicher, den Serialisierungsmechanismus zu verwenden, um Daten vorübergehend in beispielsweise einen Cache zu schreiben oder sie über das Netzwerk an ein anderes Programm mit derselben Version der relevanten Teile der Codebase zu senden. 

In diesem Fall sind Sie nicht an der Abwärtskompatibilität interessiert. Es geht Ihnen nur darum sicherzustellen, dass die Codebasen, die kommunizieren, tatsächlich die gleichen Versionen relevanter Klassen haben. Um eine solche Überprüfung zu ermöglichen, müssen Sie die serialVersionUID wie zuvor beibehalten und nicht vergessen, sie 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, jedoch mit derselben serialVersionUID. In diesem Fall erkennt der Standardmechanismus (in.defaultReadObject()) keinen Unterschied und versucht, inkompatible Daten zu deserialisieren. Jetzt kann es zu einem kryptischen Laufzeitfehler oder einem stillen Ausfall (Nullfelder) kommen. Diese Arten von Fehlern sind möglicherweise schwer zu finden.

Um diese Verwendung zu erleichtern, bietet Ihnen die Java-Plattform die Wahl, die serialVersionUID nicht manuell einzustellen. Stattdessen wird zur Kompilierzeit ein Hash der Klassenstruktur generiert und als id verwendet. Durch diesen Mechanismus wird sichergestellt, dass Sie niemals unterschiedliche Klassenstrukturen mit derselben ID haben. Daher werden diese oben genannten schwer zu verfolgenden Serialisierungsfehler der Laufzeit nicht angezeigt.

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

Und wenn Sie wie im ersten Anwendungsfall rückwärtskompatibel zu 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.

102

Was ist eine serialVersionUID und warum sollte ich sie verwenden?

SerialVersionUID ist ein eindeutiger Bezeichner für jede Klasse. Mit JVM wird die Version der Klasse verglichen, um sicherzustellen, dass dieselbe Klasse während der Serialisierung während der Deserialisierung geladen wurde.

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

Die javadocs für Serializable say:

die standardmäßige serialVersionUID-Berechnung ist stark abhängig von der Klasse Details, die je nach Implementierung des Compilers variieren können, und können führen zu unerwarteten InvalidClassExceptions während Deserialisierung.

Deshalb müssen Sie serialVersionUID deklarieren, da wir dadurch mehr steuern können.

Dieser Artikel hat einige gute Punkte zum Thema.

66
Thalaivar

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

Angenommen, Sie erstellen eine Car-Klasse, instanziieren diese und schreiben sie in einen Objektstrom. Das abgeflachte Autoobjekt befindet sich einige Zeit im Dateisystem. In der Zwischenzeit wird die Car-Klasse durch Hinzufügen eines neuen Felds geändert. Wenn Sie später versuchen, das abgeflachte Car-Objekt zu lesen (d. H. Deserialisieren), erhalten Sie den Java.io.InvalidClassException - da allen serialisierbaren Klassen automatisch ein eindeutiger Bezeichner zugewiesen wird. 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 wurde. Sie können das Auslösen dieser Ausnahme vermeiden, indem Sie die Versionierung selbst steuern, indem Sie eine explizite serialVersionUID angeben. Es gibt auch einen kleinen Leistungsvorteil, wenn Sie Ihre serialVersionUID explizit deklarieren (da sie nicht berechnet werden muss). Daher empfiehlt es sich, Ihre serialisierbaren Klassen mit Ihrer eigenen serialVersionUID zu versehen, sobald Sie sie wie folgt erstellen:

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

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 in Betracht ziehen, da der Deserialisierer des Objekts mit der Objektversion übereinstimmt, die der Classloader hat. Lesen Sie mehr dazu in der Java-Sprachspezifikation.

34
eishay

Wenn Sie diese Warnung für eine Klasse erhalten, die Sie nie über das Serialisieren nachdenken, und dass Sie sich nicht implements Serializable deklariert haben, liegt dies oft daran, dass Sie von einer Superklasse geerbt wurden, die Serializable implementiert. Oft ist es dann besser, an ein solches Objekt zu delegieren, anstatt 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 relevanten Methoden rufen Sie myList.foo() anstelle von this.foo() (oder super.foo()) auf. (Dies passt nicht in allen Fällen, aber immer noch recht häufig.)

Ich sehe oft Leute, die JFrame oder ähnliches erweitern, wenn sie wirklich nur dazu delegieren müssen. (Dies ist auch beim automatischen Vervollständigen in einer IDE hilfreich, da JFrame hunderte von Methoden hat, die Sie nicht benötigen, wenn Sie Ihre benutzerdefinierten Methoden in Ihrer Klasse aufrufen möchten.)

In einem Fall, in dem die Warnung (oder die serialVersionUID) unvermeidlich ist, müssen Sie AbstractAction (normalerweise in einer anonymen Klasse) verwenden und nur die actionPerformed-Methode hinzufügen. Ich denke, es sollte in diesem Fall keine Warnung geben (da Sie normalerweise solche anonymen Klassen über verschiedene Versionen Ihrer Klasse nicht zuverlässig serialisieren und deserialisieren können), aber ich bin nicht sicher, wie der Compiler dies erkennen könnte.

33
Paŭlo Ebermann

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

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

Wir schließen daraus, dass die serialVersionUID des serialisierten Objekts der serialVersionUID der Klasse entsprechen muss, damit der Serialisierungs-/Deserialisierungsprozess erfolgreich verläuft. Falls der Programmierer den serialVersionUID-Wert explizit im Programm angibt, wird derselbe Wert unabhängig von der Serialisierungs- und Deserialisierungsplattform mit dem serialisierten Objekt und der Klasse verknüpft (z. B. kann die Serialisierung auf Plattformen wie Windows mit Sun oder MS JVM und Deserialization können sich auf einer anderen Plattform Linux (Zing JVM) befinden.

Für den Fall, dass serialVersionUID nicht vom Programmierer angegeben wird, während die Serialisierung\DeSerialisierung eines Objekts ausgeführt wird, verwendet die Java-Laufzeitumgebung einen eigenen Algorithmus zur Berechnung. Dieser serialVersionUID-Berechnungsalgorithmus variiert von einer JRE zur anderen. Es ist auch möglich, dass die Umgebung, in der das Objekt serialisiert wird, eine JRE (z. B. Sun JVM) und die Umgebung, in der die Deserialisierung ausgeführt wird, Linux Jvm (Zing) verwendet. In solchen Fällen unterscheidet sich die mit serialisiertem Objekt verknüpfte serialVersionUID von der in der Deserialisierungsumgebung berechneten serialVersionUID der Klasse. Deserialisierung wiederum wird nicht erfolgreich sein. Um solche Situationen/Probleme zu vermeiden, muss der Programmierer immer die serialVersionUID der serialisierbaren Klasse angeben.

22
Nitesh Soni

Ein Beispiel, bei dem die fehlende serialVersionUID ein Problem verursachen kann:

Ich arbeite an dieser Java EE-Anwendung, die aus einem Webmodul besteht, das ein EJB-Modul verwendet. Das Webmodul ruft das Modul EJB remote auf und übergibt eine POJO, die Serializable als Argument implementiert.

Diese POJO's-Klasse wurde in der EJB-Dose und in ihrer eigenen Dose in der WEB-INF/lib des Webmoduls verpackt. Sie sind eigentlich die gleiche Klasse, aber wenn ich das EJB-Modul packe, entpacke ich das POJO-Glas, um es zusammen mit dem EJB-Modul zu packen.

Der Aufruf der Variable EJB schlug mit der folgenden Ausnahme fehl, da ich die Variable serialVersionUID nicht angegeben hatte:

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
18
Henrique Ordine

Machen Sie sich keine Sorgen, 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 gesagt - UIDs nach Bedarf einführen (was sehr unwahrscheinlich ist)

18
grand johnson

Zuerst muss ich die Serialisierung erklären.
Serialisierung Ermöglicht die Konvertierung des Objekts in einen Stream, um das Objekt über das Netzwerk zu senden OR Speichern in Datei OR Speichern in DB für die Verwendung von Briefen. 

Es gibt einige Regeln für die Serialisierung

  • Ein Objekt kann nur serialisiert werden, wenn seine Klasse oder seine Oberklasse die serialisierbare Schnittstelle implementiert

  • Ein Objekt ist serialisierbar (selbst implementiert die serialisierbare Schnittstelle), auch wenn seine Superklasse dies nicht ist. Die erste Superklasse in der Hierarchie der serialisierbaren Klasse, die keine serialisierbare Schnittstelle implementiert, MUSS jedoch über einen no-arg-Konstruktor verfügen. Wenn dies verletzt wird, erzeugt readObject () zur Laufzeit eine Java.io.InvalidClassException

  • Alle primitiven Typen sind serialisierbar.

  • Übergangsfelder (mit Übergangsmodifizierer) werden NICHT serialisiert (d. H. Nicht gespeichert oder wiederhergestellt). Eine Klasse, die Serializable implementiert, muss Übergangsfelder von Klassen markieren, die keine Serialisierung unterstützen (z. B. ein Dateistream).

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

Wenn das Objekt serialisiert ist Java Runtime Weist die Serienversionsnummer zu, die als serialVersionID bezeichnet wird. 

Wo wir serialVersionID brauchen:Während der Deserialisierung zur Überprüfung der Kompatibilität von Sender und Empfänger bezüglich Serialisierung. Wenn der Empfänger die Klasse mit einer anderen serialVersionID geladen hat, endet die Deserialisierung mit InvalidClassCastException .
Eine serialisierbare Klasse kann ihre eigene serialVersionUID explizit deklarieren, indem sie ein Feld mit dem Namen „serialVersionUID“ deklariert, das statisch, final und vom Typ long: sein muss.

Versuchen wir es mit einem Beispiel.

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();
}
}

Erstellen Sie ein Serialisierungsobjekt 

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");
}
}

Deserialize 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, erhalten Sie die Ausnahme. 

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)
16
JegsVala

Ich verwende serialVersionUID im Allgemeinen in einem Kontext: Wenn ich weiß, wird der Kontext der Java-VM verlassen. 

Ich würde dies wissen, wenn ich ObjectInputStream und ObjectOutputStream für meine Anwendung verwenden möchte 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 korrekt zusammenarbeiten, oder wenn sie außerhalb von VM gespeichert und abgerufen werden, zum Beispiel HttpSession. Die Sitzungsdaten können auch während eines Neustarts und Upgrades des Anwendungsservers erhalten bleiben.

Für alle anderen Fälle verwende ich 

@SuppressWarnings("serial")

meistens reicht die Voreinstellung serialVersionUID aus. Dies beinhaltet Exception, HttpServlet.

15

Felddaten stellen einige Informationen dar, die in der Klasse ..__ gespeichert sind. Klasse implementiert die Serializable-Schnittstelle Eclipse bot automatisch an, das Feld serialVersionUID zu deklarieren. Beginnen wir mit dem dort eingestellten Wert 1.

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

@SuppressWarnings("serial")
14
Mukti

SerialVersionUID wird zur Versionskontrolle von Objekten verwendet. Sie können auch serialVersionUID in Ihrer Klassendatei angeben. Wenn Sie serialVersionUID nicht angeben, kann die bereits serialisierte Klasse nicht wiederhergestellt werden, wenn Sie ein Feld in der Klasse hinzufügen oder ändern. Die serialVersionUID, die für die neue Klasse und das alte serialisierte Objekt generiert wurde, unterscheidet sich. Der Java-Serialisierungsprozess stützt sich auf die korrekte serialVersionUID, um den Status des serialisierten Objekts wiederherzustellen, und löst im Falle einer Nichtübereinstimmung der serialVersionUID die Java.io.InvalidClassException aus

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

11
Neethu

Es wäre schön, wenn CheckStyle überprüfen könnte, dass die serialVersionUID für eine Klasse, die Serializable implementiert, einen guten Wert hat, d. H. Dass sie mit dem übereinstimmt, was der Generator für die Serienversions-ID erzeugen würde. Wenn Sie beispielsweise über ein Projekt mit vielen serialisierbaren DTOs verfügen, sollten Sie daran denken, die vorhandene serialVersionUID zu löschen und neu zu generieren. Dies ist ein schmerzhafter Vorgang, und derzeit ist es die einzige Möglichkeit (dies ist mir bekannt), für jede Klasse zu regenerieren und mit zu vergleichen das Alte. Das ist sehr schmerzhaft.

10
David Wright

Warum SerialVersionUID innerhalb der Serializable-Klasse in Java verwenden?

Bei serialization erstellt Java Runtime eine Versionsnummer für eine Klasse, damit sie später deserialisiert werden kann. Diese Versionsnummer ist in Java als SerialVersionUID bekannt.

SerialVersionUID wird zur Versionierung serialisierter Daten verwendet. Sie können eine Klasse nur dann deserialisieren, wenn SerialVersionUID mit der serialisierten Instanz übereinstimmt. Wenn wir in unserer Klasse nicht SerialVersionUID deklarieren, wird sie von Java Runtime für uns generiert, jedoch nicht empfohlen. Es wird empfohlen, SerialVersionUID als private static final long-Variable zu deklarieren, um den Standardmechanismus zu vermeiden. 

Wenn Sie eine Klasse als Serializable deklarieren, indem Sie die Markerschnittstelle Java.io.Serializable implementieren, persistiert die Java-Laufzeitinstanz dieser Klasse mithilfe des standardmäßigen Serialisierungsmechanismus auf der Festplatte, sofern Sie den Prozess nicht mithilfe der Externalizable-Schnittstelle angepasst haben.

siehe auch Warum SerialVersionUID in der Klasse Serializable in Java verwenden

Code: javassist.SerialVersionUID

9
roottraveller

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, werden Tools wie IntelliJ Idea und Eclipse zu kurz, da sie Zufallszahlen generieren und nicht für eine Reihe von Dateien funktionieren auf einmal. Ich stelle das folgende bash-Skript her (es tut mir leid für Windows-Benutzer, erwägen Sie, einen Mac zu kaufen oder auf Linux zu konvertieren), um das Problem mit der serialVersionUID mit Leichtigkeit 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

speichern Sie dieses Skript, sagen Sie dazu add_serialVersionUID.sh ~/bin. Dann 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, um die serialVersionUID im folgenden Format hinzuzufügen:

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 Abzug. Stellen Sie also sicher, dass sich Ihr $ Java_HOME/bin im PATH befindet.

7
schnell18

Diese Frage ist in Effective Java von Joshua Bloch sehr gut dokumentiert. Ein sehr gutes Buch und ein Muss. Ich werde im Folgenden einige Gründe erläutern:

Die Serialisierungslaufzeit enthält für jede serialisierbare Klasse eine Nummer namens Serienversion. Diese Nummer wird als serialVersionUID bezeichnet. Nun gibt es etwas Mathematik hinter dieser Zahl, die auf den Feldern/Methoden basiert, 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 Sender und Empfänger eines serialisierten Objekts Klassen für dieses Objekt geladen haben, die in Bezug auf die Serialisierung kompatibel sind. Wenn der Empfänger eine Klasse für das Objekt geladen hat, die eine andere serialVersionUID hat als die Klasse des entsprechenden Senders, führt die Deserialisierung zu einer InvalidClassException.

Wenn die Klasse serialisierbar ist, können Sie auch Ihre eigene serialVersionUID explizit deklarieren, indem Sie ein Feld mit dem Namen "serialVersionUID" deklarieren, das statisch, final und vom Typ long sein muss. Die meisten IDEs wie Eclipse helfen Ihnen beim Generieren dieser langen Zeichenfolge.

6
Geek

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 zur Klassenstruktur berechnet. Angenommen, Sie haben eine Employee-Klasse erstellt und diese hat die Versions-ID 333 (von JVM zugewiesen). Wenn Sie nun das Objekt dieser Klasse serialisieren (Angenommen, das Employee-Objekt), weist die JVM ihr eine UID als # 333 zu.

Stellen Sie sich eine Situation vor - in der Zukunft müssen Sie Ihre Klasse bearbeiten oder ändern. Wenn Sie sie ändern, weist JVM in diesem Fall eine neue UID zu (angenommen # 444) . Wenn Sie jetzt versuchen, das Mitarbeiterobjekt zu deserialisieren, JVM vergleicht die Versions-ID (# 333) des serialisierten Objekts (Employee-Objekt) mit der der Klasse, z. B. # 444 (Da es geändert wurde). Im Vergleich wird JVM feststellen, dass beide Versions-UIDs unterschiedlich sind und daher die Deserialisierung fehlschlägt. Wenn also serialVersionID für jede Klasse vom Programmierer selbst definiert wird. Dies gilt auch dann, wenn die Klasse zukünftig weiterentwickelt wird. Daher wird JVM immer feststellen, dass die Klasse mit dem serialisierten Objekt kompatibel ist, auch wenn die Klasse geändert wird. Weitere Informationen finden Sie in Kapitel 14 von HEAD FIRST Java.

6
Er.Naved Ali

Eine einfache Erklärung
1. Serialisieren Sie Daten? Bei der Serialisierung werden Klassendaten grundsätzlich in eine Datei/einen Stream/etc geschrieben. Bei der Deserialisierung werden diese Daten in eine Klasse zurückgelesen.
2. Möchten Sie in die Produktion gehen? Wenn Sie nur etwas mit unwichtigen/gefälschten Daten testen, machen Sie sich keine Sorgen darüber (es sei denn, Sie testen die Serialisierung direkt).
3. Ist dies die erste Version? Wenn ja, setzen Sie serialVersionUID=1L.
4. Ist dies die zweite, dritte usw. Prod-Version? Jetzt müssen Sie sich um serialVersionUID kümmern und sollten sich eingehend damit befassen.

Wenn Sie beim Aktualisieren einer Klasse, die Sie schreiben/lesen müssen, die Version nicht korrekt aktualisieren, erhalten Sie grundsätzlich eine Fehlermeldung, wenn Sie versuchen, alte Daten zu lesen.

1
gagarwa

Zur Beantwortung Ihrer Frage: Wenn wir SerialVersionUID in unserer Klasse nicht deklarieren, generiert Java Runtime es für uns, aber dieser Prozess reagiert auf viele Klassenmetadaten, einschließlich Anzahl der Felder, Art der Felder, Zugriffsmodifikator der Felder, implementierte Schnittstelle Es wird daher empfohlen, dies 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, ihn aufgrund von Strom-/Systemfehlern (oder Netzwerkfehlern) zu verlieren, wenn der Objektstatus an einen anderen gesendet wird Maschine. Die Lösung für dieses Problem heißt "Persistenz", was einfach bedeutet, die Daten zu speichern. Serialisierung ist eine von vielen anderen Möglichkeiten, um Persistenz zu erreichen (durch Speichern von Daten auf Festplatte/Speicher). Beim Speichern des Status des Objekts ist es wichtig, eine Identität für das Objekt zu erstellen, um es ordnungsgemäß zurücklesen zu können (Deserialisierung). Diese eindeutige Identifikation lautet ID ist SerialVersionUID.

0
Shanks D Shiva

Um es kurz zu machen, wird in diesem Feld geprüft, 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 einen String und der Client den empfangenen String in ein Objekt. In diesem Feld wird angegeben, dass beide mit derselben Vorstellung davon arbeiten, was dieses Objekt ist. Dieses Feld hilft bei:

  • 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 deserialisiert werden kann

  • sie haben Ihre Daten in einer Datei gespeichert und später versuchen Sie, 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 beibehalten

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 das Objekt deserialisieren, werden Felder, die in der Zeichenfolge nicht vorhanden sind, als NULL gespeichert. Wenn Sie ein Feld aus Ihrem Objekt entfernt haben, behalten ältere Versionen dieses Feld immer bei -NULL, 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 ändert man die Idee, die man in die Bedeutung eines Feldes eingibt. Wenn Sie zum Beispiel 12 Jahre alt sind, meinen Sie "Fahrrad" unter "Fahrrad", aber wenn Sie 18 Jahre alt sind, meinen Sie "Motorrad" - wenn Ihre Freunde Sie zum "Radfahren durch die Stadt" einladen und Sie der einzige sind, der das macht Auf dem Fahrrad angekommen, werden Sie verstehen, wie wichtig es ist, über Felder hinweg die gleiche Bedeutung zu behalten :-)

0
Stanislav Orlov