1. transient 的作用及使用方法
- 當一個物件繼承(implements)了 Serializable 介面,這個物件就可以被序列化,Java 的序列化模式為開發者提供了許多便利,開發者可以不必關心具體序列化的過程,只要繼承了 Serializable 介面,該類別(class)的所有屬性(property)和方法(method)都會自動序列化。
- 然而在實際開發過程中,有些屬性需要序列化,有些屬性則不需要。
- 用戶的私密訊息如密碼、銀行帳號等,通常不希望在網路操作時被傳輸。
- 此時,便可在這些對應的變數前加上 transient。
- 如此一來,這些私密訊息的生命週期只會存在於調用者的記憶體(memory)中,不會寫到磁碟(disk)裡。
注意讀取時,讀取數據的順序一定要和存放數據的順序保持一致。
- 範例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TransientExample {
public static void main(String[] args){
User user = new User();
user.setUsername("Rain");
user.setPassword("12345678");
System.out.println("Read before Serializable: ");
System.out.println("Username: " + user.getUsername());
System.out.println("Password: " + user.getPassword());
try {
ObjectOutput os = new ObjectOutputStream(new FileOutputStream("/Users/rainhu/workspace/algo/temp/user.txt"));
os.writeObject(user);
os.flush();
os.close();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream("/Users/rainhu/workspace/algo/temp/user.txt"));
user = (User) is.readObject();
is.close();
System.out.println("Read after Serializable: ");
System.out.println("Username: " + user.getUsername());
System.out.println("Password: " + user.getPassword());
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e){
e.printStackTrace();
}
}
}
class User implements Serializable{
private static final long serialVersionID = 8294180014912103005L;
private String username;
private transient String password;
public String getUsername(){
return username;
}
public void setUsername(String username){
this.username = username;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password = password;
}
}
- 輸出的結果是:
Read before Serializable:
Username: Rain
Password: 12345678
Read after Serializable:
Username: Rain
Password: null
- 也就是說反序列化並沒有成功從文件獲取到訊息。
2. transient 的小結
- 一旦變數被 transient 修飾,變數將不再是物件持久化的一部分,該變敗內容將在序列化後無法再次訪問。
- transient 關鍵字只能飾飾變數(variable),不能修飾方法(method)和類別(class)。注意,區域變數是無法被 transient 修飾的。
- 被 transient 修飾的變數不能再被序列化,一個靜態變數不管是否被 transient 修飾,都不能被序列化。
- 其中,在上例中的 username 帶有 static 關鍵字,實際上是沒有被序列化的,也就是說我們在讀取之前改變 username 的值,讀取完並不會改變 username 的值,而是 JVM 中對應靜態變數的值。
3. 當遇上了 Externalizable
- 當被 transient 修飾的變數在存於一個繼承了 Externalizable 的介面,則代表沒有任何東西被自動序列化。
- 需要在
writeExternal
方法中手工指定所要序列化的變數,這與是否被 transient 修飾無關。