Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Werte Community, ich würde gerne die nachstehende Frage verstehen:
Code:
Given:
import java.io.*;
class Animal {
Animal() {
System.out.print("a");
}
}
class Dog extends Animal implements Serializable {
Dog() {
System.out.print("d");
}
}
public class Beagle extends Dog {
}
If an instance of class Beagle is created, then Serialized, then deSerialized, what is the result?
A. ad
B. ada
C. add
D. adad
E. Compilation fails.
Die Antwort B ist richtig, aber warum?
Ich hätte gedacht die Antwort A ist richtig.
Warum ist die Antwort B richtig?
Bei der ersten Objecterzeugung werden die Constructoren von unten nach oben aufgerufen. Frueher musste man den ersten Call super() im Constructor haben. Das wuerde so aussehen:
Code:
class Animal {
Animal() {
super();
System.out.print("a");
}
}
class Dog extends Animal implements Serializable {
Dog() {
super();
System.out.print("d");
}
}
public class Beagle extends Dog {
Beagle() {
super();
}
}
Der constructor von Beagle kommt zuerst, ruft super() auf, das ist Dog. Dog ruft super() auf, das waere Animal. Animal ruft super() auf, das ist Object. Ein Object wird erzeugt und der Call kehrt zurueck zu Animal, das "a" druckt. Von dort geht's zurueck zu Dog, das druckt "d" und von dort zurueck zu Beagle. Das wars dann mit der Object erzeugung.
Bei der De-serialisierung wird nur der oberste Constructor verwendet und der Rest der Werte von der JVM gesetzt. Also wird nur "a" gedruckt. Das ganze druckt dann ada.
De-serialisierung wird ganz gern fuer Hackerangriffe benutzt, weil fast alle Kontrollmechanismen in den Konstruktoren unwirksam werden. Deshalb habe ich fuer ein privates Project JABB geschrieben, ein Framework fuer sprachunabhaengige Serialisierung: https://github.com/a-genius/jabb
Cheers,
Andy
Zum selber ausprobieren:
Code:
package org.javaforum;
import java.io.*;
import java.util.*;
public class TrySer {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Beagle beagle = new Beagle();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(beagle);
byte[] bytes = baos.toByteArray();
System.out.println("\n");
System.out.println(Arrays.toString(bytes));
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Beagle animal = (Beagle) ois.readObject();
// eigentlich gehoert es aber so
System.out.println("\nUse superclass for reference");
Animal beagle2 = new Beagle();
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(beagle2);
bytes = baos.toByteArray();
System.out.println("\n");
System.out.println(Arrays.toString(bytes));
bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
Animal animal2 = (Animal) ois.readObject();
}
static class Animal {
Animal() {
System.out.print("a");
}
}
static class Dog extends Animal implements Serializable {
Dog() {
System.out.print("d");
}
}
static public class Beagle extends Dog {
}
}
Hey AndyJ, vielen Dank für Deine Antwort !!!
Du hast mir auf die Sprünge geholfen, ich hatte anscheinen eine vollkommen falsche Vorstellung von dem, was bei einer De-serialisierung geschied.
Ich habe mir mal den nachstehenden Code zusammengeschrieben, woran ich nachvollziehen konnte, was Du mir geantwortet hast. Interessant fand ich, dass die Methode readObject(); ein Object der Klasse Object zurückgibt, was aber eigentlich auch nur logisch ist, wenn man darüber nachdenkt.
Code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class ObjectTest{
String x1 = "a";
public ObjectTest() {
System.out.println(x1);
}
}
public class DeserialisierungTest extends ObjectTest implements Serializable {
String x2 = "b";
public DeserialisierungTest() {
System.out.println(x2);
}
public static void main(String[] args) {
try {
// Serialisierung
FileOutputStream ios = new FileOutputStream("DeserialisierungTest.txt");
ObjectOutputStream oos = new ObjectOutputStream(ios);
oos.writeObject(new DeserialisierungTest());
oos.close();
// Deserialisierung
FileInputStream fis = new FileInputStream("DeserialisierungTest.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
DeserialisierungTest dTestObject = (DeserialisierungTest) ois.readObject();
ois.close();
System.out.println(dTestObject);
}
catch (IOException e) {
}
catch (ClassNotFoundException e) {
}
}
}
Wie genau habe ich nun das Nachfolgende zu verstehen? "Es ist wichtig zu verstehen, daß beim Deserialisieren nicht der Konstruktor des erzeugten Objekts aufgerufen wird. Lediglich bei einer serialisierbaren Klasse, die in ihrer Vererbungshierarchie Superklassen hat, die nicht das Interface Serializable implementieren, wird der parameterlose Konstruktor der nächsthöheren nicht-serialisierbaren Vaterklasse aufgerufen. Da die aus der nicht-serialisierbaren Vaterklasse geerbten Membervariablen nicht serialisiert werden, soll auf diese Weise sichergestellt sein, daß sie wenigstens sinnvoll initialisiert werden." Quelle: https://dbs.cs.uni-duesseldorf.de/lehre/docs/java/javabuch/html/k100258.html
Müsste in meinem Code nicht die Klasse ObjectTest eine nicht-serialisierbare Vaterklasse der Klasse DeserialisierungTest sein, da die Klasse ObjectTest das Interfaces Serializable nicht implantiert und somit auch die Membervariablen x1 erst gar nicht serialisiert werden kann? Der Debugger sagt mir das mein deserialisiertes Object die Membervariabl x1 in sich trägt.