您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Java 如何使用對象流實現序列化,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
對象序列化
對象序列化機制允許把內存中的Java對象轉換成與平臺無關的二進制流,從而可以保存到磁盤或者進行網絡傳輸,其它程序獲得這個二進制流后可以將其恢復成原來的Java對象。 序列化機制可以使對象可以脫離程序的運行而對立存在
序列化的含義和意義
序列化
序列化機制可以使對象可以脫離程序的運行而對立存在
序列化(Serialize)指將一個java對象寫入IO流中,與此對應的是,對象的反序列化(Deserialize)則指從IO流中恢復該java對象
如果需要讓某個對象可以支持序列化機制,必須讓它的類是可序列化(serializable),為了讓某個類可序列化的,必須實現如下兩個接口之一:
使用對象流實現序列化
實現Serializable實現序列化的類,程序可以通過如下兩個步驟來序列化該對象:
1.創建一個ObjectOutputStream,這個輸出流是一個處理流,所以必須建立在其他節點流的基礎之上
// 創建個ObjectOutputStream輸出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
2.調用ObjectOutputStream對象的writeObject方法輸出可序列化對象
// 將一個Person對象輸出到輸出流中 oos.writeObject(per);
定義一個NbaPlayer類,實現Serializable接口,該接口標識該類的對象是可序列化的
public class NbaPlayer implements java.io.Serializable { private String name; private int number; // 注意此處沒有提供無參數的構造器! public NbaPlayer(String name, int number) { System.out.println("有參數的構造器"); this.name = name; this.number = number; } // name的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } // number的setter和getter方法 public void setNumber(int number) { this.number = number; } public int getNumber() { return this.number; } }
使用ObjectOutputStream將一個NbaPlayer對象寫入磁盤文件
import java.io.*; public class WriteObject { public static void main(String[] args) { try( // 創建一個ObjectOutputStream輸出流 ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("object.txt"))) { NbaPlayer player = new NbaPlayer("維斯布魯克", 0); // 將player對象寫入輸出流 oos.writeObject(player); } catch (IOException ex) { ex.printStackTrace(); } } }
反序列化
從二進制流中恢復Java對象,則需要使用反序列化,程序可以通過如下兩個步驟來序列化該對象:
1.創建一個ObjectInputStream輸入流,這個輸入流是一個處理流,所以必須建立在其他節點流的基礎之上
// 創建個ObjectInputStream輸出流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
2.調用ObjectInputStream對象的readObject()方法讀取流中的對象,該方法返回一個Object類型的Java對象,可進行強制類型轉換成其真實的類型
// 從輸入流中讀取一個Java對象,并將其強制類型轉換為Person類 Person p = (Person)ois.readObject();
從object.txt文件中讀取NbaPlayer對象的步驟
import java.io.*; public class ReadObject { public static void main(String[] args) { try( // 創建一個ObjectInputStream輸入流 ObjectInputStream ois = new ObjectInputStream( new FileInputStream("object.txt"))) { // 從輸入流中讀取一個Java對象,并將其強制類型轉換為NbaPlayer類 NbaPlayer player = (NbaPlayer)ois.readObject(); System.out.println("名字為:" + player.getName() + "\n號碼為:" + player.getNumber()); } catch (Exception ex) { ex.printStackTrace(); } } }
反序列化讀取的僅僅是Java對象的數據,而不是Java類,因此采用反序列化恢復Java對象時,必須提供Java對象所屬的class文件,否則會引發ClassNotFoundException異常;反序列化機制無須通過構造器來初始化Java對象
如果使用序列化機制向文件中寫入了多個Java對象,使用反序列化機制恢復對象必須按照實際寫入的順序讀取。當一個可序列化類有多個父類時(包括直接父類和間接父類),這些父類要么有無參的構造器,要么也是可序列化的—否則反序列化將拋出InvalidClassException異常。如果父類是不可序列化的,只是帶有無參數的構造器,則該父類定義的Field值不會被序列化到二進制流中
對象引用的序列化
如果某個類的Field類型不是基本類型或者String類型,而是另一個引用類型,那么這個引用類型必須是可序列化的,否則有用該類型的Field的類也是不可序列化的
public class AllStar implements java.io.Serializable { private String name; private NbaPlayer player; public AllStar(String name, NbaPlayer player) { this.name = name; this.player = player; } // 此處省略了name和player的setter和getter方法 // name的setter和getter方法 public String getName() { return this.name; } public void setName(String name) { this.name = name; } // player的setter和getter方法 public NbaPlayer getPlayer() { return player; } public void setPlayer(NbaPlayer player) { this.player = player; } }
Java特殊的序列化算法
import java.io.*; public class WriteAllStar { public static void main(String[] args) { try( // 創建一個ObjectOutputStream輸出流 ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("allStar.txt"))) { NbaPlayer player = new NbaPlayer("詹姆斯哈登", 13); AllStar allStar1 = new AllStar("西部全明星", player); AllStar allStar2 = new AllStar("首發后衛", player); // 依次將四個對象寫入輸出流 oos.writeObject(allStar1); oos.writeObject(allStar2); oos.writeObject(player); oos.writeObject(allStar2); } catch (IOException ex) { ex.printStackTrace(); } } }
4個寫入輸出流的對象,實際上只序列化了3個,而且序列的兩個AllStar對象的player引用實際是同一個NbaPlayer對象。以下程序讀取序列化文件中的對象
import java.io.*; public class ReadAllStar { public static void main(String[] args) { try( // 創建一個ObjectInputStream輸出流 ObjectInputStream ois = new ObjectInputStream( new FileInputStream("allStar.txt"))) { // 依次讀取ObjectInputStream輸入流中的四個對象 AllStar star1 = (AllStar)ois.readObject(); AllStar star2 = (AllStar)ois.readObject(); NbaPlayer player = (NbaPlayer)ois.readObject(); AllStar star3 = (AllStar)ois.readObject(); // 輸出true System.out.println("star1的player引用和player是否相同:" + (star1.getPlayer() == player)); // 輸出true System.out.println("star2的player引用和player是否相同:" + (star2.getPlayer() == player)); // 輸出true System.out.println("star2和star3是否是同一個對象:" + (star2 == star3)); } catch (Exception ex) { ex.printStackTrace(); } } }
如果多次序列化同一個可變Java對象時,只有第一次序列化時才會把該Java對象轉換成字節序列并輸出
當使用Java序列化機制序列化可變對象時,只有第一次調用WriteObject()方法來輸出對象時才會將對象轉換成字節序列,并寫入到ObjectOutputStream;即使在后面程序中,該對象的實例變量發生了改變,再次調用WriteObject()方法輸出該對象時,改變后的實例變量也不會被輸出
import java.io.*; public class SerializeMutable { public static void main(String[] args) { try( // 創建一個ObjectOutputStream輸入流 ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("mutable.txt")); // 創建一個ObjectInputStream輸入流 ObjectInputStream ois = new ObjectInputStream( new FileInputStream("mutable.txt"))) { NbaPlayer player = new NbaPlayer("斯蒂芬庫里", 30); // 系統會player對象轉換字節序列并輸出 oos.writeObject(player); // 改變per對象的name實例變量 player.setName("塞斯庫里"); // 系統只是輸出序列化編號,所以改變后的name不會被序列化 oos.writeObject(player); NbaPlayer player1 = (NbaPlayer)ois.readObject(); //① NbaPlayer player2 = (NbaPlayer)ois.readObject(); //② // 下面輸出true,即反序列化后player1等于player2 System.out.println(player1 == player2); // 下面依然看到輸出"斯蒂芬庫里",即改變后的實例變量沒有被序列化 System.out.println(player2.getName()); } catch (Exception ex) { ex.printStackTrace(); } } }
上述就是小編為大家分享的Java 如何使用對象流實現序列化了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。