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