題目取得有點(diǎn)怪異,不管這個(gè),其實(shí)是要說一下 java 中的 java.io.Serializable 接口。
首先,先來了解一下什么是 序列化 ( Serializable ) :
對(duì)象的壽命通常隨著生成該對(duì)象的程序塊的終止而終止。有時(shí)候,你可能需要將對(duì)象的狀態(tài)保存下來,在需要時(shí)再將對(duì)象恢復(fù)(反序列化)。
我們把對(duì)象的這種能記錄自己的狀態(tài)以便將來再生的能力,叫做對(duì)象的持久性 ( persistence )。
對(duì)象通過寫出描述自己狀態(tài)的數(shù)值來記錄自己,這個(gè)過程就叫對(duì)象的序列化 ( Serialization ) 。
類可以通過實(shí)現(xiàn) java.io.Serializable 接口來啟用其序列化功能。未實(shí)現(xiàn)此接口的類將無法使其任何狀態(tài)序列化或反序列化。
類實(shí)現(xiàn) java.io.Serializable 接口,無需實(shí)現(xiàn)任何方法或字段,因?yàn)?java.io.Serializable 接口本身就沒有方法或字段,它僅用來標(biāo)識(shí)可序列化的語義。
Java 序列化技術(shù)可以讓你將一個(gè)對(duì)象的狀態(tài)寫入到一個(gè) IO 流里,并且可以從其它地方把該 IO 流里的數(shù)據(jù)讀出來。重新構(gòu)造一個(gè)相同的對(duì)象。
這就有點(diǎn)像你將數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫里,然后再拿出來,這前后得到的東西是一樣的。它的這種機(jī)制允許你將對(duì)象通過網(wǎng)絡(luò)進(jìn)行傳播,
并可以隨時(shí)把對(duì)象持久化到數(shù)據(jù)庫、文件等系統(tǒng)里。
另外,序列化運(yùn)行時(shí)使用一個(gè)稱為 serialVersionUID 的版本號(hào)與每個(gè)可序列化類相關(guān)聯(lián),
該序列號(hào)在反序列化過程中用于驗(yàn)證序列化對(duì)象的發(fā)送者和接收者是否為該對(duì)象加載了與序列化兼容的類。
如果接收者加載的該對(duì)象的類的 serialVersionUID 與對(duì)應(yīng)的發(fā)送者的類的版本號(hào)不同,則反序列化將會(huì)導(dǎo)致失敗并拋出 InvalidClassException。
如還想要更進(jìn)一步的詳細(xì)信息,可以自行查看 JDK 的 API,里面對(duì) Serializable 做了比較詳細(xì)的解釋。
接下來做個(gè)小示例 :
package net.yeah.fancydeepin.model;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public User(){
}
public User (Integer id, String name){
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
Junit 測試 :
package junit.test;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import net.yeah.fancydeepin.model.User;
public class TestApp {
@Test
public void serializable() throws Exception{
User user = new User(9080, "fancy");
ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream("user.ser"));
outStream.writeObject(user);
System.out.println("<---- Finished ---->");
}
@Test
public void inverseSerializable() throws Exception{
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("user.ser"));
User user = (User)inputStream.readObject();
System.out.println("ID : " + user.getId());
System.out.println("name : " + user.getName());
}
}
選中 serializable 方法,右鍵,Run As Junit Test,后臺(tái)輸出 :
<---- Finished ---->
選中工程名,按 F5 刷新一下,在項(xiàng)目名的根目錄下就生成了一個(gè) user.ser 文件,這就是 User 對(duì)象序列化生成的文件,它記錄了 User 對(duì)象的一些狀態(tài)信息,
當(dāng)然,你可以根據(jù)需要選擇文件的存放路徑。
選中 inverseSerializable 方法,右鍵,Run As Junit Test,后臺(tái)輸出 :
ID : 9080
name : fancy
1 . 若將 User 類中的序列化接口實(shí)現(xiàn)去掉 :
package net.yeah.fancydeepin.model;
public class User{
private Integer id;
private String name;
public User(){
}
public User (Integer id, String name){
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
其余不變,再次運(yùn)行 Junit Test 的 serializable 方法,后臺(tái)拋出異常 :
java.io.NotSerializableException: net.yeah.fancydeepin.model.User
2 . 先將 User 類撤銷回來 :
package net.yeah.fancydeepin.model;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public User(){
}
public User (Integer id, String name){
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
其余不變,再次運(yùn)行 Junit Test 的 serializable 方法,先讓它正確序列化 User 對(duì)象生成 user.ser,接著,修改 serialVersionUID 的值 :
private static final long serialVersionUID = 10086L;
接著,運(yùn)行 Junit Test 的 inverseSerializable 方法,后臺(tái)拋出異常 :
java.io.InvalidClassException: net.yeah.fancydeepin.model.User; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 10086
這兩個(gè)異常是為了幫助朋友們理解 Serializable,異常信息都比較容易理解和接受,這里就不多解釋了,本文也到此結(jié)束。