Serializable 接口:該接口沒有方法或字段,僅用於標識由該接口實現類創建的對象是可序列化的。
示例:
import java.io.Serializable;
public class UserInfo implements Serializable {
private static final long serialVersionUID = -564040236692883153L;
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name='" + name + '\'' + ", age=" + age;
}
}
import java.io.*;
public class Test {
/**
* 序列化
*
* @author GaoHuanjie
*/
public static void serialize(){
UserInfo userInfo = new UserInfo();
userInfo.setAge(23);
userInfo.setName("Tom");
System.out.println(userInfo);
ObjectOutput objectOutput = null;
try {
objectOutput = new ObjectOutputStream(new FileOutputStream("D:\\user_info.ser"));
objectOutput.writeObject(userInfo);
objectOutput.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (objectOutput!=null) {
try {
objectOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 反序列化
*
* @author GaoHuanjie
*/
public static void deserialize(){
ObjectInput objectInput = null;
try {
objectInput = new ObjectInputStream(new FileInputStream("D:\\user_info.ser"));
UserInfo userInfo = (UserInfo) objectInput.readObject();
System.out.println(userInfo);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (objectInput!=null) {
try {
objectInput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
serialize();//序列化
deserialize();//反序列化
}
}
serialVersionUID常量
實現Serializable接口的類須顯式聲明serialVersionUID常量,該常量作用如下:反序列化能否成功取決於三方面,首先序列化和反序列化類所在包相同,其次序列化和反序列化類的類名相同,最後序列化和反序列化類serialVersionUID的值要相同,兩個類中的代碼可以不同,如果不指定serialVersionUID,則類出現警告,但這是次要的,更重要的是序列化時將根據Java(TM)對象序列化規範爲該類計算一個默認的serialVersionUID值,這就要求反序列化時使用的類與序列化時使用的類必須完全相同(有相同的屬性和方法),否則反序列化失敗,因爲反序列化時serialVersionUID的值也是根據Java(TM)對象序列化規範計算出來的默認值,由於序列化類代碼和反序列化類代碼不同,則serialVersionUID的值肯定不同;但在實際開發中序列化類代碼和反序列化類代碼極有可能不同,在這種情況下爲了反序列化成功就要求顯式聲明serialVersionUID常量且值要相同。serialVersionUID的生成策略有兩種:一個是固定的 1L,一個是根據Java(TM)對象序列化規範生成的 long 類型數據;如果沒有特殊需求,推薦使用固定值,這樣便於序列化類代碼和反序列化類serialVersionUID一致;如果限制某些用戶的使用,則推薦第二種生成策略。
transient 關鍵字
在序列化時,transient 關鍵字修飾的成員變量不會被序列化;在反序列化時,transient 關鍵字修飾的成員變量被賦以默認值,如整型爲0,浮點型爲0.0,引用類型爲null。
static關鍵字
在序列化時,static關鍵字修飾的成員變量不會被序列化。序列化保存的是對象的狀態,靜態變量屬於類的狀態,因此序列化並不保存靜態變量,即序列化信息中不包含這個靜態成員域。
import java.io.Serializable;
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
private static int count;
public UserInfo() {
count++;
}
public String toString() {
return "count:" + count;
}
}
static修飾的成員變量,序列化和反序列化代碼在一個進程中執行時會序列化成功,因爲序列化時jvm已經把靜態變量加載進來了,所以反序列化時獲取的是加載好的靜態變量,如下例子:
import java.io.*;
public class Test {
public static void main(String[] args) {
try {
ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("user_info.ser"));
objectOutput.writeObject(new UserInfo());
objectOutput.close();
ObjectInput objectInput = new ObjectInputStream(new FileInputStream("user_info.ser"));
UserInfo userInfo = (UserInfo) objectInput.readObject();
System.out.println(userInfo);
objectInput.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
static修飾的成員變量,序列化和反序列化代碼不再一個進程,由於反序列化時是重新加載靜態變量,所以靜態變量是初始值,如下列子:
序列化:
import java.io.*;
public class Test1 {
public static void main(String[] args) {
try {
ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("user_info.ser"));
objectOutput.writeObject(new UserInfo());
objectOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
反序列化:
import java.io.*;
public class Test2 {
public static void main(String[] args) {
try {
ObjectInput objectInput = new ObjectInputStream(new FileInputStream("user_info.ser"));
UserInfo userInfo = (UserInfo) objectInput.readObject();
System.out.println(userInfo);
objectInput.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}