Heim > Java > javaLernprogramm > Hauptteil

Detaillierter Beispielcode für die Serialisierung und Deserialisierung von Java-Objekten

黄舟
Freigeben: 2017-03-31 10:37:47
Original
1394 Leute haben es durchsucht

In diesem Artikel wird hauptsächlich die Serialisierung und Deserialisierung von Java -Objekten vorgestellt. Der Herausgeber findet es ziemlich gut, daher werde ich es jetzt mit Ihnen teilen und als Referenz geben. Folgen wir dem Editor und werfen wir einen Blick darauf.

Im vorherigen Artikel haben wir die Verwendung von Byte-Stream-Zeichenströmen eingeführt. Damals haben wir den DataOutputStream-Stream verwendet, um ein Objekt an den Stream auszugeben > Der Wert des Attributs wird beim Lesen nacheinander an den Stream ausgegeben und umgekehrt. Unserer Meinung nach ist dieses Verhalten wirklich umständlich, insbesondere wenn dieses Objekt viele Attributwerte enthält. Auf dieser Grundlage kann der Objektserialisierungsmechanismus in Java diesen Vorgang sehr gut lösen. In diesem Artikel wird die Java-Objektserialisierung kurz vorgestellt. Der Hauptinhalt lautet wie folgt:

  1. Präzise Codeimplementierung

  2. Grundlegender Algorithmus für die Serialisierungsimplementierung

  3. Zwei besondere Situationen

  4. Benutzerdefinierter Serialisierungsmechanismus

  5. Serialisierungsversionskontrolle

1. Einfache Code-Implementierung

Bevor wir die Verwendung der Objektserialisierung vorstellen, schauen wir uns an, was wir zuvor getan haben. Speichert Daten eines Objekttyps.

//简单定义一个Student类
public class Student {

 private String name;
 private int age;

 public Student(){}
 public Student(String name,int age){
 this.name = name;
 this.age=age;
 }

 public void setName(String name){
 this.name = name;
 }
 public void setAge(int age){
 this.age = age;
 }
 public String getName(){
 return this.name;
 }
 public int getAge(){
 return this.age;
 }
 //重写toString
 @Override
 public String toString(){
 return ("my name is:"+this.name+" age is:"+this.age);
 }
}
Nach dem Login kopieren
//main方法实现了将对象写入文件并读取出来
public static void main(String[] args) throws IOException{

 DataOutputStream dot = new DataOutputStream(new FileOutputStream("hello.txt"));
 Student stuW = new Student("walker",21);
 //将此对象写入到文件中
 dot.writeUTF(stuW.getName());
 dot.writeInt(stuW.getAge());
 dot.close();

 //将对象从文件中读出
 DataInputStream din = new DataInputStream(new FileInputStream("hello.txt"));
 Student stuR = new Student();
 stuR.setName(din.readUTF());
 stuR.setAge(din.readInt());
 din.close();

 System.out.println(stuR);
 }
Nach dem Login kopieren
Ausgabeergebnis: Mein Name ist:Walker, Alter ist:21


Offensichtlich ist diese Art des Codeschreibens umständlich, mal sehen, wie man es verwendet Serialisierung ist Wird zum Speichern der Objektinformationen verwendet.

public static void main(String[] args) throws IOException, ClassNotFoundException {

 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello.txt"));
 Student stuW = new Student("walker",21);
 oos.writeObject(stuW);
 oos.close();

 //从文件中读取该对象返回
 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello.txt"));
 Student stuR = (Student)ois.readObject();
 System.out.println(stuR);
 }
Nach dem Login kopieren
Beim Schreiben einer Datei wird nur eine Anweisung verwendet, writeObject, und beim Lesen wird nur eine Anweisung, readObject, verwendet. Und die Set- und Get-Methoden in Student werden nicht mehr verwendet. Ist es nicht ganz einfach? Als nächstes werden Implementierungsdetails vorgestellt.

2. Grundlegender Algorithmus für die Serialisierung

Bei diesem Mechanismus entspricht jedes Objekt einer eindeutigen Seriennummer, und jedes Objekt wird auch gespeichert entspricht jedem unterschiedlichen Objekt gemäß dieser Seriennummer. Unter Objektserialisierung versteht man die Verwendung der Seriennummer jedes Objekts zum Speichern und Lesen. Nehmen Sie zunächst das Schreiben eines Objekts in einen Stream. Für jedes Objekt werden die grundlegenden Informationen des Objekts im Stream gespeichert, wenn es zum ersten Mal angetroffen wird Speichern Sie diese Informationen und notieren Sie stattdessen die Seriennummer dieses Objekts (da die Daten nicht wiederholt gespeichert werden müssen). Beim Lesen wird jedes im Stream gefundene Objekt direkt ausgegeben, wenn es zum ersten Mal angetroffen wird. Wenn die Seriennummer eines Objekts gelesen wird, wird das zugehörige Objekt gefunden und ausgegeben.


