java对象的序列化机制详解
Java對(duì)象的序列化機(jī)制
??Java對(duì)象的序列化,是將內(nèi)存中的java對(duì)象轉(zhuǎn)化為二進(jìn)制的字節(jié)流,然后保存到磁盤中或者在網(wǎng)絡(luò)上。這就是序列化對(duì)象,反序列化顧名思義就是將對(duì)象的二進(jìn)制字節(jié)流恢復(fù)成原來(lái)的對(duì)象。注意只有對(duì)象的類名和屬性能被序列化(包括基本類型,數(shù)組,對(duì)其他對(duì)象的引用)不包括方法,static屬性(靜態(tài)屬性),transient屬性(瞬態(tài)屬性)都不會(huì)被序列化。
??那什么叫做序列化的對(duì)象呢,在Java中不是所有類都是序列化類,如果一個(gè)類要實(shí)現(xiàn)序列化就必須實(shí)現(xiàn)下面兩個(gè)接口之一:
???(1)Serializable接口??(2)Externalizable接口
對(duì)于這兩個(gè)接口的區(qū)別后面就會(huì)知道的,我們先把類都實(shí)現(xiàn)Serializable接口,這個(gè)接口java沒有提供任何的方法,java設(shè)計(jì)他只是作為一個(gè)類的序列化的標(biāo)志,表明此類可以進(jìn)行序列化。
??如果要講java對(duì)象轉(zhuǎn)化為二進(jìn)制的字節(jié)流并寫出,就一定需要對(duì)象的流來(lái)進(jìn)行輸出,所以這里用到ObjectOutputStream類,這個(gè)輸出流是一個(gè)處理流,所以需要?jiǎng)?chuàng)建一個(gè)字節(jié)輸出流然后用這個(gè)處理流進(jìn)行包裝,所以處理流也叫作包裝流。反之ObjectInputSteam是將對(duì)象寫入的類。寫出的對(duì)象方法是ObjectOutputStem對(duì)象.writeObject(序列化對(duì)象的實(shí)例)。寫入的方法是ObjectInputStream的對(duì)象.readObject(序列化的對(duì)象);說(shuō)了這么多,我就做一個(gè)例子吧。。
??代碼:創(chuàng)建一個(gè)實(shí)現(xiàn)序列化的Person類
?
public class Person implements Externalizable {private String name;private int age;public Person1(String name,int age) {this.name=name;this.age=age;//這個(gè)地方用于測(cè)試序列化和反序列化對(duì)象時(shí)候?qū)嵗惖那闆rSystem.out.println("帶參數(shù)的構(gòu)造器的使用");}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}?
代碼:創(chuàng)建測(cè)試類,進(jìn)行測(cè)試
public static void main(String[] args) throws IOException {//如果處理流,當(dāng)關(guān)閉流的時(shí)候就不需要再將節(jié)點(diǎn)流進(jìn)行關(guān)閉了//這是對(duì)對(duì)象進(jìn)行寫出的操作(序列化對(duì)象)FileOutputStream fos=null;ObjectOutputStream oos=null;try {fos=new FileOutputStream(new File("E://javatest.txt"));oos=new ObjectOutputStream(fos);Person per=new Person("孫悟空",66);oos.writeObject(per);} catch (FileNotFoundException e) {// TODO Auto-generated catch block e.printStackTrace();}finally {if(oos!=null) {oos.close();}}//這是對(duì)對(duì)象進(jìn)行寫入的操作(反序列化對(duì)象)FileInputStream fis=null;ObjectInputStream ois=null;try {fis=new FileInputStream("E://javatest.txt");ois=new ObjectInputStream(fis);//處理流將文件的字節(jié)流進(jìn)行包裝//將對(duì)象反序列化寫入的時(shí)候得到的都是Object類型的數(shù)據(jù),必須進(jìn)行強(qiáng)制類型的轉(zhuǎn)化Person per=(Person)ois.readObject();System.out.println("姓名"+per.getName()+"年齡"+per.getAge());} catch (Exception e) {e.printStackTrace();} finally {if(ois!=null) {ois.close();}}}readObject方法會(huì)拋出ClassNotFoundException異常,也就是說(shuō)當(dāng)反序列化時(shí)候找不到對(duì)應(yīng)的java類會(huì)將引發(fā)這個(gè)異常,因?yàn)榉葱蛄谢x取的僅僅是java對(duì)象的數(shù)據(jù),而不是java類,因此采用反序列化恢復(fù)java對(duì)象時(shí),必須提供該java對(duì)象所屬類的class文件,否則就會(huì)引發(fā)該異常。
??輸出結(jié)果可以看出當(dāng)反序列化的時(shí)候構(gòu)造器沒有執(zhí)行,也就是反序列化類無(wú)需通過(guò)構(gòu)造器來(lái)進(jìn)行初始化java對(duì)象
?注:如果我們向文件中使用序列化機(jī)制寫入多個(gè)java的對(duì)象,使用反序列化機(jī)制恢復(fù)對(duì)象時(shí)必須按實(shí)際的寫入順序讀取。?
???Y(^o^)Y屬性是引用類型的對(duì)象的序列化
???我們上面所說(shuō)的屬性都是String類型和基本類型,如果我們需要一個(gè)引用類型呢,那么這個(gè)引用類型也必須是可序列化的類,否則擁有該類型的屬性類不可序列化。下面我將要定義一個(gè)引用類型的屬性,重新創(chuàng)建一個(gè)Teacher類,引用屬性必須實(shí)現(xiàn)序列化,否則Treacher不論實(shí)現(xiàn)不實(shí)現(xiàn)(1)Serializable接口??(2)Externalizable接口這兩個(gè)接口,他都不是序列化的類,因?yàn)楫?dāng)對(duì)象序列化的時(shí)候,會(huì)順帶著把引用類型的屬性進(jìn)行序列化,所以要想Teacher是序列化的類,則必須將Person的類進(jìn)行序列化。
??代碼Teacher類
?
public class Teacher implements Serializable {private String name;private Person student;//引用類型的屬性(這個(gè)Person類就是上面實(shí)現(xiàn)序列化的類)public Teacher(String name,Person student) {this.name=name;this.student=student;System.out.println("帶參數(shù)的構(gòu)造器的使用");}public String getName() {return name;}public void setName(String name) {this.name = name;}public Person getStudent() {return student;}public void setStudent(Person student) {this.student = student;} }?
代碼?測(cè)試代碼
public static void main(String[] args) throws IOException {// TODO Auto-generated method stub FileOutputStream fos=null;ObjectOutputStream oos=null;Person p=new Person("孫悟空",66);Teacher t1=new Teacher("玄奘法師",p);Teacher t2=new Teacher("菩提祖師",p);try {fos=new FileOutputStream(new File("E://javatext.txt"));oos=new ObjectOutputStream(fos);oos.writeObject(t1);oos.writeObject(t2);oos.writeObject(p);oos.writeObject(t1);} catch (FileNotFoundException e) {// TODO Auto-generated catch block e.printStackTrace();} finally {if(oos!=null) {oos.close();}}} }分析這段代碼可以看出我創(chuàng)建出來(lái)了三個(gè)類。Person?p=new?Person("孫悟空",66);Teacher?t1=new?Teacher("玄奘法師",p);Teacher?t2=new?Teacher("菩提祖師",p);如果我將這三個(gè)類進(jìn)行對(duì)象的序列化的話,t1寫出并且Person類也會(huì)進(jìn)行序列化,同理t2也是,然后我們又顯示序列化了Person類,所以Person類在此次寫出中,被序列化了三回,那么對(duì)于t1,t2來(lái)說(shuō)實(shí)際上他們的Person類是同一個(gè),但是如果Person序列化三回的話,t1,t2就沒有引用同一個(gè)Person類,這顯然是不符合實(shí)際情況的。Java對(duì)此采用了一種特殊的序列化算法,算法的內(nèi)容是:
(1)所有保存到磁盤中的對(duì)象都有一個(gè)序列化編號(hào)。
(2)當(dāng)程序師徒序列化一個(gè)對(duì)象的時(shí)候,程序?qū)⑾葯z查對(duì)象是否已經(jīng)序列化過(guò),只有當(dāng)該對(duì)象從未(在本次虛擬機(jī)中)被序列化過(guò),系統(tǒng)才會(huì)將該對(duì)象轉(zhuǎn)化成字節(jié)序列并輸出。
(3)如果某個(gè)對(duì)象是已經(jīng)序列化過(guò)的,程序?qū)⒅苯又皇禽敵鲆粋€(gè)序列化編號(hào),而不是重新序列化該對(duì)象。
Y(^o^)Y序列化的對(duì)象是可變的類
??根據(jù)java的序列化機(jī)制,當(dāng)我先寫進(jìn)去序列化的時(shí)候,如果我改變了可變類的屬性值,那么當(dāng)我想再次進(jìn)行序列化的時(shí)候就不能把更改后的值序列化了,因?yàn)閖ava的序列化機(jī)制當(dāng)在此序列化同一的對(duì)象的時(shí)候,輸出的是一個(gè)序列化編號(hào)。程序會(huì)比較兩個(gè)對(duì)象是同一個(gè)對(duì)象,就不會(huì)把對(duì)象重新的序列化。就是更改后的對(duì)象并沒有被寫入。這再次驗(yàn)證了java的序列化機(jī)制。
??代碼?測(cè)試類
public class VolatileClassTest {/*** 序列化可變類* @param args* @throws IOException * @throws ClassNotFoundException */public static void main(String[] args) throws IOException, ClassNotFoundException {// TODO Auto-generated method stub FileOutputStream fos=null;ObjectOutputStream oos=null;FileInputStream fis=null;ObjectInputStream ois=null;try {//進(jìn)行序列化的操作fos=new FileOutputStream(new File("E://javatest.txt"));oos=new ObjectOutputStream(fos);Person p=new Person("孫悟空",600);oos.writeObject(p);//將對(duì)象進(jìn)行序列化p.setName("紅孩兒");//可變類將姓名屬性設(shè)置為紅孩兒,可變類oos.writeObject(p);//將更改后的類進(jìn)行序列化//進(jìn)行反序列化操作fis=new FileInputStream(new File("E://javatest.txt"));ois=new ObjectInputStream(fis);Person per=(Person)ois.readObject();//輸出的姓名還是孫悟空,再次驗(yàn)證了java的序列化機(jī)制System.out.println("姓名是"+per.getName());} catch (FileNotFoundException e) {// TODO Auto-generated catch block e.printStackTrace();} finally {if(oos!=null) {oos.close();}if(ois!=null) {ois.close();}}} }?
轉(zhuǎn)載于:https://www.cnblogs.com/dukc/p/4823710.html
總結(jié)
以上是生活随笔為你收集整理的java对象的序列化机制详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一个线程加一运算,一个线程做减一运算,多
- 下一篇: [CareerCup] 9.6 Gene