Martin Jung: Objekte, Verweise

Beitrag lesen

Hi Mathias,

ich hab mal versucht dein Beispiel zu verstehen.

Gut! ;-)

Also in meinem Beispiel waren das ja keine inneren Klassen und zudem waren sie auch nicht statisch. Spielt das eine Rolle?

Gute Frage - darauf ein Jein. Für die Verdeutlichung dessen, was das Beispiel zeigen sollte, spielt das zunächst einmal keine Rolle.

Innere Klassen sind ein Mittel zur Organisation von Klassendefinitionen[1]. Auf Ebene des Bytecodes werden innere Klassen in individuelle Class-Dateien kompiliert und ihre "Inner/Outer"-Beziehungen zur Laufzeit über "ganz normale" Objektbeziehungen realisiert (der Compiler erweitert beteiligte Klassen hierzu geeignet um entsprechende Felder). Statisch (also zur Compile-Zeit) werden diese Beziehungen jedoch auch festgehalten, nämlich im Namen der inneren Klassen (<OuterClassName$InnerClassName.class>). Und da der Klassen-Name durch ObjectOutputStream.writeObject(Object) ebenso serialisiert wird, muss in der Ziel VM bei Deserialisierung mit ObjectInputStream.readObject() auch die Definition einer äußeren Klasse vorhanden sein[2]. Ist dies nicht sicherzustellen, müssen zu serialisierende Objekte richtigerweise durch Top-Level Klassen definiert werden.

Wenn ich dich richtig verstanden habe, dann sollten alle Objekte innerhalb von Klassen mit Verweisen auf andere Klassen "mitgesandt" werden solange sie serialisierbar und nicht statisch sind.

Nein. Wie geschrieben, dürfen zu serialisierende Member zusätzlich nicht das transient-Schlüsselwert besitzen.

Dh. im meinem Beispiel sollte das funktionieren und der Wert im Vektor am "Zielort" noch vorhanden sein?

Ähm - wenn Du die Klassen serialisierbar machst (und gegebenfalls in Top-Level Klassen extrahierst), dann ja. Dies zu zeigen war die Absicht meines Beispiels (Hinweis durch Re-Zitat: der Beispielcode "sollte lauffähig sein").

Sinnvolle Korrekturen zum Beispiel:

letzter try/catch-Block in main()

System.out.println("read start: " + timeStamp());
        **  // SerializableRecursive toSerialize = new SerializableRecursive();
        **  SerializableRecursive toSerialize = (SerializableRecursive) is.readObject();

Klasse AnyContainer (komplett ersetzen)

static class AnyContainer implements Serializable {
        public Vector vec = new Vector();

/** @see java.io.Serializable */
        private void writeObject(ObjectOutputStream os) throws IOException {
            // individuelles Verhalten
            this.vec.addElement("Object serialized: " +TestStandardSerialization.timeStamp());
            // dann erst Aufruf des default write Mechanismus
            os.defaultWriteObject();
        }
        private void readObject(java.io.ObjectInputStream is)
                throws IOException, ClassNotFoundException {
            // zuerst Aufruf des default read Mechanismus
            is.defaultReadObject();
            // individuelles Verhalten
            this.vec.addElement("Object added during deserialization: " +TestStandardSerialization.timeStamp());
        }
    }

Zum versenden benutze ich den ObjectOutputStream.

Habe ich mir gedacht.

Viele Grüße,
Martin Jung

[1]
..und ich habe innere Klassen verwendet, weil diese Teil des Beispiels sind und so einfach lauffähiger Code gepostet werden kann. Dies ist übrigens eine sinnvoller Verwendungsweck für innere Klassen.

[2]
Der Aufruf von ObjectInputStream.readObject() führt bei Abwesenheit der äußeren Klasse dann zu einer ClassNotFoundException.
Dieses Standard-Verhalten kann man natürlich dadurch ändern, dass man die Deserialisierung "eben" selbst realisiert.. (spezielle ClassLoader etc.) ;-)