Erklären Sie einige Punkte. Wenn ein Objekt serialisierbar sein möchte, muss es die

Schnittstelle java.io.Serializable; implementieren irgendetwas umsetzen. Unser ObjectOutputStream-Stream ist ein Stream, der Objektinformationen in Bytes konvertieren kann. Der Konstruktor lautet wie folgt:

public ObjectOutputStream(OutputStream out)
Nach dem Login kopieren
Das heißt, alle Byte-Streams können als Parameter übergeben werden mit allen Byte-Operationen. Die Methoden writeObject und readObject werden in diesem Stream definiert, um die Serialisierung und Deserialisierung von Objekten zu implementieren. Natürlich können wir den Serialisierungsmechanismus auch anpassen, indem wir diese beiden Methoden in der Klasse implementieren, die später ausführlich vorgestellt werden. Hier müssen wir nur den gesamten Serialisierungsmechanismus verstehen. Es wird nur eine Kopie aller Objektdaten gespeichert. Wenn dasselbe Objekt erneut angezeigt wird, wird nur die entsprechende Seriennummer gespeichert. Im Folgenden werden wir seinen Grundalgorithmus in zwei besonderen Situationen intuitiv erleben.

Zwei besondere Beispiele

Schauen Sie sich zuerst das erste Beispiel an:

public class Student implements Serializable {

 String name;
 int age;
 Teacher t; //另外一个对象类型

 public Student(){}
 public Student(String name,int age,Teacher t){
 this.name = name;
 this.age=age;
 this.t = t;
 }

 public void setName(String name){this.name = name;}
 public void setAge(int age){this.age = age;}
 public void setT(Teacher t){this.t = t;}
 public String getName(){return this.name;}
 public int getAge(){return this.age;}
 public Teacher getT(){return this.t;}
}

public class Teacher implements Serializable {
 String name;

 public Teacher(String name){
 this.name = name;
 }
}

public static void main(String[] args) throws IOException, ClassNotFoundException {

 Teacher t = new Teacher("li");
 Student stu1 = new Student("walker",21,t);
 Student stu2 = new Student("yam",22,t);
 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello.txt"));
 oos.writeObject(stu1);
 oos.writeObject(stu2);

 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello.txt"));
 Student stuR1 = (Student)ois.readObject();
 Student stuR2 = (Student)ois.readObject();

 if (stuR1.getT() == stuR2.getT())
  System.out.println("相同对象");
 }
Nach dem Login kopieren
Das Ergebnis ist sehr offensichtlich Objekt wird ausgegeben. Wir haben in der Hauptfunktion zwei Schülertypobjekte definiert, aber beide

verweisen intern auf dasselbe Lehrerobjekt . Nachdem die Serialisierung abgeschlossen ist, werden die beiden Objekte deserialisiert. Durch den Vergleich, ob ihre internen Lehrerobjekte dieselbe Instanz sind, können Sie sehen, dass t in den Stream geschrieben wird, wenn das erste Schülerobjekt serialisiert wird, aber wenn Sie auf die Lehrerobjektinstanz stoßen Beim zweiten Schülerobjekt wurde festgestellt, dass es bereits geschrieben wurde, sodass es nicht mehr in den Stream geschrieben wird und nur die entsprechende Sequenznummer als Referenz gespeichert wird. Bei der Deserialisierung ist das Prinzip natürlich ähnlich. Dies ist derselbe grundlegende Algorithmus, den wir oben eingeführt haben.

Sehen Sie sich das zweite spezielle Beispiel unten an:

public class Student implements Serializable {

 String name;
 Teacher t;

}

public class Teacher implements Serializable {
 String name;
 Student stu;

}

public static void main(String[] args) throws IOException, ClassNotFoundException {

 Teacher t = new Teacher();
 Student s =new Student();
 t.name = "walker";
 t.stu = s;
 s.name = "yam";
 s.t = t;

 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello.txt"));
 oos.writeObject(t);
 oos.writeObject(s);
 oos.close();

 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello.txt"));
 Teacher tR = (Teacher)ois.readObject();
 Student sR = (Student)ois.readObject();
 if(tR == sR.t && sR == tR.stu)System.out.println("ok");

 }
