Serialisierung und Deserialisierung von Objekten
1) Die Objektserialisierung dient andernfalls dazu, das Objektobjekt in eine Bytesequenz umzuwandeln Dies wird als Deserialisierung des Objekts bezeichnet.
2) Serialisierungsstrom (ObjectOutputStream), der ein gefilterter Bytestrom ist – writeObject()-Methode
Deserialisierungsstrom (ObjectInputStream) – readObject()-Methode
3) Serialisierbare Schnittstelle (Serialisierbar)
Das Objekt muss die Serialisierungsschnittstelle implementieren, um serialisiert zu werden, andernfalls tritt eine Ausnahme auf.
Hinweis: Diese Schnittstelle hat keine Methoden, es ist nur ein [Standard]
1 Grundlegendste Sequenz Der Prozess der Serialisierung und Deserialisierung
Serialisierung und Deserialisierung werden alle an Objektobjekten durchgeführt. Hier ist ein einfacher Fall, um den Prozess der Objektserialisierung und -deserialisierung zu demonstrieren.
1. Erstellen Sie eine neue Student-Klasse (Testklasse)
Hinweis: Zur Durchführung von Serialisierungsvorgängen ist eine Klasse erforderlich, die die Serialisierungsschnittstelle implementiert! !
@SuppressWarnings("serial") public class Student implements Serializable{ private String stuno;//id private String stuna;//姓名 private int stuage;//年龄 public String getStuno() { return stuno; } public void setStuno(String stuno) { this.stuno = stuno; } public String getStuna() { return stuna; } public void setStuna(String stuna) { this.stuna = stuna; } public Student() { super(); // TODO Auto-generated constructor stub } public Student(String stuno, String stuna, int stuage) { super(); this.stuno = stuno; this.stuna = stuna; this.stuage = stuage; } @Override public String toString() { return "Student [stuno=" + stuno + ", stuna=" + stuna + ", stuage=" + stuage + "]"; } public int getStuage() { return stuage; } public void setStuage(int stuage) { this.stuage = stuage; } }
2. Instanzen der Student-Klasse in Dateien serialisieren
Die grundlegenden Schritte sind wie folgt:
1) Geben Sie die Serialisierung an und Datei speichern
2), die ObjectOutputStream-Klasse erstellen
3), eine Student-Klasse erstellen
4), die writeObject-Methode zum Serialisieren verwenden
5 ), Verwenden Sie die Methode close(), um den Stream zu schließen
String file="demo/obj.dat"; //对象的序列化 ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream(file)); //把Student对象保存起来,就是对象的序列化 Student stu=new Student("01","mike",18); //使用writeObject方法序列化 oos.writeObject(stu); oos.close();
Ergebnisse ausführen: Sie können sehen, dass die serialisierte Datei von obj.dat im Demoverzeichnis
3. Deserialisieren Sie die Datei und lesen Sie das Student-Klassenobjekt aus
Die grundlegenden Schritte sind wie folgt: 1), geben Sie die Datei an, die deserialisiert werden soll 2), Konstruieren Sie die ObjectInputStream-Klasse 3), verwenden Sie die readObject-Methode zum Deserialisieren 1), verwenden Sie die close-Methode, um den Stream zu schließenString file="demo/obj.dat"; ObjectInputStream ois =new ObjectInputStream( new FileInputStream(file)); //使用readObject()方法序列化 Student stu=(Student)ois.readObject();//强制类型转换 System.out.println(stu); ois.close();
Hinweis: Beim Deserialisieren einer Datei sind die von der readObject-Methode herausgenommenen Objekte standardmäßig vom Typ Object und müssen in umgewandelt werden entsprechenden Typ.
2. Transienten- und ArrayList-Quellcode-Analyse
Im täglichen Programmierprozess wollen wir manchmal nicht alle Elemente Was soll ich zu diesem Zeitpunkt tun, wenn eine Klasse vom Compiler serialisiert werden soll? Java stellt ein Schlüsselworttransient bereit, um Elemente zu ändern, die nicht automatisch vom JVM serialisiert werden sollen. Lassen Sie uns dieses Schlüsselwort kurz erklären.
Transient-Schlüsselwort: Durch Transient geändertes Element. Dieses Element wird standardmäßig nicht von JVM serialisiert, Sie können die Serialisierung dieses Elements jedoch selbst abschließen.
Hinweis: 1) Wenn bei der zukünftigen Netzwerkprogrammierung bestimmte Elemente nicht übertragen werden müssen, können Sie vorübergehende Änderungen verwenden, um Datenverkehr zu sparen Effiziente Elementserialisierung zur Verbesserung der Leistung. 2) Sie können writeObject verwenden, um die Serialisierung dieses Elements selbst abzuschließen.ArrayList wird mit dieser Methode optimiert. Object[] elementData, der Kerncontainer von ArrayList, verwendet vorübergehende Änderungen, die Serialisierung des elementData-Arrays ist jedoch in writeObject selbst implementiert. Nur gültige Elemente im Array werden serialisiert. readObject ist ähnlich.
--------------Der Weg, sich selbst zu serialisieren- -
Fügen Sie der zu serialisierenden Klasse zwei Methoden hinzu (Diese beiden Methoden stammen aus dem ArrayList-Quellcode Zwei spezielle Methoden, die aus extrahiert wurden):
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化操作 s.writeInt(stuage);//自己完成被transient修饰的元素的序列化 } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException,ClassNotFoundException{ s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作 this.stuage=s.readInt();//自己完成stuage的反序列化操作 }
Hier gibt es eine weitere Frage: Warum müssen wir die Serialisierung und Deserialisierung immer noch manuell durchführen?
Dieses Problem muss anhand des Quellcodes von ArrayList analysiert werden: Sie können das sehen ArrayList-Quellcode Der Zweck der Selbstserialisierung: Die unterste Ebene von ArrayList ist ein Array. Die Selbstserialisierung kann ungültige Elemente im Array filtern und nur gültige Elemente im Array serialisieren,wodurch die Leistung verbessert wird .
Daher können wir während des eigentlichen Programmiervorgangs die Serialisierung nach Bedarf selbst abschließen, um die Leistung zu verbessern.三、序列化中子父类构造函数问题
在类的序列化和反序列化中,如果存在子类和父类的关系时,序列化和反序列化的过程又是怎么样的呢?
这里我写一个测试类来测试子类和父类实现序列化和反序列化时构造函数的实现变化。
public static void main(String[] args) throws IOException { // TODO Auto-generated method stub String file="demo/foo.dat"; ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream(file)); Foo2 foo2 =new Foo2(); oos.writeObject(foo2); oos.flush(); oos.close(); } } class Foo implements Serializable{ public Foo(){ System.out.println("foo"); } } class Foo1 extends Foo{ public Foo1(){ System.out.println("foo1"); } } class Foo2 extends Foo1{ public Foo2(){ System.out.println("foo2"); } }
运行结果:这是序列化时递归调用了父类的构造函数
接来下看看反序列化时,是否递归调用父类的构造函数。
ObjectInputStream ois=new ObjectInputStream( new FileInputStream(file)); Foo2 foo2=(Foo2)ois.readObject(); ois.close();
运行结果:控制台没有任何输出。
那么这个结果是否证明反序列化过程中父类的构造函数就是始终不调用的呢?
然而不能证明!!
因为再看下面这个不同的测试例子:
class Bar { public Bar(){ System.out.println("bar"); } } class Bar1 extends Bar implements Serializable{ public Bar1(){ System.out.println("bar1"); } } class Bar2 extends Bar1{ public Bar2(){ System.out.println("bar2"); } }
我们用这个例子来测试序列化和反序列化。
序列化结果:
反序列化结果:没实现序列化接口的父类被显示调用构造函数
【反序列化时】,向上递归调用构造函数会从【可序列化的一级父类结束】。即谁实现了可序列化(包括继承实现的),谁的构造函数就不会调用。
总结:
1)父类实现了serializable接口,子类继承就可序列化。
子类在反序列化时,父类实现了序列化接口,则不会递归调用其构造函数。
2)父类未实现serializable接口,子类自行实现可序列化
子类在反序列化时,父类没有实现序列化接口,则会递归调用其构造函数。
本文来自 java入门 栏目,欢迎学习!
Das obige ist der detaillierte Inhalt vonSerialisierung und Deserialisierung von Java-Objekten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!