2009-11-02 17 views
13

Ich habe eine Klasse, die für die unveränderliche Verwendung bestimmt ist, daher möchte ich alle Felder final beschriften.Serialisierung und unveränderliche Objekte

Die Klasse wird jedoch serialisiert und deserialisiert, um sie über das Netzwerk zu senden. Damit dies funktioniert, ist ein leerer Konstruktor erforderlich. Dies verhindert, dass ich die letzten Felder erstelle.

Ich bin mir sicher, dass dies ein ziemlich häufiges Problem ist, aber ich kann keine Lösung finden. Wie soll ich vorgehen?

Antwort

7

In dem typischen Serialisierungsfall ist es nicht erforderlich, dass die Klasse einen leeren Konstruktor oder nicht finale Felder aufweist, die serialisiert werden können.

Nun, wenn Sie Ihre eigene Serialisierung durchführen müssen, oder Sie müssen eine Klasse, die nicht Serializable implementieren Unterklasse, das ist eine andere Geschichte.

Sie müssen also einige weitere Details angeben, wie Sie ein Problem haben.

+1

Danke, ich war die typische Methode der Serialisierung verwenden, aber hatte immer einen leeren Konstruktor geliefert, wie das war, wie ich dachte, es funktioniert. – Pool

6

Ein Konstruktor ohne Argon ist nicht erforderlich. Die am weitesten abgeleitete nicht-serialisierbare Klasse benötigt einen Konstruktor ohne Argumente, der für die am wenigsten abgeleitete serialisierbare Klasse verfügbar ist. Wenn Sie Felder in einem readObject mutieren müssen, verwenden Sie einen seriellen Proxy über readResolve und writeReplace.

5

Dieses Problem ist ein open bug on the Java language. (Beachten Sie, dass dies nur gilt, wenn Sie die Serialisierung manuell durchführen müssen, z. B. mit readObject)

+0

Aus der Bewertung: "Das Problem gilt für letzte Instanz Felder außer den serialisierbaren Felder der Klasse" so im Standardfall funktioniert es gut. Nick scheint etwas anderes zu machen. – Yishai

+0

Ah ja, ich sollte einen Haftungsausschluss hinzufügen, dass dies nur gilt, wenn Sie in readObject oder so etwas einhaken müssen. –

3

Um das Gesagte zu wiederholen, sind keine Arg-Konstruktoren erforderlich, wenn Sie die Implementierung der java.io.Serializable-Schnittstelle ausführen . Sehen Sie sich zum Beispiel den Quellcode java.lang.Integer an, eine einfache serialisierbare/unveränderbare Klasse, die zwei Konstruktoren hat: einen, der einen int annimmt, und einen, der einen String akzeptiert. Quellcode: http://www.docjar.com/html/api/java/lang/Integer.java.html. Javadoc: http://java.sun.com/javase/6/docs/api/java/lang/Integer.html.

Auch abhängig von der Komplexität Ihrer Klasse und was Sie tun, könnten Sie die Implementierung der Serialisierung über die java.io.Externalizable Schnittstelle in Betracht ziehen (obwohl einige es für veraltet halten, und es erfordert einen Argumenten Nein-Arg). Hier ein Überblick über SO: What is the difference between Serializable and Externalizable in Java?, und hier ist das offizielle Java-Tutorial: http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html.

3

Für das Protokoll, da ich ein ähnliches Problem hatte:
ich eine Nachricht hatte „java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar; kein gültiger Konstruktor

Ich dachte, es war, weil es einen Standardkonstruktor fehlte. Aber die obigen Antworten bestätigen, dass es nicht zwingend ist (aber unsere App verwendet einen alten Serializer, der tatsächlich einen Standardkonstruktor benötigt, so dass der Fall entstehen kann).

Dann fand ich eine Seite besagt:

Wenn eine Klasse, die für die Vererbung entworfen ist nicht serialisierbar ist, es kann unmöglich sein, eine serializable Unterklasse zu schreiben. Insbesondere ist es unmöglich, wenn die Oberklasse keinen zugänglichen parameterlosen Konstruktor zur Verfügung stellt.

Daher die Nachricht, die ich habe, nehme ich an.Es schien, dass das Kernproblem klassisch war: Ich erklärte eine Klasse als serialisierbar, aber die Oberklasse war nicht! Ich habe die Serializable-Schnittstelle in die Hierarchie verschoben, und alles war gut.

Aber die Botschaft war ein wenig irreführend ... :-)

0

A no-arg Konstruktor nicht erforderlich ist. Lassen Sie sich den Quellcode lesen:

// java.io.ObjectStreamClass 
private static Constructor<?> getSerializableConstructor(Class<?> cl) { 
    Class<?> initCl = cl; 
    while (Serializable.class.isAssignableFrom(initCl)) { 
     if ((initCl = initCl.getSuperclass()) == null) { 
      return null; 
     } 
    } 
    ... 
} 

also eigentlich der nicht-arg Konstruktor in der nächsten nicht Serializable Klasse in der Typenhierarchie erforderlich ist.

Dies bedeutet, dass die folgende Klasse Domain serialisiert werden kann.

class Domain implements Serializable { 
    private final int a; 

    public Domain(int a) { 
     this.a = a; 
    } 
} 

Aber die Klasse Son kann nicht:

class Father{ 
    private final int a; 

    public Father(int a) { 
    this.a = a; 
    } 
} 

class Son extends Father implements Serializable { 
    public Son(int a) { 
    super(a); 
    } 
} 
Verwandte Themen