Nach dem Login kopieren

输出的结果是ok,这个例子可以叫做:循环引用。从结果我们可以看出来,序列化之前两个对象存在的相互的引用关系,经过序列化之后,两者之间的这种引用关系是依然存在的。其实按照我们之前介绍的判断算法来看,首先我们先序列化了teacher对象,因为他内部引用了student的对象,两者都是第一次遇到,所以将两者序列化到流中,然后我们去序列化student对象,发现这个对象以及内部的teacher对象都已经被序列化了,于是只保存对应的序列号。读取的时候根据序列号恢复对象。

四、自定义序列化机制

综上,我们已经介绍完了基本的序列化与反序列化的知识。但是往往我们会有一些特殊的要求,这种默认的序列化机制虽然已经很完善了,但是有些时候还是不能满足我们的需求。所以我们看看如何自定义序列化机制。自定义序列化机制中,我们会使用到一个关键字,它也是我们之前在看源码的时候经常遇到的,transient。将字段声明transient,等于是告诉默认的序列化机制,这个字段你不要给我写到流中去,我会自己处理的。

public class Student implements Serializable {

 String name;
 transient int age;

 public String toString(){
 return this.name + ":" + this.age;
 }
}

public static void main(String[] args) throws IOException, ClassNotFoundException {

 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello.txt"));
 Student stu = new Student();
 stu.name = "walker";stu.age = 21;
 oos.writeObject(stu);

 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello.txt"));
 Student stuR = (Student)ois.readObject();

 System.out.println(stuR);
 }
Nach dem Login kopieren

输出结果:walker:0

我们不是给age字段赋初始值了么,怎么会是0呢?正如我们上文所说的一样,被transient修饰的字段不会被写入流中,自然读取出来就没有值,默认是0。下面看看我们怎么自己来序列化这个age。

//改动过的student类,main方法没有改动,大家可以往上看
public class Student implements Serializable {

 String name;
 transient int age;

 private void writeObject(ObjectOutputStream oos) throws IOException {
 oos.defaultWriteObject();

 oos.writeInt(25);
 }

 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
 ois.defaultReadObject();

 age = ois.readInt();
 }

 public String toString(){
 return this.name + ":" + this.age;
 }
}
Nach dem Login kopieren

输出结果:walker:25

结果既不是我么初始化的21,也不是0,而是我们在writeObject方法中写的25。现在我们一点一点看看每个步骤的意义。首先,要想要实现自定义序列化,就需要在该对象定义的类中实现两个方法,writeObject和readObject,而且格式必须和上面贴出来的一样,笔者试过改动方法修饰符,结果导致不能成功序列化。这是因为,Java采用反射机制,检查该对象所在的类中有没有实现这两个方法,没有的话就使用默认的ObjectOutputStream中的这个方法序列化所有字段,如果有的话就执行你自己实现的这个方法。

接下来,看看这两个方法实现的细节,先看writeObject方法,参数是ObjectOutputStream 类型的,这个拿到的是我们在main方法中定义的ObjectOutputStream 对象,要不然它怎么知道该把对象写到那个地方去呢?第一行我们调用的是oos.defaultWriteObject();这个方法实现的功能是,将当前对象中所有没有被transient修饰的字段写入流中,第二条语句我们显式的调用了writeInt方法将age的值写入流中。读取的方法类似,此处不再赘述。

五、版本控制

最后我们来看看,序列化过程的的版本控制问题。在我们将一个对象序列化到流中之后,该对象对应的类的结构改变了,如果此时我们再次从流中将之前保存的对象读取出来,会发生什么?这要分情况来说,如果原类中的字段被删除了,那从流中输出的对应的字段将会被忽略。如果原类中增加了某个字段,那新增的字段的值就是默认值。如果字段的类型发生了改变,抛出异常。在Java中每个类都会有一个记录版本号的变量:static final serivalVersionUID = 115616165165L,此处的值只用于演示并不对应任意某个类。这个版本号是根据该类中的字段等一些属性信息计算出来的,唯一性较高。每次读出的时候都会去比较之前和现在的版本号确认是否发生版本不一致情况,如果版本不一致,就会按照上述的情形分别做处理。

对象的序列化就写完了,如果有什么内容不妥的地方,希望大家指出!

Das obige ist der detaillierte Inhalt vonDetaillierter Beispielcode für die Serialisierung und Deserialisierung von Java-Objekten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage