成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java對象的序列化與反序列化

開發 開發工具
序列化 (Serialization)是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程。一般將一個對象存儲至一個儲存媒介,例如檔案或是記億體緩沖等。在網絡傳輸過程中,可以是字節或是XML等格式。

序列化與反序列化

序列化 (Serialization)是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程。一般將一個對象存儲至一個儲存媒介,例如檔案或是記億體緩沖等。在網絡傳輸過程中,可以是字節或是XML等格式。而字節的或XML編碼格式可以還原完全相等的對象。這個相反的過程又稱為反序列化。

Java對象的序列化與反序列化

在Java中,我們可以通過多種方式來創建對象,并且只要對象沒有被回收我們都可以復用該對象。但是,我們創建出來的這些Java對象都是存在于JVM的堆內存中的。只有JVM處于運行狀態的時候,這些對象才可能存在。一旦JVM停止運行,這些對象的狀態也就隨之而丟失了。

[[222942]]

但是在真實的應用場景中,我們需要將這些對象持久化下來,并且能夠在需要的時候把對象重新讀取出來。Java的對象序列化可以幫助我們實現該功能。

對象序列化機制(object serialization)是Java語言內建的一種對象持久化方式,通過對象序列化,可以把對象的狀態保存為字節數組,并且可以在有需要的時候將這個字節數組通過反序列化的方式再轉換成對象。對象序列化可以很容易的在JVM中的活動對象和字節數組(流)之間進行轉換。

在Java中,對象的序列化與反序列化被廣泛應用到RMI(遠程方法調用)及網絡傳輸中。

相關接口及類

Java為了方便開發人員將Java對象進行序列化及反序列化提供了一套方便的API來支持。其中包括以下接口和類:

  • java.io.Serializable
  • java.io.Externalizable
  • ObjectOutput
  • ObjectInput
  • ObjectOutputStream
  • ObjectInputStream

Serializable 接口

類通過實現 java.io.Serializable 接口以啟用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用于標識可序列化的語義。

當試圖對一個對象進行序列化的時候,如果遇到不支持 Serializable 接口的對象。在此情況下,將拋出 NotSerializableException。

雖然Serializable接口中并沒有定義任何屬性和方法,但是如果一個類想要具備序列化能力也比必須要實現它。其實,主要是因為序列化在真正的執行過程中會使用instanceof判斷一個類是否實現類Serializable,如果未實現則直接拋出異常。關于這部分內容,我會單開一篇文章講解。

如果要序列化的類有父類,要想同時將在父類中定義過的變量持久化下來,那么父類也應該集成java.io.Serializable接口。

