Input/Output Serialisierung und Object.hashCode()

Alan47

Mitglied
Hallo zusammen,

ich habe kürzlich etwas entdeckt, das mich sehr verwundert hat. Dafür habe ich euch ein minimales, funktionierendes Beispiel geschrieben:

Java:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashSet;

public class SerializationTest {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {
		HashSet<MyObject> hashSet = new HashSet<MyObject>();
		MyObject objectA = new MyObject();
		hashSet.add(objectA);
		// serialize to file
		File file = new File("test");
		FileOutputStream fos = new FileOutputStream(file);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(hashSet);
		oos.writeObject(objectA);
		oos.close();
		fos.close();
		// set all references to null
		hashSet = null;
		objectA = null;
		// reload from file
		FileInputStream fis = new FileInputStream(file);
		ObjectInputStream ois = new ObjectInputStream(fis);
		hashSet = (HashSet<MyObject>) ois.readObject();
		objectA = (MyObject) ois.readObject();
		// close the streams
		ois.close();
		fis.close();
		file.delete();
		// the critical call:
		if (hashSet.contains(objectA)) {
			System.out.println("This works");
			// WHY does this work???
		} else {
			System.out.println("This does not work");
		}

	}
}

class MyObject implements Serializable {

	public static final long serialVersionUID = 1L;
}


Was passiert:
- ein HashSet wird angelegt
- ein Objekt ("objektA") wird angelegt
- dem HashSet wird objektA hinzugefügt
- das HashSet und objektA werden in eine Datei serialisiert
- die Referenzen auf die Objekte werden aus dem Programm gelöscht
- das HashSet und objektA werden erneut geladen
- das HashSet bestätigt die Existenz von objektA in seinem Inhalt.


Eines vorweg: ich finde es gut, dass das funktioniert, es kommt meiner Anwendung entgegen. Aber: warum funktioniert das eigentlich? HashSets funktionieren ja auf Basis der "hashCode()"-Methode der Objekte, die sie speichern. Wenn ein Objekt seinen hashCode() ändert, so würde das HashSet das Objekt nicht mehr finden und ein Aufruf von "contains(...)" würde false zurückliefern.
Da der Aufruf von "contains(...)" aber true zurückliefert, lässt das nur einen Schluss zu: die Standard-Implementierung von "hashCode()" liefert über die Lebensdauer eines Objektes hinweg konstante Werte. Wenn man sich jetzt aber die API zu Object#hashCode() ansieht, so wird dort behauptet, dass die hashCode()-Implementierung auf der internen Objekt-ID basiert, die für jedes erzeugte Objekt einzigartig ist.

Und jetzt kommt die Stelle, wo ich mich frage, wieso der obige Code funktionieren kann: wenn ein Objekt serialisiert und erneut geladen wird, dann muss es zwangsläufig eine neue interne Objekt-ID bekommen (es könnte passieren, dass die ursprüngliche Objekt-ID schon vergeben ist). Daher müsste sich der hashCode() des Objektes ändern, da er ja auf eben jener ID passiert. Offensichtlich tut er das aber nicht, sonst würde das Objekt im HashSet nicht mehr gefunden werden. Die Ausgabe des Programms auf der Kommandozeile ist immer "This works".


Ein verzwicktes Rätsel - ich bin zwar froh, dass es funktioniert, aber ich wüsste gerne, warum es funktioniert. Kann jemand Licht auf diese Sache werfen?



Gruß,


Alan
 
Zuletzt bearbeitet:
B

bygones

Gast
mhm verstehe nicht so was dich ueberrascht ?!

du serialisierst eine HashSet das ein Objekt beinhaltet und wunderst dich danach dass das Objekt (das du auch deserialisiert) noch im Set ist ?

Holy moly, was waere das, wenn das nicht gelten wuerde ?! jegliche Containerklassen waeren unsinnig zu serialisieren ?!
 
S

SlaterB

Gast
@Alan47
du ziehst ohne Not falsche Schlüsse, z.B. könntest du dir die Hashcodes vorher und nachher auch anschauen!

das HashSet wird bei der Serialisierung nicht exakt gleich bleiben, nicht zwingend die alten HashCodes weiterverwenden,
sondern wird beim Laden neu aufgebaut mit den dann neuen Hashcodes,
das alte Objekt ist im neuen auch nicht mehr zu finden, ein weiterer Test

