#1.序列化與反序列化的概念
將對象轉換爲字節序列的過程稱爲對象的序列化。
反過來,將字節序列恢復成對象的過程稱爲對象的反序列化。
#2.爲何要將對象序列化?
2.1當咱們須要將內存中的對象保存到一個文件中/數據庫中的時候
一般咱們須要將某些對象進行序列化,讓它離開內存空間,入駐物理硬盤,以便長期保存,須要的時候在調取它。例如:緩存,咱們須要將緩存存儲起來,須要的時候再將它取出來。
2.2須要在網絡上傳送對象的時候
當兩個進程在進行遠程通訊時,彼此時間須要發送數據,不管哪一種類型的數據,都會以二進制序列的形式在網絡上傳送。
#3.如何實現對象序列化?
很簡單,將須要序列化的類實現Serializable接口便可,Serializable接口中沒有任何方法。將它理解爲一個標記,即代表這個類能夠序列化。
#4.實現序列化原理
java.io.ObjectOutputStream表示對象輸出流,writeObject(Object obj)方法將指定對象obj寫入一個輸出流中,即對該對象進行序列化。
java.io.ObjectInputStream表示對象輸入流,readObject()方法從ObjectInputStream讀取字節序列,再將它們反序列化成爲一個對象,並將其返回。
只有實現了Serializable接口的類才能被序列化。對象序列化步驟:
1>建立一個對象輸出流,即ObjectOutputStream,它能夠包裝一個目標輸出流,例如文件輸出流。
2>調用writeObject(Object obj)方法,參數爲obj
對象反序列化過程:
1>建立一個對象輸入流,即ObjectInputStream,它能夠包裝一個源輸入流,例如文件輸入流。
2>調用readObject()方法讀取對象
#5.實例
5.1 定義一個User類並實現Serializablejava
public class User implements Serializable{ //序列化id private static final long serialVersionUID = 1L; private Integer id; private String name; }
5.2序列化與反序列化User對象spring
public class TestSerializable { public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException { //序列化對象 SerializeUser(); //反序列化 User user = DeSerializeUser(); System.out.println(user); } }
序列化對象代碼數據庫
/** * 序列化User對象 * 1>建立一個對象輸出流,即ObjectOutputStream,它能夠包裝一個目標輸出流,例如文件輸出流。 * 2>調用writeObject(Object obj)方法,參數爲obj * @throws IllegalAccessException * @throws InstantiationException */ private static void SerializeUser() throws InstantiationException, IllegalAccessException{ //運用反射建立User對象 User user = new User(); try { Class<?> clazz = Class.forName("com.test.spring.bean.User"); user = (User) clazz.newInstance(); user.setId(1001); user.setName("張三"); } catch (ClassNotFoundException e1) { System.out.println("沒有找到該類"); e1.printStackTrace(); } //建立對象輸出流 //將User對象序列化,並存儲到E盤的Test文件下User.txt文件中 ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream(new File("E:\\Test\\User.txt"))); oos.writeObject(user); System.out.println("對象序列化成功"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } }
反序列化代碼緩存
/** * 反序列化User對象 * 1>建立一個對象輸入流,即ObjectInputStream,它能夠包裝一個源輸入流,例如文件輸入流。 * 2>調用readObject()方法讀取對象 * @throws ClassNotFoundException */ private static User DeSerializeUser() throws ClassNotFoundException{ //new方式建立對象 User user = new User(); ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream(new File("E:\\Test\\User.txt"))); user = (User) ois.readObject(); System.out.println("對象反序列化成功"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { try { ois.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return user; }
#6.serialVersionUID
serialVersionUID是序列化版本號,全部實現Serializable接口的類都須要有一個表示序列化版本標識符。
那這個serialVersionUID有什麼用呢?
1.咱們去掉User類中的serialVersionUID
2.在序列化這個類
3.在User類中添加新的屬性
4.再反序列化User類
報錯信息以下網絡
java.io.InvalidClassException: com.test.spring.bean.User; local class incompatible: stream classdesc serialVersionUID = 5057804141597769629, local class serialVersionUID = -2824417979782532292
反序列化的過程當中出現問題,報錯是stream classdesc serialVersionUID與local class serialVersionUID不一致。
在User類中,若是咱們沒有指定serialVersionUID,則java編譯器會自動給該類添加一個serialVersionUID;因爲沒有顯式的指定serialVersionUID,全部咱們修改了User類以後,編譯器又會給咱們指定一個serialVersionUID,這就出現了兩個序列化版本號不一致的錯誤。
接着測試下有serialVersionUID的狀況
1.加上serialVersionUID
2.序列化對象
3.修改對象字段
4.直接反序列化對象
測試了(假設新增屬性爲age),證實能夠反序列化成功,結果以下測試
對象反序列化成功 User [id=1001, name=張三, age=null]