transient解析

1,用途

  我們知道,當一個對象實現了Serilizable接口,這個對象就可以被序列化,我們不關心其內在的原理,只需要瞭解這個類實現了Serilizable接口,這個類的所有屬性和方法都會自動序列化。而在開發過程中,我們可能要求:當對象被序列化時(寫入字節序列到目標文件)時,有些屬性需要序列化,而其他屬性不需要被序列化,打個比方,如果一個用戶有一些敏感信息(如密碼,銀行卡號等),爲了安全起見,不希望在網絡操作(主要涉及到序列化操作,本地序列化緩存也適用)中被傳輸,這些信息對應的變量就可以加上transient關鍵字。換句話說,這個字段的生命週期僅存於調用者的內存中而不會寫到磁盤裏持久化。 
 所以,transient的用途在於:阻止實例中那些用此關鍵字聲明的變量持久化;當對象被反序列化時(從源文件讀取字節序列進行重構),這樣的實例變量值不會被持久化和恢復。例如,當反序列化對象——數據流(例如,文件)可能不存在時,原因是你的對象中存在類型爲java.io.InputStream的變量,序列化時這些變量引用的輸入流無法被打開。

2,使用方法

序列化的時候,將不需要序列化的屬性前添加關鍵字transient即可。 
示例:

package newDay.day13;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {  
    private static final long serialVersionUID = 996890129747019948L;  
    private String name;  
    private transient String psw;  

    public UserInfo(String name, String psw) {  
        this.name = name;  
        this.psw = psw;  
    }  

    public String toString() {  
        return "name=" + name + ", psw=" + psw;  
    }  
}  
public class TestTransient {
    public static void main(String[] args) {  
        UserInfo userInfo = new UserInfo("張三", "123456");  
        System.out.println(userInfo);  
        try {  
            // 序列化,被設置爲transient的屬性沒有被序列化  
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));  
            o.writeObject(userInfo);  
            o.close();  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
        try {  
            // 重新讀取內容  
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));  
            UserInfo readUserInfo = (UserInfo) in.readObject();  
            //讀取後psw的內容爲null  
            System.out.println(readUserInfo.toString());  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
}

運行結果:

name=張三, psw=123456
name=張三, psw=null

  密碼字段爲null,說明被標記爲transient的屬性在對象被序列化的時候不會被保存。

使用小結:

  1,一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化後無法獲得訪問。 
  2,transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量如果是用戶自定義類變量,則該類需要實現Serializable接口。 
  3,被transient關鍵字修飾的變量不再能被序列化,一個靜態變量不管是否被transient修飾,均不能被序列化。 
  對於第三點,加上static之後,依然能把姓名輸出。這是因爲:反序列化後類中static型變量name的值爲當前JVM中對應static變量的值,這個值是JVM中的不是反序列化得出的。下例可說明,其值時JVM中得到的而不是反序列化得到的:

package newDay.day13;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {  
    private static final long serialVersionUID = 996890129747019948L;  
    private static String name;  
    private transient String psw;  

    public UserInfo(String name, String psw) {  
        this.name = name;  
        this.psw = psw;  
    }  

    public static String getName() {
        return name;
    }

    public static void setName(String name) {
        UserInfo.name = name;
    }

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {  
        return "name=" + name + ", psw=" + psw;  
    }  
}  
public class TestTransient {
    public static void main(String[] args) {  
        UserInfo userInfo = new UserInfo("張三", "123456"); 
        System.out.println(userInfo);  
        try {  
            // 序列化,被設置爲transient的屬性沒有被序列化  
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));  
            o.writeObject(userInfo);  
            o.close();  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
        try {  
            //在反序列化之前改變name的值
            userInfo.setName("hello");
            // 重新讀取內容  
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));  
            UserInfo readUserInfo = (UserInfo) in.readObject();  
            //讀取後psw的內容爲null  
            System.out.println(readUserInfo.toString());  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
}

運行結果:

name=張三, psw=123456
name=hello, psw=null
  • 1
  • 2

這說明反序列化後類中static型變量name的值爲當前JVM中對應static變量的值,爲修改後hello,而不是序列化時的值“張三”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章