2017-06-27 4 views
2

Ich habe mich gefragt, ob Sie Klassendaten in einem Objekt serialisiert wie so:Was genau sind serialisierte Klassendaten?

public Something implements Serializable{ 
    private static final long serialVersionUID = 1L; 
    public Class type; 
} 

Welche Daten tatsächlich serialisiert und als Typ gespeichert?

Ist es möglich, Informationen wie simplename und Fullname von Typ zu bekommen, auch wenn Sie diese Klasse zum Zeitpunkt geladen hat nicht?

+0

Sie sollten keine unformatierten Typen verwenden. –

Antwort

2

Ist es möglich, Informationen wie simplyname und fullname vom Typ zu erhalten, auch wenn Sie diese Klasse zu diesem Zeitpunkt nicht geladen haben?

Solange die Klasse für den Typ vorhanden ist, wird die Klasse, auf die sich das Objekt Class bezieht, geladen.


den Code unten:

class Test implements Serializable { 
    // verion UID 

    public Class type; 

    public Test(Class type) { 
     this.type = type; 
    } 
} 

ich serialisiert ein Test Objekt, das die Class für eine andere Art enthalten: Second

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("text.obj")); 
out.writeObject(new Test(Second.class)); 
out.close(); 

Jetzt ist es zurück in das Lesen:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("text.obj")); 
Test test = (Test) in.readObject(); 
in.close(); 

In diesem Code gibt es keinen Verweis auf die Klasse Second. Wenn Second geladen wird, wenn das obige Programm ausgeführt wird, können wir annehmen, dass es aufgrund der Deserialisierung lieber als direkte Referenz war.

Und es tut:

enter image description here

Also ja, werden die Dinge wie type.getSimpleName() zu erhalten versuchen, arbeiten.

Running:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("text.obj")); 
Test test = (Test) in.readObject(); 
System.out.println(test.type.getSimpleName()); 
in.close(); 

Drucke

Second 

Wenn Sie die Second Klasse löschen, erhalten Sie ClassNotFoundException wie erwartet. Beim Lesen des Stacktrace können Sie sehen, dass das Programm versucht, die Klasse Second zu laden:

Exception in thread "main" java.lang.ClassNotFoundException: test.Second 
    at java.net.URLClassLoader.findClass(Unknown Source) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) 
    at java.lang.ClassLoader.loadClass(Unknown Source) 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Unknown Source) 
    at java.io.ObjectInputStream.resolveClass(Unknown Source) 
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source) 
    at java.io.ObjectInputStream.readClassDesc(Unknown Source) 
    at java.io.ObjectInputStream.readClass(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source) 
    at java.io.ObjectInputStream.readSerialData(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.readObject(Unknown Source) 
+0

Danke, das war ziemlich erschöpfend! Nur ein kleiner Nachschlag: Sagen wir, wenn Sie in einem serialisierten Objekt ein Array von verschiedenen Class-Typen hätten (die alle im Projekt fehlen), nehme ich an, dass der Inputstream die Exception werfen würde, sobald sie die erste trifft, richtig? Wäre es möglich, die deklarierten Daten von denen zu lesen? –

+0

@MoffKalast Ja, eine Ausnahme wird ausgelöst, sobald versucht wird, ein Objekt zu deserialisieren, für das die Klasse im Projekt nicht existiert. Darf ich fragen, warum Sie das erforschen? Objektströme werden tendenziell missbraucht (für Dinge, die mit einem anderen Tool effizienter ausgeführt werden können), und die Serialisierung kann zu Problemen bei der Skalierung führen, wenn sie nicht mit Vorsicht behandelt wird (siehe meine Antwort zu "[Was ist die Strafe für die unnötige Implementierung von Serializable] (https://stackoverflow.com/questions/39079928/what-is-the-penalty-for-uncessessary-implementing-serializable/39088501#39088501)) –

+0

Nun, ich hatte eine erhebliche Menge an serialisierten Dateien, die Class-Daten enthalten als ein Mittel zum Identifizieren von Komponenten, mit denen ich kompatibel bleiben muss, während ich die Pakete der tatsächlichen Klassen modifiziere, änderte ich den ObjectInputStream so, dass er den Klassen-Simplex mit dem einer Klasse in einem Hashmaps übereinstimmt, falls er nicht standardmäßig gefunden werden kann (wie diese Antwort) schlägt vor: https://stackoverflow.com/a/3916282/4012132) Ich war vor allem an anderen Ideen und der Tatsache interessiert, dass ein roher Typ der Klasse serialisierbar ist, während die Klasse, die er enthält, nicht sein kann - was einige seltsame s verursacht tuff es wieder aufladen. –

0

Einfach: Dies serialisiert alle nicht-transienten Felder, die in dieser Klasse vorhanden sind.

In diesem Sinne: Wenden Sie sich an die Quelle von Class.java, wenn Sie sich wirklich um die Details kümmern.

Die zweite Frage (wenn es möglich ist, eine Klasse zu deserialisieren, die nicht geladen werden kann) - ich mache eine fundierte Vermutung: Ich denke, das sollte scheitern. Der Punkt ist: Das Klassenobjekt würde es Ihnen ermöglichen, nach Feldern, Methoden, ... zu fragen. Was nicht möglich ist ohne das Wissen über diese Klasse.

Aber das sollte ziemlich einfach zu testen sein. Für den Fall, dass niemand heute Nacht eine bessere Antwort findet ... Ich werde morgen nachsehen und Sie wissen lassen.