摘要:序列化機制使得對象可以脫離程序的運行而獨立存在。普通序列化接口是一個標記接口,不用實現任何方法。如果此對象已經序列化過,則直接輸出編號即可。圖示上述序列化過程。
一、序列化的含義、意義及使用場景二、序列化實現的方式1、Serializable1.1 普通序列化1.2 成員是引用的序列化1.3 同一對象序列化多次的機制1.4 java序列化算法潛在的問題1.5 可選的自定義序列化2、Externalizable:強制自定義序列化3、兩種序列化對比三、序列化版本號serialVersionUID四、總結
一、序列化的含義、意義及使用場景如果需要將某個對象保存到磁盤上或者通過網絡傳輸,那么這個類應該實現Serializable接口或者Externalizable接口之一。
Serializable接口是一個標記接口,不用實現任何方法。一旦實現了此接口,該類的對象就是可序列化的。
步驟一:創建一個ObjectOutputStream輸出流;
步驟二:調用ObjectOutputStream對象的writeObject輸出可序列化對象。
public?class?Person?implements?Serializable?{
??private?String?name;
??private?int?age;
??//我不提供無參構造器
??public?Person(String?name,?int?age)?{
??????this.name?=?name;
??????this.age?=?age;
??}
??@Override
??public?String?toString()?{
??????return?"Person{"?+
??????????????"name=""?+?name?+?"""?+
??????????????",?age="?+?age?+
??????????????"}";
??}
}
public?class?WriteObject?{
??public?static?void?main(String[]?args)?{
??????try?(//創建一個ObjectOutputStream輸出流
???????????ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream("object.txt")))?{
??????????//將對象序列化到文件s
??????????Person?person?=?new?Person("9龍",?23);
??????????oos.writeObject(person);
??????}?catch?(Exception?e)?{
??????????e.printStackTrace();
??????}
??}
}
步驟一:創建一個ObjectInputStream輸入流;
步驟二:調用ObjectInputStream對象的readObject()得到序列化的對象。
我們將上面序列化到person.txt的person對象反序列化回來
public?class?Person?implements?Serializable?{
??private?String?name;
??private?int?age;
??//我不提供無參構造器
??public?Person(String?name,?int?age)?{
??????System.out.println("反序列化,你調用我了嗎?");
??????this.name?=?name;
??????this.age?=?age;
??}
??@Override
??public?String?toString()?{
??????return?"Person{"?+
??????????????"name=""?+?name?+?"""?+
??????????????",?age="?+?age?+
??????????????"}";
??}
}
public?class?ReadObject?{
??public?static?void?main(String[]?args)?{
??????try?(//創建一個ObjectInputStream輸入流
???????????ObjectInputStream?ois?=?new?ObjectInputStream(new?FileInputStream("person.txt")))?{
??????????Person?brady?=?(Person)?ois.readObject();
??????????System.out.println(brady);
??????}?catch?(Exception?e)?{
??????????e.printStackTrace();
??????}
??}
}
//輸出結果
//Person{name="9龍",?age=23}
waht");
如果一個可序列化的類的成員不是基本類型,也不是String類型,那這個引用類型也必須是可序列化的;否則,會導致此類不能序列化。
看例子,我們新增一個Teacher類。將Person去掉實現Serializable接口代碼。
public?class?Person{
????//省略相關屬性與方法
}
public?class?Teacher?implements?Serializable?{
????private?String?name;
????private?Person?person;
????public?Teacher(String?name,?Person?person)?{
????????this.name?=?name;
????????this.person?=?person;
????}
?????public?static?void?main(String[]?args)?throws?Exception?{
????????try?(ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream("teacher.txt")))?{
????????????Person?person?=?new?Person("路飛",?20);
????????????Teacher?teacher?=?new?Teacher("雷利",?person);
????????????oos.writeObject(teacher);
????????}
????}
}
我們看到程序直接報錯,因為Person類的對象是不可序列化的,這導致了Teacher的對象不可序列化
同一對象序列化多次,會將這個對象序列化多次嗎?答案是否定的。
public?class?WriteTeacher?{
????public?static?void?main(String[]?args)?throws?Exception?{
????????try?(ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream("teacher.txt")))?{
????????????Person?person?=?new?Person("路飛",?20);
????????????Teacher?t1?=?new?Teacher("雷利",?person);
????????????Teacher?t2?=?new?Teacher("紅發香克斯",?person);
????????????//依次將4個對象寫入輸入流
????????????oos.writeObject(t1);
????????????oos.writeObject(t2);
????????????oos.writeObject(person);
????????????oos.writeObject(t2);
????????}
????}
}
依次將t1、t2、person、t2對象序列化到文件teacher.txt文件中。
注意:反序列化的順序與序列化時的順序一致。
public?class?ReadTeacher?{
????public?static?void?main(String[]?args)?{
????????try?(ObjectInputStream?ois?=?new?ObjectInputStream(new?FileInputStream("teacher.txt")))?{
????????????Teacher?t1?=?(Teacher)?ois.readObject();
????????????Teacher?t2?=?(Teacher)?ois.readObject();
????????????Person?p?=?(Person)?ois.readObject();
????????????Teacher?t3?=?(Teacher)?ois.readObject();
????????????System.out.println(t1?==?t2);
????????????System.out.println(t1.getPerson()?==?p);
????????????System.out.println(t2.getPerson()?==?p);
????????????System.out.println(t2?==?t3);
????????????System.out.println(t1.getPerson()?==?t2.getPerson());
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????}
}
//輸出結果
//false
//true
//true
//true
//true
從輸出結果可以看出,Java序列化同一對象,并不會將此對象序列化多次得到多個對象。
所有保存到磁盤的對象都有一個序列化編碼號
當程序試圖序列化一個對象時,會先檢查此對象是否已經序列化過,只有此對象從未(在此虛擬機)被序列化過,才會將此對象序列化為字節序列輸出。
如果此對象已經序列化過,則直接輸出編號即可。
圖示上述序列化過程。
由于java序利化算法不會重復序列化同一個對象,只會記錄已序列化對象的編號。如果序列化一個可變對象(對象內的內容可更改)后,更改了對象內容,再次序列化,并不會再次將此對象轉換為字節序列,而只是保存序列化編號。
public?class?WriteObject?{
????public?static?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/6880.html
摘要:動態地代理,可以猜測一下它的含義,在運行時動態地對某些東西代理,代理它做了其他事情。所以動態代理的內容重點就是這個。所以下一篇我們來細致了解下的到底是怎么使用動態代理的。 之前講了《零基礎帶你看Spring源碼——IOC控制反轉》,本來打算下一篇講講Srping的AOP的,但是其中會涉及到Java的動態代理,所以先單獨一篇來了解下Java的動態代理到底是什么,Java是怎么實現它的。 ...
摘要:序列化機制使得對象可以脫離程序的運行而獨立存在。普通序列化接口是一個標記接口,不用實現任何方法。如果此對象已經序列化過,則直接輸出編號即可。圖示上述序列化過程。一、序列化的含義、意義及使用場景二、序列化實現的方式1、Serializable1.1 普通序列化1.2 成員是引用的序列化1.3 同一對象序列化多次的機制1.4 java序列化算法潛在的問題1.5 可選的自定義序列化2、Extern...
摘要:序列化機制使得對象可以脫離程序的運行而獨立存在。普通序列化接口是一個標記接口,不用實現任何方法。如果此對象已經序列化過,則直接輸出編號即可。圖示上述序列化過程。一、序列化的含義、意義及使用場景二、序列化實現的方式1、Serializable1.1 普通序列化1.2 成員是引用的序列化1.3 同一對象序列化多次的機制1.4 java序列化算法潛在的問題1.5 可選的自定義序列化2、Extern...
摘要:手動創建執行線程存在以上問題,而線程池就是用來解決這些問題的。線程池詳解上面我們已經知道了線程池的作用,而對于這樣一個好用,重要的工具,當然已經為我們提供了實現,這也是本篇文章的重點。,線程池一旦空閑超過時間,線程都將被回收。 showImg(https://segmentfault.com/img/remote/1460000018476903); 本文原創地址,我的博客:https...
摘要:注解在類上為類提供一個全參的構造方法,加了這個注解后,類中不提供默認構造方法了。這個注解用在類上,使用類中所有帶有注解的或者帶有修飾的成員變量生成對應的構造方法。 轉載請注明原創地址:http://www.54tianzhisheng.cn/2018/01/07/lombok/ showImg(http://ohfk1r827.bkt.clouddn.com/blog/180107/7...
閱讀 2984·2023-04-26 00:23
閱讀 3399·2021-09-13 10:28
閱讀 2178·2021-08-31 14:18
閱讀 2884·2019-08-30 15:54
閱讀 1939·2019-08-30 15:43
閱讀 1276·2019-08-29 16:56
閱讀 2800·2019-08-29 14:16
閱讀 2053·2019-08-28 17:51