下面是一個實現了java.io.Serializable接口的類

  1. package com.hollischaung.serialization.SerializableDemos; 
  2. import java.io.Serializable
  3. /** 
  4. * Created by hollis on 16/2/17. 
  5. * 實現Serializable接口 
  6. */ 
  7. public class User1 implements Serializable { 
  8.    private String name
  9.    private int age; 
  10.    public String getName() { 
  11.        return name
  12.    } 
  13.    public void setName(String name) { 
  14.        this.name = name
  15.    } 
  16.    public int getAge() { 
  17.        return age; 
  18.    } 
  19.    public void setAge(int age) { 
  20.        this.age = age; 
  21.    } 
  22.    @Override 
  23.    public String toString() { 
  24.        return "User{" + 
  25.                "name='" + name + '\'' + 
  26.                ", age=" + age + 
  27.                '}'
  28.    } 

通過下面的代碼進行序列化及反序列化

  1. package com.hollischaung.serialization.SerializableDemos; 
  2.  
  3. import java.io.File; 
  4. import java.io.FileInputStream; 
  5. import java.io.FileOutputStream; 
  6. import java.io.IOException; 
  7. import java.io.ObjectInputStream; 
  8. import java.io.ObjectOutputStream; 
  9.  
  10. /** 
  11. * Created by hollis on 16/2/17. 
  12. * SerializableDemo1 結合SerializableDemo2說明 一個類要想被序列化必須實現Serializable接口 
  13. */ 
  14. public class SerializableDemo1 { 
  15.  
  16.    public static void main(String[] args) { 
  17.        //Initializes The Object 
  18.        User1 user = new User1(); 
  19.        user.setName("hollis"); 
  20.        user.setAge(23); 
  21.        System.out.println(user); 
  22.  
  23.        //Write Obj to File 
  24.        try (FileOutputStream fos = new FileOutputStream("tempFile"); ObjectOutputStream oos = new ObjectOutputStream( 
  25.            fos)) { 
  26.            oos.writeObject(user); 
  27.        } catch (IOException e) { 
  28.            e.printStackTrace(); 
  29.        } 
  30.  
  31.        //Read Obj from File 
  32.        File file = new File("tempFile"); 
  33.        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { 
  34.            User1 newUser = (User1)ois.readObject(); 
  35.            System.out.println(newUser); 
  36.        } catch (IOException | ClassNotFoundException e) { 
  37.            e.printStackTrace(); 
  38.        } 
  39.    } 
  40.  
  41. //OutPut
  42. //User{name='hollis', age=23} 
  43. //User{name='hollis', age=23} 

如果你觀察夠細微的話,你可能會發現,我在上面的測試代碼中使用了IO流,但是我并沒有顯示的關閉他。這其實是Java 7中的新特性try-with-resources。這其實是Java中的一個語法糖,背后原理其實是編譯器幫我們做了關閉IO流的工作。后面我會單獨出一篇文章介紹下如何使用語法糖提高代碼質量。

上面的代碼中,我們將代碼中定義出來的User對象通過序列化的方式保存到文件中,然后再從文件中將他到序列化成Java對象。結果是我們的對象的屬性均被持久化了下來。

Externalizable接口

除了Serializable 之外,java中還提供了另一個序列化接口Externalizable

為了了解Externalizable接口和Serializable接口的區別,先來看代碼,我們把上面的代碼改成使用Externalizable的形式。

  1. package com.hollischaung.serialization.ExternalizableDemos; 
  2.  
  3. import java.io.Externalizable; 
  4. import java.io.IOException; 
  5. import java.io.ObjectInput; 
  6. import java.io.ObjectOutput; 
  7.  
  8. /** 
  9. * Created by hollis on 16/2/17. 
  10. * 實現Externalizable接口 
  11. */ 
  12. public class User1 implements Externalizable { 
  13.  
  14.    private String name
  15.    private int age; 
  16.  
  17.    public String getName() { 
  18.        return name
  19.    } 
  20.    public void setName(String name) { 
  21.        this.name = name
  22.    } 
  23.    public int getAge() { 
  24.        return age; 
  25.    } 
  26.    public void setAge(int age) { 
  27.        this.age = age; 
  28.    } 
  29.    public void writeExternal(ObjectOutput out) throws IOException { 
  30.  
  31.    } 
  32.    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
  33.  
  34.    } 
  35.    @Override 
  36.    public String toString() { 
  37.        return "User{" + 
  38.                "name='" + name + '\'' + 
  39.                ", age=" + age + 
  40.                '}'
  41.    } 
  1. package com.hollischaung.serialization.ExternalizableDemos; 
  2.  
  3. import java.io.*; 
  4.  
  5. /** 
  6. * Created by hollis on 16/2/17. 
  7. * 對一個實現了Externalizable接口的類進行序列化及反序列化 
  8. */ 
  9. public class ExternalizableDemo1 { 
  10.  
  11.   public static void main(String[] args) { 
  12.       //Write Obj to file 
  13.       User1 user = new User1(); 
  14.       user.setName("hollis"); 
  15.       user.setAge(23); 
  16.       try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"))){ 
  17.           oos.writeObject(user); 
  18.       } catch (IOException e) { 
  19.           e.printStackTrace(); 
  20.       } 
  21.  
  22.       //Read Obj from file 
  23.       File file = new File("tempFile"); 
  24.       try(ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file))){ 
  25.           User1 newInstance = (User1) ois.readObject(); 
  26.           //output 
  27.           System.out.println(newInstance); 
  28.       } catch (IOException | ClassNotFoundException e ) { 
  29.           e.printStackTrace(); 
  30.       } 
  31.   } 
  32. //OutPut
  33. //User{name='null', age=0} 

