對象流:
有的時候,我們可能需要将記憶體中的對象持久化到硬碟下,或者将硬碟中的對象資訊讀到記憶體中,這個時候我們可能會用到流,java IO中提供了友善我們使用的流(對象流)友善我們進行對象的序列化和反序列化操作
序列化:
講對象轉換成一個位元組序列的過程,相當于寫入操作
反序列化:
将一個位元組序列轉換為對象的過程,相當于讀操作
java IO 也提供了一個接口來标志是否可以序列化----Serializable接口
該接口源碼裡邊什麼内容都沒有,這個接口隻是一個标記接口,用來告訴我們的JVM虛拟機,實作了這個接口的對象,可以序列化,類似我們的Cloneable接口,也是标記接口
public interface Serializable {
}
public interface Cloneable {
}
如果需要序列化操作的對象沒有實作該接口,操作的時候,會出現序列化失敗的錯誤
serialVersionUID (序列化的版本ID)相關問題
- 1.serialVersionUID如何生成?
- 1.一個是預設的1L,比如:private static final long serialVersionUID = 1L;
- 2.一個是根據類名、接口名、成員方法及屬性等來生成一個64位的哈希字段,比如: private static final long serialVersionUID = xxxxL;
- 2.Java的序列化機制流程?
- 在進行對象序列化時,系統會預設給每個對象生成一個serialVersionUID,系統預設生成的serialVersionUID是根據對象的類,超類,屬性和方法等資訊計算得到的,如果,對象資訊發生變化,例如增加或者減少一個屬性,增加或減少一個方法等,該serialVersionUID也會發生相應的變化,
- 每個序列化的對象都是采用一個序列化好來進行儲存的,當序列化一個對象時,程式會檢查該對象是否已經序列化過,如果沒有則使用位元組流中的資料建構序列化對象,并為該對象關聯一個serialVersionUID,可以是系統生成也可以指定,如果對象已經序列化過,則程式直接輸出該對象關聯的序列号在和本地serialVersionUID進行比較,一緻則反序列化輸出對象
- java序列化機制是通過JVM在運作時判斷傳進來的位元組流的serialVersionUID和本地相應實體類的serialVersionUID進行比較來驗證版本的一緻性。如果一緻,則可以執行反序列化,不一緻則會出現序列化版本不一緻的異常
IO(五)對象流和序列化反序列化
-
3.serialVersionUID作用?
維持版本一緻性
transient關鍵字
在序列化的過程中,我們有時候并不想該對象所有的屬性都參與序列化,這時候就需要用到transient關鍵字,如果用transient聲明一個執行個體變量,當對象存儲時,它的值不需要維持。換句話來說就是,用transient關鍵字标記的成員變量不參與序列化過程。
當反序列化的時候,該屬性就會輸出他的預設值
public class Dog implements Serializable{
/**
* 序列化版本ID
*/
private static final long serialVersionUID = 1L;
private String name;
private transient int id;
private String age;
private String address;
//省略get/set
public Dog(String name, int id,String age, String address) {
super();
this.name = name;
this.id = id;
this.age = age;
this.address = address;
}
IO 中的為我們提供了對象流用來操作對象的持久化
/**
* 寫入對象(序列化)
*/
public static void writeObject() {
File file = new File("object.txt");
if(!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
OutputStream outputStream = new FileOutputStream(file);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
Dog dog1 = new Dog("K", 12, "13","obejct");
Dog dog2 = new Dog("o", 15, "21");
Dog[] dogs = {dog1,dog2};
objectOutputStream.writeObject(dog1);
System.out.println("寫入完畢");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 讀對象(反序列化)
*/
public static void readObject() {
File file = new File("object.txt");
if(!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
InputStream inputStream = new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
//Dog[] dogs = (Dog[])objectInputStream.readObject();
System.out.println("讀取完畢");
//for(Dog dog : dogs) {
// System.out.println("結果:"+dog);
//}
Dog dog = (Dog)objectInputStream.readObject();
System.out.println("結果:"+dog);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
id屬性沒有參與到序列化的過程,反序列化得到的就是他的預設值,引用類型為null
使用對象流也是非常簡單,因為JAVA IO中使用裝飾設計模式為我們解決了很多困難,我們隻需要重新包裝位元組流就可以擴充對象流操作功能。