intellij - serialisierung java




Was ist eine serialVersionUID und warum sollte ich sie verwenden? (14)

Was ist eine serialVersionUID und warum sollte ich sie verwenden?

SerialVersionUID ist ein eindeutiger Bezeichner für jede Klasse. JVM verwendet sie, um die Versionen der Klasse zu vergleichen und 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. Darüber hinaus möchten Sie manchmal aus irgendeinem Grund die Deserialisierung alter serialisierter Objekte verbieten [ backward incompatibility ], und in diesem Fall müssen Sie lediglich die serialVersionUID ändern.

Die Javadocs für Serializable sagen :

Die standardmäßige serialVersionUID-Berechnung reagiert sehr empfindlich auf Klassendetails, die je nach Implementierung des Compilers variieren können. Dies kann zu unerwarteten InvalidClassException während der Deserialisierung führen.

Daher müssen Sie serialVersionUID angeben, da wir dadurch mehr Kontrolle haben .

Dieser Artikel hat einige gute Punkte zum Thema.

Eclipse gibt Warnungen aus, wenn eine serialVersionUID fehlt.

Die serialisierbare Klasse Foo deklariert kein statisches finales 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.


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

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

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

Wenn eine serialisierbare Klasse eine serialVersionUID nicht explizit deklariert, berechnet die Serialisierungslaufzeit einen standardmäßigen serialVersionUID Wert für diese Klasse basierend auf verschiedenen Aspekten der Klasse, wie in der Java-Objektserialisierungsspezifikation beschrieben. Es wird jedoch dringend empfohlen, dass alle serialisierbaren Klassen die serialVersionUID Werte explizit deklarieren, da die standardmäßige serialVersionUID Berechnung sehr empfindlich auf Klassendetails serialVersionUID , die je nach Implementierung des Compilers variieren können. Dies kann zu unerwarteten InvalidClassExceptions während der Deserialisierung führen. 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 nach Möglichkeit den privaten Modifizierer verwenden, da solche Deklarationen nur für die sofort deklarierenden Klasse gelten. serialVersionUID Felder sind als geerbte Member nicht nützlich.


Felddaten stellen einige Informationen dar, die in der Klasse gespeichert sind. Class implementiert die Serializable Schnittstelle. serialVersionUID bot Eclipse 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")

Ich kann diese Gelegenheit nicht verpassen, um Josh Blochs Buch Effective Java (2nd Edition) zu veröffentlichen. 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. serialVersionUID eines dieser serialVersionUID auf irgendeine Weise ändern, wird 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, können Sie mit dem JDK-Tool serialver die serialVersionUID für die alte Klasse generieren und explizit festlegen das auf der neuen Klasse. (Abhängig von Ihren Änderungen müssen Sie möglicherweise auch eine benutzerdefinierte Serialisierung implementieren, indem readObject Methoden writeObject und readObject hinzufügen - siehe Serializable Javadoc oder zuvor erwähntes Kapitel 11.)


In der ursprünglichen Frage wurde nach dem Warum gefragt, wo diese Serial Version ID nützlich wäre. Nun, ich habe einen gefunden.

Angenommen, Sie erstellen eine Car , instanziieren sie und schreiben Sie sie in einen Objektstrom. Das abgeflachte Autoobjekt befindet sich einige Zeit im Dateisystem. In der Zwischenzeit wird die Car durch Hinzufügen eines neuen Felds geändert. Wenn Sie später versuchen, das abgeflachte Car Objekt zu lesen (dh zu deserialisieren), erhalten Sie die java.io.InvalidClassException - da 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 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, serialVersionUID 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
}

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)


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. Wenn der Programmierer den serialVersionUID-Wert explizit im Programm angibt, wird derselbe Wert unabhängig von der Serialisierungs- und Deserialisierungsplattform dem serialisierten Objekt und der Klasse zugeordnet (z. B. kann die Serialisierung auf Plattformen wie Windows mit sun oder ausgeführt werden 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.


Wenn Sie Ihre Objekte niemals 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.


Wenn Sie serialisieren, nur weil Sie aus Gründen der Implementierung serialisieren müssen (zum Beispiel, wenn Sie für eine HTTPSession serialisieren ... wenn diese gespeichert ist oder nicht, ist es wahrscheinlich nicht wichtig, ein Formularobjekt zu deserialisieren.) dann kannst du 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. Die serialVersionUID stellt Ihre Klassenversion dar und Sie sollten sie 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 eine standardisierte serialisierbare Benutzer-ID, indem Sie auf die Schnellkorrekturoption klicken, und machen Sie sich keine Sorgen.


Zuerst muss ich die Serialisierung erklären.
Durch die Serialisierung kann das Objekt in einen Stream konvertiert werden, um dieses Objekt über das Netzwerk zu senden ODER in eine Datei zu speichern ODER zur Verwendung in Briefen in DB zu speichern.

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.

  • Transiente Felder (mit Transient Modifier) ​​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. ein Dateistream).

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

Wenn das Objekt serialisiert ist, ordnet JAVA Runtime die Serienversionsnummer zu, die als serialVersionID bezeichnet wird.

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

Warum SerialVersionUIDinnerhalb von SerializableJava in Java verwenden?

Während der serializationJava-Laufzeitumgebung erstellt eine Versionsnummer für eine Klasse, damit sie später deserialisiert werden kann. Diese Versionsnummer ist als SerialVersionUIDin Java bekannt.

SerialVersionUIDwird zur Versionierung serialisierter Daten verwendet. Sie können eine Klasse nur dann deserialisieren, wenn sie SerialVersionUIDmit der serialisierten Instanz übereinstimmt. Wenn wir nicht SerialVersionUIDin unserer Klasse deklarieren , generiert Java Runtime 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 als Serializabledurch das Implementieren einer Markerschnittstelle deklarieren java.io.Serializable, persistiert die Java-Laufzeitinstanz dieser Klasse mithilfe des standardmäßigen Serialisierungsmechanismus auf der Festplatte, sofern Sie den Prozess nicht mithilfe der ExternalizableSchnittstelle angepasst haben .

Weitere Informationen finden Sie unter Warum SerialVersionUID in der Klasse Serializable in Java verwenden

Code: javassist.SerialVersionUID


Diese Frage ist in Effective Java von Joshua Bloch sehr gut dokumentiert. Ein sehr gutes Buch und ein Muss. Ich werde einige der 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 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 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 dabei, diese lange Zeichenfolge zu erzeugen.


Jedes Mal, wenn ein Objekt serialisiert wird, wird das Objekt mit einer Versions-ID-Nummer für die Klasse des Objekts versehen. Diese ID wird als serialVersionUID und 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 JVM ihr als # 333 UID zu.

Betrachten Sie eine Situation - in der Zukunft müssen Sie Ihre Klasse bearbeiten oder ändern. In diesem Fall weist die JVM in diesem Fall eine neue UID zu (Angenommen # 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 wird JVM feststellen, dass beide Versions-UIDs unterschiedlich sind und 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.


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 Klasse java.io.InvalidClassException aus

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







serialversionuid