通過上面的實例的輸出結果可以發現,對User1類進行序列化及反序列化之后得到的對象的所有屬性的值都變成了默認值。也就是說,之前的那個對象的狀態并沒有被持久化下來。這就是Externalizable接口和Serializable接口的區別:

Externalizable繼承了Serializable,該接口中定義了兩個抽象方法:writeExternal()與readExternal()。當使用Externalizable接口來進行序列化與反序列化的時候需要開發人員重寫writeExternal()與readExternal()方法。

由于上面的代碼中,并沒有在這兩個方法中定義序列化實現細節,所以輸出的內容為空。還有一點值得注意:在使用Externalizable進行序列化的時候,在讀取對象時,會調用被序列化類的無參構造器去創建一個新的對象,然后再將被保存對象的字段的值分別填充到新對象中。所以,實現Externalizable接口的類必須要提供一個public的無參的構造器。

如果實現了Externalizable接口的類中沒有無參數的構造函數,在運行時會拋出異常:java.io.InvalidClassException。如果一個Java類沒有定義任何構造函數,編譯器會幫我們自動添加一個無參的構造方法,可是,如果我們在類中定義了一個有參數的構造方法了,編譯器便不會再幫我們創建無參構造方法,這點需要注意。

按照要求修改之后代碼如下:

  1. package com.hollischaung.serialization.ExternalizableDemos; 
  2.  
  3. import java.io.Externalizable; 
  4. import java.io.IOException; 
  5. import java.io.ObjectInput; 
  6. import java.io.ObjectOutput; 
  7.  
  8. /** 
  9. * Created by hollis on 16/2/17. 
  10. * 實現Externalizable接口,并實現writeExternal和readExternal方法 
  11. */ 
  12. public class User2 implements Externalizable { 
  13.  
  14.    private String name
  15.    private int age; 
  16.  
  17.    public String getName() { 
  18.        return name
  19.    } 
  20.    public void setName(String name) { 
  21.        this.name = name
  22.    } 
  23.    public int getAge() { 
  24.        return age; 
  25.    } 
  26.    public void setAge(int age) { 
  27.        this.age = age; 
  28.    } 
  29.    public void writeExternal(ObjectOutput out) throws IOException { 
  30.        out.writeObject(name); 
  31.        out.writeInt(age); 
  32.    } 
  33.    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
  34.        name = (String) in.readObject(); 
  35.        age = in.readInt(); 
  36.    } 
  37.  
  38.    @Override 
  39.    public String toString() { 
  40.        return "User{" + 
  41.                "name='" + name + '\'' + 
  42.                ", age=" + age + 
  43.                '}'
  44.    } 

再執行測試得到以下結果

  1. //OutPut
  2. //User{name='hollis', age=23} 

這次,就可以把之前的對象狀態持久化下來了。

ObjectOutput和ObjectInput 接口

上面的writeExternal方法和readExternal方法分別接收ObjectOutput和ObjectInput類型參數。這兩個類作用如下。

ObjectInput 擴展自 DataInput 接口以包含對象的讀操作。

DataInput 接口用于從二進制流中讀取字節,并根據所有 Java 基本類型數據進行重構。同時還提供根據 UTF-8 修改版格式的數據重構 String 的工具。

對于此接口中的所有數據讀取例程來說,如果在讀取所需字節數之前已經到達文件末尾 (end of file),則將拋出 EOFException(IOException 的一種)。如果因為到達文件末尾以外的其他原因無法讀取字節,則將拋出 IOException 而不是 EOFException。尤其是,在輸入流已關閉的情況下,將拋出 IOException。

ObjectOutput 擴展 DataOutput 接口以包含對象的寫入操作。

