Java序列化和反序列化存在的意義
文章來源:
一 javabean為什麼要實現序列化?
所謂的Serializable,就是java提供的通用資料儲存和讀取的介面。至於從什麼地方讀出來和儲存到哪裡去都被隱藏在函式引數的背後了。這樣子,任何型別只要實現了Serializable介面,就可以被儲存到檔案中,或者作為資料流通過網路傳送到別的地方。也可以用管道來傳輸到系統的其他程式中。這樣子極大的簡化了類的設計。只要設計一個儲存一個讀取功能就能解決上面說得所有問題。
java的"物件序列化"能讓你將一個實現了Serializable介面的物件轉換成一組byte,這樣日後要用這個物件時候,你就能把這些byte資料恢復出來,並據此重新構建那個物件了。
工作流當中流程變數的幾種資料型別:string integer short long double boolean date binary serializable,這就是為什麼要將 javabean實現序列化的原因,因為你將物件設定到流程變數中必須要實現序列化,否則會在設定流程變數的時候報錯找不到該型別。
java物件序列化機制就是把記憶體中的Java物件(User之類的JavaBean)轉換成二進位制流。java物件序列化後可以很方便的儲存或者在網路中傳輸。Java的序列化機制是通過執行時判斷類的序列化ID(serialVersionUID)來判定版本的一致性。在反序列化時,java虛擬機器會通過二進位制流中的serialVersionUID與本地的對應的實體類進行比較,如果相同就認為是一致的,可以進行反序列化,正確獲得資訊,否則丟擲序列化版本不一致的異常。所以涉及到資料傳輸或者儲存的類,嚴格意義上來說都要加上序列化ID,這也是一種良好的程式設計習慣。
二 java 中為什麼實體類需要實現序列化
序列化是一種用來處理物件流的機制。所謂物件流就是將物件的內容進行流化。可以對流化後的物件進行讀寫操作,也可將流化後的物件傳輸於網路之間。序列化是為了解決在對物件流進行讀寫操作時所引發的問題。
序列化的實現:將需要被序列化的類實現Serializable介面,該介面沒有需要實現的方法,implements Serializable只是為了標註該物件是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(物件流)物件,接著,使用ObjectOutputStream物件的writeObject(Object obj)方法就可以將引數為obj的物件寫出(即儲存其狀態),要恢復的話則用輸入流;
什麼時候使用序列化:
- 物件序列化可以實現分散式物件。主要應用例如:RMI(即遠端呼叫Remote Method Invocation)要利用物件序列化執行遠端主機上的服務,就像在本地機上執行物件時一樣。
- java物件序列化不僅保留一個物件的資料,而且遞迴儲存物件引用的每個物件的資料。可以將整個物件層次寫入位元組流中,可以儲存在檔案中或在網路連線上傳遞。利用物件序列化可以進行物件的"深複製",即複製物件本身及引用的物件本身。序列化一個物件可能得到整個物件序列。
- 序列化可以將記憶體中的類寫入檔案或資料庫中。比如將某個類序列化後存為檔案,下次讀取時只需將檔案中的資料反序列化就可以將原先的類還原到記憶體中。也可以將類序列化為流資料進行傳輸。總的來說就是將一個已經例項化的類轉成檔案儲存,下次需要例項化的時候只要反序列化即可將類例項化到記憶體中並保留序列化時類中的所有變數和狀態。
- 物件、檔案、資料,有許多不同的格式,很難統一傳輸和儲存序列化以後就都是位元組流了,無論原來是什麼東西,都能變成一樣的東西,就可以進行通用的格式傳輸或儲存,傳輸結束以後,要再次使用,就進行反序列化還原,這樣物件還是物件,檔案還是檔案.因為JAVA中要將物件序列化為 流 的 形式進行傳輸
三 java為什麼要實現serializable序列化
我們有時候想把一個物件寫到一個檔案上,實現持久化,可以這麼做
class User{
String userName ;
String password;
public User(String userName , String passwrod) {
this.userName = userName;
this.password = passwrod;
}
@Override
public String toString() {
return "使用者名稱:"+this.userName+ " 密碼:"+ this.password;
}
}
public class Test {
public static void main(String[] args) throws IOException, Exception {
writeObj();
}
//定義方法把物件的資訊寫到硬碟上------>物件的序列化。
public static void writeObj() throws IOException{
//把user物件的資訊持久化儲存。
User user = new User("admin","123");
//找到目標檔案
File file = new File("/Users/chen/Downloads/obj.txt");
//建立資料輸出流物件
FileOutputStream fileOutputStream = new FileOutputStream(file);
//建立物件的輸出流物件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//把物件寫出
objectOutputStream.writeObject(user);
//關閉資源
objectOutputStream.close();
}
}
執行時發現報錯java
Exception in thread “main” java.io.NotSerializableException: User
要求必要需實現serializable介面,serializable介面沒有任何方法,是一個標識介面。在user類後面implements Serializable,然後開啟obj.txt檔案會發現是一堆位元組碼檔案,這是原先的物件編譯後的,我們如果要看這個物件需要反序列化.
class User implements Serializable{
String userName ;
String password;
public User(String userName , String passwrod) {
this.userName = userName;
this.password = passwrod;
}
@Override
public String toString() {
return "使用者名稱:"+this.userName+ " 密碼:"+ this.password;
}
}
public class Test {
public static void main(String[] args) throws IOException, Exception {
writeObj();
readObj();
}
//定義方法把物件的資訊寫到硬碟上------>物件的序列化。
public static void writeObj() throws IOException{
//把user物件的資訊持久化儲存。
User user = new User("admin","123");
//找到目標檔案
File file = new File("/Users/chen/Downloads/obj.txt");
//建立資料輸出流物件
FileOutputStream fileOutputStream = new FileOutputStream(file);
//建立物件的輸出流物件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//把物件寫出
objectOutputStream.writeObject(user);
//關閉資源
objectOutputStream.close();
}
//把檔案中的物件資訊讀取出來-------->物件的反序列化
public static void readObj() throws IOException, ClassNotFoundException{
//找到目標檔案
File file = new File("/Users/chen/Downloads/obj.txt");
//建立資料的輸入通道
FileInputStream fileInputStream = new FileInputStream(file);
//建立物件的輸入流物件
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
//讀取物件資訊
User user = (User) objectInputStream.readObject(); //建立物件肯定要依賴物件所屬 的class檔案。
System.out.println("物件的資訊:"+ user);
}
}
輸出:
物件的資訊:使用者名稱:admin 密碼:123