Transient關鍵字解密

一 概述

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;
}

StringBuffer源碼中存在一個toStringCache數組使用transient關鍵字修飾,而且給出的註釋是

A cache of the last value returned by toString. Cleared whenever the StringBuffer is modified。

toString返回最後一個值的緩存,無論何時,當StringBuffer被修改時會被去除。

二 關鍵字transient

瞭解關鍵字transient之前,我們應該先了解一個重要的概念——Java中的序列化機制:在Java中對象的序列化指的是將對象轉化成字節序列進行表示。該字節序列包含該對象的數據,有關對象的類型的信息和存儲在對象中數據的類型。一個序列化後的對象可以被寫到數據庫或者文件中,也可以用於網絡傳輸,一般當我們使用緩存cache(注:當內存空間不夠有可能會本地存儲到硬盤)或者遠程過程調用RPC(網絡傳輸)的時候,經常需要讓我們的實體類實現Serializable接口,使得其序列化。

將序列化對象寫入文件後,我們可以從文件中將其讀出來,並將其進行反序列化,這樣原來序列化的對象的類型信息,對象的數據,以及對象中的數據類型可以用來在內存中新建對象。

對象的序列化與反序列化的過程都是Java虛擬機(JVM)獨立的,所以我們可以將一個平臺序列化的對象放到另一個完全不同的平臺上進行反序列化。

類 ObjectInputStream 和 ObjectOutputStream 是高層次的數據流,它們包含反序列化和序列化對象的方法。

ObjectOutputStream 類包含很多寫方法來寫各種數據類型,但是一個特別的方法例外:

public final void writeObject(Object x) throws IOException

上面的方法序列化一個對象,並將它發送到輸出流。

類 ObjectInputStream 類包含如下反序列化一個對象的方法:

public final Object readObject() throws IOException, ClassNotFoundException

該方法從流中取出下一個對象,並將對象反序列化。它的返回值爲Object,因此,你需要將它轉換成合適的數據類型。

關鍵字transient: 其實就是使得被其修飾的關鍵字不被序列化,可以將無需序列化的字段Filter掉從而能夠節省內存或存儲空間。

爲了更好的突出,transient關鍵字在序列化中起的作用,給出下列代碼示例:

package com.apple.family.testkeytransient;

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 = 2763654297152416310L;
    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);

        // 爲 area 重新賦值
        rectangle1.setArea();
        System.out.println("3.恢復成原始對象\n"+rectangle1);
        in.close();
    }
}

執行結果如下:

1.原始對象
width : 3
height : 4
area : 12
2.反序列化後的對象
width : 3
height : 4
area : null //由於transient關鍵字修飾了area字段,所以序列化時被Filter了,所以反序列化時爲null
3.恢復成原始對象
width : 3
height : 4
area : 12

Process finished with exit code 0

 

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