DataOutput 接口用于將數據從任意 Java 基本類型轉換為一系列字節,并將這些字節寫入二進制流。同時還提供了一個將 String 轉換成 UTF-8 修改版格式并寫入所得到的系列字節的工具。

對于此接口中寫入字節的所有方法,如果由于某種原因無法寫入某個字節,則拋出 IOException。

ObjectOutputStream、ObjectInputStream類

通過前面的代碼片段中我們也能知道,我們一般使用ObjectOutputStream的writeObject方法把一個對象進行持久化。再使用ObjectInputStream的readObject從持久化存儲中把對象讀取出來。

更多關于ObjectInputStream和ObjectOutputStream的相關知識,我會單獨有一篇文章介紹,敬請期待。

transient 關鍵字

transient 關鍵字的作用是控制變量的序列化,在變量聲明前加上該關鍵字,可以阻止該變量被序列化到文件中,在被反序列化后,transient 變量的值被設為初始值,如 int 型的是 0,對象型的是 null。關于transient 關鍵字的拓展同樣下一篇文章介紹。

序列化ID

虛擬機是否允許反序列化,不僅取決于類路徑和功能代碼是否一致,一個非常重要的一點是兩個類的序列化 ID 是否一致(就是 private static final long serialVersionUID)

序列化 ID 在 Eclipse 下提供了兩種生成策略,一個是固定的 1L,一個是隨機生成一個不重復的 long 類型數據(實際上是使用 JDK 工具生成),在這里有一個建議,如果沒有特殊需求,就是用默認的 1L 就可以,這樣可以確保代碼一致時反序列化成功。那么隨機生成的序列化 ID 有什么作用呢,有些時候,通過改變序列化 ID 可以用來限制某些用戶的使用。

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2011-06-01 15:05:02

序列化反序列化

2012-04-13 10:45:59

XML

2009-06-14 22:01:27

Java對象序列化反序列化

2022-08-06 08:41:18

序列化反序列化Hessian

2023-12-13 13:49:52

Python序列化模塊

2009-08-24 17:14:08

C#序列化

2009-09-09 15:47:27

XML序列化和反序列化

2009-09-09 14:45:41

XML序列化和反序列化

2011-05-18 15:20:13

XML

2009-08-06 11:16:25

C#序列化和反序列化

2010-03-19 15:54:21

Java Socket

2019-11-20 10:07:23

web安全PHP序列化反序列化

2009-08-25 14:24:36

C#序列化和反序列化

2011-06-01 14:50:48

2016-09-21 00:15:27

2016-01-05 15:10:59

2023-11-20 08:44:18

數據序列化反序列化

2021-11-18 07:39:41

Json 序列化Vue

2009-08-25 14:43:26

C#序列化和反序列化

2009-09-09 16:10:11

.NET序列化和反序列
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲综合区 | 亚洲国产区 | 黄免费在线 | 亚洲va国产日韩欧美精品色婷婷 | 日日操夜夜操天天操 | 色综合99| 欧美福利视频一区 | 91在线 | 亚洲一区二区电影在线观看 | 亚洲国产成人精品女人久久久 | 国产精品久久久久一区二区三区 | 国产在线观看一区二区 | 国产午夜精品一区二区三区嫩草 | 欧美啪啪网站 | av网站在线看 | 在线播放一区二区三区 | 天天操夜夜爽 | 国产99热精品 | 男人阁久久 | 色婷婷激情综合 | 久草视频网站 | 日韩中文字幕视频 | 亚洲国产精品久久久久秋霞不卡 | 欧美一区二区在线 | 国产不卡一区在线观看 | 免费在线黄色av | 亚洲国产精品99久久久久久久久 | 欧美性一级 | 久久夜夜 | 久久9视频 | 亚洲精品粉嫩美女一区 | 欧美视频成人 | 中文字幕第100页 | 亚洲高清网| xxx.在线观看 | 久久免费看 | xxxxx免费视频 | 不卡一区 | 久久综合一区二区三区 | 久久久久一区二区三区四区 | www久久国产|