Java序列化,java序列化和還原序列化

來源:互聯網
上載者:User

Java序列化,java序列化和還原序列化
1.概述通過序列化機制,我們可以把Java記憶體中的對象轉換成二進位位元組流,這樣就可以把JavaObject Storage Service到磁碟中,或者在網路中傳輸Java對象。
1.1序列化的含義和意義序列化機制允許將實現序列化的Java對象轉換成位元組序列,這些自己序列可以儲存在磁碟上,或通過網路傳輸,以備以後重新恢複原來的對象。序列化機制使得對象可以脫離程式的運行而單獨存在。
對象的序列化(Serilize)指將一個Java對象寫入IO流中,與此相反的是對象的還原序列化(Deserialize)則指從IO流中恢複該Java對象。
如果需要讓某個對象支援序列化機制,則必須讓它的類實現下面兩個介面之一:
Seriliazable
Externalizable
所有網路上傳輸的對象的類都應該是可序列化的,比如RMI(遠程方法調用)過程中的參數和返回值。

所有需要儲存在磁碟中的對象的類都必須是可序列化的,比如Web應用中需要儲存到HttpSession或SevletContext屬性中的應用。

2.使用物件流程實現序列化

import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class SerializeTest {public static void main(String[] args) {try {ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("src/com/t/color.txt"));Color color=new Color("Red");oos.writeObject(color);//將對象寫入輸出資料流} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}try {ObjectInputStream ois=new ObjectInputStream(new FileInputStream("src/com/t/color.txt"));//從輸入資料流中讀取對象並強制轉換成Color類Color col=(Color)ois.readObject();System.out.println(col.getColor());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}}class Color implements Serializable{                 private static final long serialVersionUID = -3398911857061187891L;private String color;public Color(String color) {this.color=color;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}}

PS:還原序列化無須通過構造器來初始化Java對象。
如果使用序列化機制向檔案中寫入多個Java對象,使用還原序列化機制恢複對象時必須按實際寫入的順序讀取。

3.對象引用的序列化如果一個類中的成員變數有參考型別(不是基本類型或String類型),那麼這個參考型別必須是可序列化的,否則該類不可以序列化,即使它實現了Seriliazable或Externalizable也不能序列化。

import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class SerializeTest {public static void main(String[] args) {try {ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("src/com/t/color.txt"));Color color=new Color("Red");Person person=new Person("lavor_zl", color);oos.writeObject(color);//將對象寫入輸出資料流oos.writeObject(person);//將對象寫入輸出資料流} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}try {ObjectInputStream ois=new ObjectInputStream(new FileInputStream("src/com/t/color.txt"));//從輸入資料流中讀取對象並強制轉換成Color類Color col=(Color)ois.readObject();System.out.println(col.getColor());                        Person per=(Person)ois.readObject();                        System.out.println(per.getName());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}}class Color implements Serializable{/** *  */private static final long serialVersionUID = -3398911857061187891L;private String color;public Color(String color) {this.color=color;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}}class Person implements Serializable{/** *  */private static final long serialVersionUID = 3426878037487779564L;private String name;private Color color;public Person(String name,Color color) {this.name=name;this.color=color;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Color getColor() {return color;}public void setColor(Color color) {this.color = color;}}

Color color=new Color("Red");
Person person=new Person("lavor_zl", color);
oos.writeObject(color);//將對象寫入輸出資料流
oos.writeObject(person);//將對象寫入輸出資料流
一般情況下,這裡建立序列化的順序是先序列化color對象,在序列化person對象並且將再次序列化person對象所引用的Color對象,但是這裡person對象引用的Color類對象剛好是前面已經序列化了的color對象。情況會不一樣。
那麼Java序列化機制採用的序列化規則到底是怎麼樣的啊?
1、所有儲存到磁碟中的對象都有一個序列化編號。
2、當程式試圖序列化一個對象時,程式會檢查該對象是否已經被序列化過,只有該對象從未在本次虛擬機器中序列化過,系統才會將該對象轉換成位元組序列並輸出。
3、如果每個對象已經被序列化過,程式只是直接輸出一個序列化編號,而不是再次重新序列化該對象。
正是基於這些規則,多次序列化一個對象時,只有第一次序列化時才會把該Java對象轉換成位元組序列輸出,即使後面改變了該對象的成員變數,還原序列化時改變的成員變數的值也不會被輸出。

4.自訂序列化當我們序列化某個對象時,如果不想序列化該對象的某個成員變數時,可以用transient關鍵字修飾該成員變數,transient關鍵字只能修飾成員變數。用transient關鍵字修飾的成員變數將被完全隔離在序列化機制之外。這樣導致在還原序列化恢複Java對象時無法擷取該變數的值,Java還提供一種自訂序列化機制,通過自訂序列化可以讓程式控制如何序列化各成員變數,甚至完全不序列化某些成員變數(與使用transient關鍵字效果相同)。
4.1一種自訂序列化機制
在序列化和還原序列化過程中需要特殊處理的類應該提供如下特殊的簽名方法,這些特殊的簽名方法用來來實現自訂序列化。

private void writeObject(java.io.ObjectOutputStream out)throws IOException
private void readObject(java.io.ObjectInputStream in)throws IOException,ClassNotFoundException
private void readObjectNoData()throws ObjectStreamException

import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Test implements Serializable{private static final long serialVersionUID = 6102026641912972144L;private int id;private String name;public Test(int id,String name) {this.id=id;this.name=name;}private void writeObject(ObjectOutputStream out)throws IOException{out.writeInt(id);out.writeChars(name);}private void readObject(ObjectInputStream in)throws IOException,ClassNotFoundException{this.id=in.readInt();//this.name=in.readLine()也可以,不過readLine()已經不推薦使用this.name=(String) in.readObject();}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

PS:readObject()方法讀取成員變數的順序應該和writeObject()儲存塵成員變數的順序一致,否則不能正常恢複該Java對象。
static關鍵字修飾的成員變數也不可以被序列化,因為它是屬於類的而不是屬於對象的


還有一種更徹底的自訂序列化機制,它甚至可以在序列化該對象時將該對象替換成其他對象。可以通過一下方法實現
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
此方法有序列化機制在序列化之前調用,只要該方法存在。

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.io.Serializable;import java.util.ArrayList;public class Test implements Serializable{private int id;private String name;public Test(int id,String name) {this.id=id;this.name=name;}//重寫writeReplace()方法,程式在序列化該類對象之前調用該方法private Object writeReplace()throws ObjectStreamException{ArrayList<Object> list=new ArrayList<Object>();list.add(id);list.add(name);return list;}public static void main(String[] args) {try{ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("replace.txt"));ObjectInputStream ois=new ObjectInputStream(new FileInputStream("replace.txt"));Test test=new Test(1, "lavor_zl");oos.writeObject(test);ArrayList<Object> list=(ArrayList<Object>) ois.readObject();System.out.println(list);//輸出:[1, lavor_zl]}catch(Exception e){e.printStackTrace();}}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

與writeReplace()相對,序列化機制還有一個特殊的方法,它可以實現保護性的複製整個對象
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
該方法緊跟著readObject()方法之後調用,該方法返回值將會替代原來的還原序列化對象。
readResolve()方法在序列化單例類、枚舉類時尤其有用。

4.1另一種自訂序列化機制Java還提供另一種自訂序列化機制,這種序列化方式完全由程式員決定儲存和恢複對象資料。要實現該目標,Java類必須實現Externalizable介面。
void writeExternal(ObjectOutput out):需要序列化的類實現該方法來儲存對象的狀態
void readExternal(ObjectInput in):需要序列化的類通過該方法來實現還原序列化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.