Code aus HashSet zur Serialisierung:
Java:
    /**
     * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
     * serialize this set).
     *
     * @serialData The capacity of the backing <tt>HashMap</tt> instance
     *		   (int), and its load factor (float) are emitted, followed by
     *		   the size of the set (the number of elements it contains)
     *		   (int), followed by all of its elements (each an Object) in
     *             no particular order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
	// Write out any hidden serialization magic
	s.defaultWriteObject();

        // Write out HashMap capacity and load factor
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());

        // Write out size
        s.writeInt(map.size());

	// Write out all elements in the proper order.
	for (Iterator i=map.keySet().iterator(); i.hasNext(); )
            s.writeObject(i.next());
    }

    /**
     * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
     * deserialize it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
	// Read in any hidden serialization magic
	s.defaultReadObject();

        // Read in HashMap capacity and load factor and create backing HashMap
        int capacity = s.readInt();
        float loadFactor = s.readFloat();
        map = (((HashSet)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));

        // Read in size
        int size = s.readInt();

	// Read in all elements in the proper order.
	for (int i=0; i<size; i++) {
            E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }

gut ist allgemein bei Serialisierung, dass das eine MyObject nur genau einmal im Stream steht, nicht zweimal und dann getrennt wieder geladen,
da wird aufgepasst so dass beim Laden das gelesene Objekt exakt das aus der geladenen Map ist
 

Alan47

Mitglied
das HashSet wird bei der Serialisierung nicht exakt gleich bleiben, nicht zwingend die alten HashCodes weiterverwenden,
sondern wird beim Laden neu aufgebaut mit den dann neuen Hashcodes,
das alte Objekt ist im neuen auch nicht mehr zu finden, ein weiterer Test

Ha, genau das ist der Punkt :) Ich war irgendwie total verbohrt und dachte dass das HashSet eben einfach rausgeschrieben und wieder reingelesen wird - darauf, dass es beim Reinlesen mit den neuen Hashcodes neu aufgebaut werden könnte, habe ich komplett vergessen. Darum war ich auch so verwirrt, jetzt ist es klar.

Vielen Dank!




Alan
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
antonia09 Einkaufszettel Persistenz und Serialisierung Allgemeine Java-Themen 6
D Serialisierung und Deserialisierung von Objekten - Frageprogramm Allgemeine Java-Themen 4
R Datentypen Korrekte integer in Hex ASCII Konvertierung und serialisierung Allgemeine Java-Themen 1
M Serialisierung funktioniert nicht Allgemeine Java-Themen 9
Z Best Practice Serialisierung Allgemeine Java-Themen 2
Arif Input/Output Serialisierung - Datei wird nicht erzeugt Allgemeine Java-Themen 3
M Alternative zur Serialisierung.. Protobuf? Allgemeine Java-Themen 9
E Serialisierung - Deserialisierung Allgemeine Java-Themen 4
Thallius Serialisierung schlägt fehl. Allgemeine Java-Themen 3
M Serialisierung & Verschlüsselung Allgemeine Java-Themen 2
E Serialisierung - Sinn einer generierten serialVersionUID? Allgemeine Java-Themen 4
V Serialisierung von Instanz eigener Klasse Allgemeine Java-Themen 5
K Serialisierung einer verschachtelten Datenstuktur Allgemeine Java-Themen 9
Tobse Input/Output Dateiformat: Serialisierung VS Custom format Allgemeine Java-Themen 6
A Problem bei Serialisierung von Bibliotheks-Klassen Allgemeine Java-Themen 6
A Input/Output Serialisierung Sonderzeichen Allgemeine Java-Themen 3
P Serialisierung der Oberklasse Allgemeine Java-Themen 2
Kr0e Circular reference - Serialisierung Allgemeine Java-Themen 6
K Serialisierung in Properties-Datei möglich? Allgemeine Java-Themen 3
B Serialisierung mit Unterobjekten über Netzwerk Allgemeine Java-Themen 3
C Serialisierung - Standardwert für nachträglich hinzugefügtes Feld Allgemeine Java-Themen 2
S Serialisierung der Kindklasse Allgemeine Java-Themen 5
K Serialisierung komplett selbst machen Allgemeine Java-Themen 13
C Serialisierung ohne Serializable Allgemeine Java-Themen 4
S Serialisierung und Referenzen Allgemeine Java-Themen 6
S Viele Bilder -> Speicher ausgelastet? / (De-)serialisierung geht nicht mehr richtig Allgemeine Java-Themen 8
E Objekt bei Serialisierung ändern Allgemeine Java-Themen 2
Q Serialisierung / Speicherung Geschwindingkeit & Aktuelle Position Allgemeine Java-Themen 7
Z Serialisierung und Deserialisierung einer HashMap Allgemeine Java-Themen 17
W Serialisierung Allgemeine Java-Themen 6
K Serialisierung von Hashmap in Vector Allgemeine Java-Themen 3
F Serialisierung und Obfuscation? Allgemeine Java-Themen 7
G (De)serialisierung und Referenzen Allgemeine Java-Themen 5
T Serialisierung: Wie macht RMI das so schnell? Allgemeine Java-Themen 14
J Serialisierung: readInt + writeInt Allgemeine Java-Themen 4
X Einige Fragen zu Serialisierung Allgemeine Java-Themen 2
J bean + serialisierung + serialVersionUID Allgemeine Java-Themen 3
K Serialisierung Allgemeine Java-Themen 6
thE_29 Wie funktioniert Serialisierung? Allgemeine Java-Themen 10
S Problem mit Serialisierung Allgemeine Java-Themen 2
C Serialisierung von JComboBox Allgemeine Java-Themen 4
H Object cast exception Allgemeine Java-Themen 7
P JDK nicht installiert in Net Object Fusion Allgemeine Java-Themen 7
Erwin82a Object cannot be converted to Custom Class in Lampda Expression Allgemeine Java-Themen 2
Zeppi Cast Object in Generics Allgemeine Java-Themen 4
MoxxiManagarm Mapping into existing object Allgemeine Java-Themen 15
coolian Swing erstellt fillreckt immmer ein neues object Allgemeine Java-Themen 13
N Wo ist Object.class ? Allgemeine Java-Themen 0
R Erste Schritte Object reference funktioniert nicht. Wie mach ichs richtig? Allgemeine Java-Themen 3
RalleYTN Datentypen Herausfinden ob Object ein Array ist ohne den Typen des Arrays zu kennen? Allgemeine Java-Themen 12
N Gibt es etwas allgemeineres as Object? Allgemeine Java-Themen 16
Bananabert Swing jtree : image als user object Allgemeine Java-Themen 2
N ArrayList in eigenem Object nicht richtig serialisierbar Allgemeine Java-Themen 14
B [Android] EditText-Object ist null - Nimmt nicht den Wert des enthaltenen Textfeldes ein Allgemeine Java-Themen 2
Z Vergleich zwischen int und Object Allgemeine Java-Themen 1
D Object nach Vererbung mit Class Object überprüfen Allgemeine Java-Themen 4
T InvalidClassException - Read null attempting to read class descriptor for object Allgemeine Java-Themen 8
J Ist eine Instanz von einem bestimmten Object Typ? Allgemeine Java-Themen 6
L Sortieren von "Map<String, Object>" Allgemeine Java-Themen 2
M Cast double[]-->Object[] oder Vector<double[]> Allgemeine Java-Themen 3
G REST- Object darstellung Allgemeine Java-Themen 6
C Object.equals() liefert falschen Wert? Allgemeine Java-Themen 14
darekkay Generics: Wildcard und Object Allgemeine Java-Themen 5
O Socket Object wird scheinbar falsch empfangen Allgemeine Java-Themen 6
N Klasse/Object Eigenaufruf Allgemeine Java-Themen 5
G JNI Shared Object Allgemeine Java-Themen 10
B Variable class in java.lang.Object Allgemeine Java-Themen 11
S Klassen Zuorgnung Object-char Allgemeine Java-Themen 2
N java.lang.IllegalMonitorStateException: object not locked by thread before notify() Allgemeine Java-Themen 2
S Type mismatch: cannot convert from Object to float Allgemeine Java-Themen 3
M Jaxb und JPA: A cycle is detected in the object graph Allgemeine Java-Themen 5
H double dispatch und equals(Object) Allgemeine Java-Themen 6
J Datentypen Problem mit Date-Object Allgemeine Java-Themen 2
B Variablen Alle RenderingHints.Keys (KEY_*) in Array + alle RenderingHints.Keys (VALUE_*) in Object[] Allgemeine Java-Themen 8
J Verschiedene Klassen als "Object" in ArrayList und dann in for-Schleife erzeugen!? Allgemeine Java-Themen 2
L Object Instanz anhand eines Strings Allgemeine Java-Themen 10
A Datei als Object einlesen und das Object als Singleton instance setzen. Allgemeine Java-Themen 13
DEvent embedded Object Database in Text Format Allgemeine Java-Themen 5
J Casting Problem Object, Double und String Allgemeine Java-Themen 3
M Object-Instanz in Date übersetzen Allgemeine Java-Themen 6
P Tree Object structure Allgemeine Java-Themen 19
G Object mit clone kopieren Allgemeine Java-Themen 21
J merkwürdig: Object Allgemeine Java-Themen 6
woezelmann Object nach Deserialisierung nicht mehr gleich Allgemeine Java-Themen 13
Iron Monkey Object in Datei effizienter lesen / schreiben Allgemeine Java-Themen 13
L Object = null? Allgemeine Java-Themen 16
dayaftereh Serializable und Object In/Out Stream Allgemeine Java-Themen 2
T Object auf Double, Int, String testen Allgemeine Java-Themen 5
N serialize deserialize java object über string Allgemeine Java-Themen 8
N getName() of reflection Object Allgemeine Java-Themen 4
B Probelm mit File Object Allgemeine Java-Themen 6
G NoClassDefFoundError: java/lang/Object Allgemeine Java-Themen 4
S Liste Object Löschen Allgemeine Java-Themen 7
P not enough space for object heap - Trotz mehr RAM? Allgemeine Java-Themen 6
MQue List<String> aus List<Object> generieren Allgemeine Java-Themen 2
M ArrayList<Object[]> und toArray() Allgemeine Java-Themen 5
Daniel_L LinkedList vom Typ Object-Array? Allgemeine Java-Themen 4
B Warum return type Object ? Allgemeine Java-Themen 4
D Generisches Object erstellen Allgemeine Java-Themen 2
M Databinding von Object zu properties-Datei Allgemeine Java-Themen 10

Ähnliche Java Themen


Oben