本次講解中我們建立一個Java的項目去體會一下序列化Serializable的使用,序列化的原理以及序列化的自定義請參見我的另外一篇博客(java高級---->Serializable序列化的源碼分析)
目錄導航
Serializable序列化的簡要說明
一、 持久化的簡單介紹:
“持久化”意味着對象的“生存時間”並不取決於程序是否正在執行——它存在或“生存”於程序的每一次調用之間。通過序列化一個對象,將其寫入磁盤,以后在程序再次調用時重新恢復那個對象,就能圓滿實現一種“持久”效果。
二、 語言里增加了對象序列化的概念后,可提供對兩種主要特性的支持:
- 遠程方法調用(RMI)使本來存在於其他機器的對象可以表現出好象就在本地機器上的行為。將消息發給遠程對象時,需要通過對象序列化來傳輸參數和返回值。
- 使用一個Java Bean 時,它的狀態信息通常在設計期間配置好。程序啟動以后,這種狀態信息必須保存下來,以便程序啟動以后恢復;具體工作由對象序列化完成。
三、 Serializable的一些說明:
- 對象的序列化處理非常簡單,只需對象實現了Serializable 接口即可(該接口僅是一個標記,沒有方法)
- 序列化的對象包括基本數據類型,所有集合類以及其他許多東西,還有Class 對象
- 對象序列化不僅保存了對象的“全景圖”,而且能追蹤對象內包含的所有句柄並保存那些對象;接着又能對每個對象內包含的句柄進行追蹤
- 使用transient關鍵字修飾的的變量,在序列化對象的過程中,該屬性不會被序列化。
四、 序列化的步驟:
- 首先要創建某些OutputStream對象:OutputStream outputStream = new FileOutputStream("output.txt")
- 將其封裝到ObjectOutputStream對象內:ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
- 此后只需調用writeObject()即可完成對象的序列化,並將其發送給OutputStream:objectOutputStream.writeObject(Object);
- 最后不要忘記關閉資源:objectOutputStream.close(), outputStream .close();
五、 反序列化的步驟:
- 首先要創建某些OutputStream對象:InputStream inputStream= new FileInputStream("output.txt")
- 將其封裝到ObjectInputStream對象內:ObjectInputStream objectInputStream= new ObjectInputStream(inputStream);
- 此后只需調用readObject()即可完成對象的反序列化:objectInputStream.readObject();
- 最后不要忘記關閉資源:objectInputStream.close(),inputStream.close();
Serializable序列化的代碼實例
項目結構如下,源代碼下載見huhx友情鏈接:
一、 首先我們建立一個Man類,實現了Serializable接口,用於Person類的測試:
package com.huhx.model; import java.io.Serializable; public class Man implements Serializable { private static final long serialVersionUID = 1L; private String username; private String password; public Man(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
二、 我們再建立一個Person類,用於序列化:
package com.huhx.model; import java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = 1L; private Man man; private String username; private transient int age; public Person() { System.out.println("person constru"); } public Person(Man man, String username, int age) { this.man = man; this.username = username; this.age = age; } public Man getMan() { return man; } public void setMan(Man man) { this.man = man; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
三、 編寫一個包含main方法的測試類:MainTest,它的writeSerializableObject用於序列化對象:
// Serializable:把對象序列化 public static void writeSerializableObject() { try { Man man = new Man("huhx", "123456"); Person person = new Person(man, "劉力", 21); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("output.txt")); objectOutputStream.writeObject("string"); objectOutputStream.writeObject(person); objectOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
四、 測試類MainTest,它的readSerializableObject用於反序列化對象:
// Serializable:反序列化對象 public static void readSerializableObject() { try { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("output.txt")); String string = (String) objectInputStream.readObject(); Person person = (Person) objectInputStream.readObject(); objectInputStream.close(); System.out.println(string + ", age: " + person.getAge() + ", man username: " + person.getMan().getUsername()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
五、 在Main方法添加以上兩個方法的運行,結果如下:
- 在Person類中包含Man的引用,當Person被序列化的時候,從結果可以知道Man也被序列化了
- writeObject方法可以傳入String,是因為String首先是一個類,其次它也是實現了Serializable接口的
- Person類中的age字段是transient,從打印結果可以看到,序列化Person person = new Person(man, "劉力", 21)對象時,age沒有進行序列化。如果transient修飾的Object類型的,那么打印的結果將會是null
Externalizable序列化的代碼實例
首先我們看一下Externalizable的定義:繼承了Serializable接口
public interface Externalizable extends java.io.Serializable
一、 同樣的我們先創建一個實現了Externalizable的User類:重寫里面兩個方法readExternal和writeExternal
package com.huhx.model; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class User implements Externalizable { private String user; public String getUser() { return user; } public int getAge() { return age; } private int age; public User() { System.out.println("user constructor."); } public User(String user, int age) { System.out.println("user constructor two."); this.user = user; this.age = age; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("read external."); user = (String) in.readObject(); age = in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { System.out.println("write external."); out.writeObject(user); out.writeInt(age); } }
二、 在MainTest中加入方法writeExternalizableObject,用於序列化對象User
// Externalizable的序列化對象 public static void writeExternalizableObject() { User user = new User("huhx", 22); try { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("Externalizable.txt")); objectOutputStream.writeObject(user); objectOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
三、 在MainTest中加入方法writeExternalizableObject,用於反序列化對象User
// Externalizable的反序列化對象 public static void readExternalizableObject() { try { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("Externalizable.txt")); User user = (User) objectInputStream.readObject(); objectInputStream.close(); System.out.println("name: " + user.getUser() + ", age: " + user.getAge()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
四、 在Main方法添加以上兩個方法的運行,結果如下:
- 首先User user = new User("huhx", 22);執行了User的含參構造函數
- 當執行到writeObject(user);方法時,由於User實現了Externalizable接口,所以它的writeExternal會執行,
- 在User中的readExternal方法中調用了ObjectInput的readObject方法,在這個方法中通過反射機制創建User的實例,調用了User的無參構造函數。
- 然后在readObject方法執行的時候,同樣會先執行User類的readExternal方法。這個會在后續源代碼分析時講到
友情鏈接
- 本文測試代碼: 訪問密碼 12bb
- 序列化的原理分析 java高級---->Serializable序列化的源碼分析