1. 程式人生 > >Java中的關鍵字transient

Java中的關鍵字transient

閱讀目錄

  • 先解釋下Java中的物件序列化
  • 關於transient關鍵字
  • 舉個例子

先解釋下Java中的物件序列化

在討論transient之前,有必要先搞清楚Java中序列化的含義;

Java中物件的序列化指的是將物件轉換成以位元組序列的形式來表示,這些位元組序列包含了物件的資料和資訊,一個序列化後的物件可以被寫到資料庫或檔案中,也可用於網路傳輸,一般當我們使用快取cache(記憶體空間不夠有可能會本地儲存到硬碟)或遠端呼叫rpc(網路傳輸)的時候,經常需要讓我們的實體類實現Serializable介面,目的就是為了讓其可序列化。

當然,序列化後的最終目的是為了反序列化,恢復成原先的Java物件,要不然序列化後幹嘛呢,所以序列化後的位元組序列都是可以恢復成Java物件的,這個過程就是反序列化。

關於transient關鍵字

Java中transient關鍵字的作用,簡單地說,就是讓某些被修飾的成員屬性變數不被序列化,這一看好像很好理解,就是不被序列化,那麼什麼情況下,一個物件的某些欄位不需要被序列化呢?如果有如下情況,可以考慮使用關鍵字transient修飾:

1、類中的欄位值可以根據其它欄位推匯出來,如一個長方形類有三個屬性:長度、寬度、面積(示例而已,一般不會這樣設計),那麼在序列化的時候,面積這個屬性就沒必要被序列化了;

2、其它,看具體業務需求吧,哪些欄位不想被序列化;

PS,記得之前看HashMap原始碼的時候,發現有個欄位是用transient修飾的,我覺得還是有道理的,確實沒必要對這個modCount欄位進行序列化,因為沒有意義,modCount主要用於判斷HashMap是否被修改(像put、remove操作的時候,modCount都會自增),對於這種變數,一開始可以為任何值,0當然也是可以(new出來、反序列化出來、或者克隆clone出來的時候都是為0的),沒必要持久化其值。

/**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException). */ transient int modCount;

最後,為什麼要不被序列化呢,主要是為了節省儲存空間,其它的感覺沒啥好處,可能還有壞處(有些欄位可能需要重新計算,初始化什麼的),總的來說,利大於弊。

舉個例子

僅僅是示例,具體使用請根據實際情況:

package tmp;

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

class Rectangle implements Serializable{

    /**
     *
     */
    private static final long serialVersionUID = 1710022455003682613L;
    private Integer width;
    private Integer height;
    private transient Integer area;



    public Rectangle (Integer width, Integer height){
        this.width = width;
        this.height = height;
        this.area = width * height;
    }

    public void setArea(){
        this.area = this.width * this.height;
    }

    @Override
    public String toString(){
        StringBuffer sb = new StringBuffer(40);
        sb.append("width : ");
        sb.append(this.width);
        sb.append("\nheight : ");
        sb.append(this.height);
        sb.append("\narea : ");
        sb.append(this.area);
        return sb.toString();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        Rectangle rectangle = new Rectangle(3,4);
        System.out.println("1.原始物件\n"+rectangle);
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("rectangle"));
        // 往流寫入物件
        o.writeObject(rectangle);
        o.close();

        // 從流讀取物件
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("rectangle"));
        Rectangle rectangle1 = (Rectangle)in.readObject();
        System.out.println("2.反序列化後的物件\n"+rectangle1);
        rectangle1.setArea();
        System.out.println("3.恢復成原始物件\n"+rectangle1);
        in.close();
    }
}

結果列印(達到目的,節省儲存空間,成功恢復成原始物件):

1.原始物件

width : 3

height : 4

area : 12

2.反序列化後的物件

width : 3

height : 4

area : null

3.恢復成原始物件

width : 3

height : 4

area : 12