Frage

In Java, wenn eine Klasse Serializable implementiert, sondern ist abstrakt, sollte es ein serialVersionUID hat lange erklärt, oder die Unterklassen macht nur dazu nötig sein?

In diesem Fall ist es in der Tat die Absicht, dass alle Unterklassen mit Serialisierung befassen, wie der Zweck des Typs verwendet werden soll, in RMI nennt.

War es hilfreich?

Lösung

Die serialVersionUID vorgesehene Kompatibilität zwischen einem deseralized Objekt und der aktuellen Version der Klasse zu bestimmen. Als solches ist es nicht wirklich notwendig, in der ersten Version einer Klasse, oder in diesem Fall in einer abstrakten Basisklasse. Sie werden nie eine Instanz dieser abstrakten Klasse serialisieren / deserialisieren, so dass es keine serialVersionUID benötigt.

(Natürlich macht es eine Compiler-Warnung generiert, die Sie wollen, um loszuwerden, nicht wahr?)

Es stellt sich heraus james' Kommentar korrekt ist. Die serialVersionUID einer abstrakten Basisklasse nicht zu Subklassen weitergegeben wird. Im Hinblick auf das, Sie Sie die serialVersionUID in Ihrer Basisklasse benötigen.

Der Code zum Test:

import java.io.Serializable;

public abstract class Base implements Serializable {

    private int x = 0;
    private int y = 0;

    private static final long serialVersionUID = 1L;

    public String toString()
    {
        return "Base X: " + x + ", Base Y: " + y;
    }
}



import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Sub extends Base {

    private int z = 0;

    private static final long serialVersionUID = 1000L;

    public String toString()
    {
        return super.toString() + ", Sub Z: " + z;
    }

    public static void main(String[] args)
    {
        Sub s1 = new Sub();
        System.out.println( s1.toString() );

        // Serialize the object and save it to a file
        try {
            FileOutputStream fout = new FileOutputStream("object.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fout);
            oos.writeObject( s1 );
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Sub s2 = null;
        // Load the file and deserialize the object
        try {
            FileInputStream fin = new FileInputStream("object.dat");
            ObjectInputStream ois = new ObjectInputStream(fin);
            s2 = (Sub) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println( s2.toString() );
    }
}

Führen Sie das Haupt einmal in Sub, um es ein Objekt zu erstellen und zu speichern. Dann die serialVersionUID in der Klasse Basis ändern, kommentiert die Zeilen in Haupt aus, die das Objekt speichern (so es sie nicht wieder speichern, Sie wollen einfach nur die alten laden), und es erneut. Dies wird zu einer Ausnahme führen

java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

Andere Tipps

Ja, in der Regel aus dem gleichen Grunde, dass jede andere Klasse eine serielle ID muss - zu vermeiden, eine für sich erzeugt wird. Grundsätzlich kann jede Klasse (nicht-Schnittstelle), die serializable implementiert sollte serielle Version ID definieren oder Sie riskieren Deserialisierung Fehler, wenn die gleiche .class- Kompilierung nicht in dem Server- und Client-JVMs ist.

Es gibt auch andere Möglichkeiten, wenn Sie versuchen, etwas Phantasie zu tun. Ich bin nicht sicher, was Sie unter „es ist die Absicht der Unterklassen ...“. Werden Sie benutzerdefinierte Serialisierung Methoden (zB. Write, readObject-) schreiben? Wenn ja gibt es andere Möglichkeiten, um mit einer Superklasse zu tun.

siehe: http://java.sun.com/javase/6 /docs/api/java/io/Serializable.html

HTH Tom

Eigentlich von Toms Link unter Hinweis darauf, ob serialVersionID fehlt tatsächlich durch Serialisierung berechnet Laufzeit das heißt nicht während der Kompilierung

  

Wenn eine serializable Klasse nicht explizit einen erklären   serialVersionUID, dann wird die Laufzeit der Serialisierung a berechnen   Standard serialVersionUID Wert für diese Klasse auf der Grundlage verschiedenen Aspekte   die Klasse ...

Das macht die Sache noch komplizierter, die unterschiedlichen Versionen von JRE.

Konzeptionell, sehen die serialisierten Daten wie folgt aus:

subClassData(className + version + fieldNames + fieldValues)
parentClassData(className + version + fieldNames + fieldValues)
... (up to the first parent, that implements Serializable)

Wenn Sie also deserialisieren, Mismatch in Version in irgendeiner der Klassen in der Hierarchie bewirkt, dass die Deserialisierung zum Scheitern verurteilt. Nichts ist für Schnittstellen gespeichert, so gibt es keine Notwendigkeit Version für sie angeben.

Antwort: Ja, Sie brauchen auch serialVersionUID in der Basis abstrakten Klasse zu liefern. Auch wenn es nicht über Felder (className + version werden gespeichert, auch wenn es keine Felder).

Beachten Sie auch folgende Möglichkeiten:

  1. Wenn Klasse kein Feld hat, dass in den serialisierten Daten (a entferntes Feld) gefunden wird, wird er ignoriert.
  2. Wenn Klasse ein Feld hat, ist, dass nicht in serialisierten Daten (ein neues Feld), auf 0 / false / null gesetzt ist (nicht auf dem Standardwert wie man erwarten würde).
  3. , wenn ein Feld Datentyp ändert, muss der deserialisiert Wert auf den neuen Typ zuordenbar sein. Z.B. wenn Sie ein Object Feld mit String Wert haben, den Feldtyp ändern, wird erfolgreich sein String, aber Integer Wechsel nicht. Doch von int zu long Feld ändern wird nicht funktionieren, obwohl Sie int Wert long Variablen zuweisen können.
  4. Wenn Unterklasse nicht mehr die übergeordnete Klasse erweitert, die es in den serialisierten Daten erstreckt, wird er ignoriert (wie im Fall 1).
  5. Wenn nun eine Unterklasse eine Klasse erweitert wird, dass nicht in serialisierten Daten gefunden, Elternklasse Felder sind mit 0 / false / Nullwert wieder (wie im Fall 2).

In einfachen Worten: Sie Felder neu anordnen, hinzufügen und entfernen Sie sie, auch die Klassenhierarchie ändern. Sie sollten nicht umbenennen Felder oder Klassen (es wird nicht scheitern, aber die Werte werden nicht deserialisiert werden). Sie können nicht Art von Feldern mit primitivem Typ ändern, und Sie können Referenztyp vorgesehene Felder eines ändern der neue Typ von allen Werten zugeordnet werden kann.

. Hinweis: Wenn die Basisklasse nicht Serializable implementieren und nur die Unterklasse ist, dann Felder aus der Basisklasse würde als transient verhalten

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top