為什麼Java有瞬態字段?




field transient (11)

transient變量是不可序列化的變量。

想到這可能有用的一個例子是,變量只在特定對象實例的上下文中才有意義,並且在對對象進行序列化和反序列化後變為無效。 在這種情況下,將這些變量變為null會很有用,這樣您可以在需要時使用有用的數據重新初始化它們。

為什麼Java有瞬態字段?


在回答這個問題之前,我必須向您解釋SERIALIZATION ,因為如果您了解科學計算機中的序列化意味著什麼,那麼您可以輕鬆理解這個關鍵字。

序列化當一個對象通過網絡傳輸/保存在物理媒體(文件,...)中時,該對象必須是“序列化”的。 序列化轉換字節狀態對象系列。 這些字節在網絡上發送/保存,並且從這些字節重新創建對象。

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}

現在,如果你想不做這個對象的TRANSFERT / SAVED字段,你可以使用關鍵字 transient

private transient attr2;

Example


在理解transient關鍵字之前,必須理解序列化的概念。 如果讀者知道序列化,請跳過第一點。

什麼是序列化?

序列化是使對象的狀態持久化的過程。 這意味著對象的狀態轉換為字節流並存儲在文件中。 以同樣的方式,我們可以使用反序列化從字節中取回對象的狀態。 這是Java編程中的重要概念之一,因為序列化主要用於網絡編程。 需要通過網絡傳輸的對象必須轉換為字節。 為此,每個類或接口都必須實現Serializable接口。 這是一個沒有任何方法的標記界面。

現在什麼是transient關鍵字及其目的?

默認情況下,所有對象的變量都轉換為持久狀態。 在某些情況下,您可能想要避免保留一些變量,因為您不需要保存這些變量。 所以你可以聲明這些變量是transient 。 如果變量被聲明為transient ,那麼它將不會被持久化。 這是transient關鍵字的主要目的。

我想用下面的例子來解釋上述兩點:

package javabeat.samples;

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

class NameStore implements Serializable{
    private String firstName;
    private transient String middleName;
    private String lastName;

    public NameStore (String fName, String mName, String lName){
        this.firstName = fName;
        this.middleName = mName;
        this.lastName = lName;
    }

    public String toString(){
        StringBuffer sb = new StringBuffer(40);
        sb.append("First Name : ");
        sb.append(this.firstName);
        sb.append("Middle Name : ");
        sb.append(this.middleName);
        sb.append("Last Name : ");
        sb.append(this.lastName);
        return sb.toString();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        NameStore nameStore = new NameStore("Steve", "Middle","Jobs");
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore"));
        // writing to object
        o.writeObject(nameStore);
        o.close();

        // reading from object
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore"));
        NameStore nameStore1 = (NameStore)in.readObject();
        System.out.println(nameStore1);
    }
}

輸出結果如下:

First Name : Steve
Middle Name : null
Last Name : Jobs

中間名稱被聲明為transient ,所以它不會被存儲在永久存儲器中。

Source


因為並非所有變量都具有可序列化的性質


允許你定義你不想串行化的變量。

在一個對像中,你可能有一些你不想序列化/持久化的信息(可能是對一個父工廠對象的引用),或者對序列化沒有意義。 將這些標記為“暫時”意味著序列化機制將忽略這些字段。


我的小小貢獻:

什麼是Java中的瞬態變量?
在簡單的句子中,用transient關鍵字修改的任何變量都會在java中變成瞬態變量。

為什麼我們需要java中的瞬態變量?
Transient關鍵字為您提供了對序列化過程的一些控制,並使您能夠靈活地從序列化過程中排除一些對象屬性。 有些時候確實不需要對對象的某些屬性進行序列化,我們會看到哪些變量不應該被序列化,並且應該在下一節中使其成為瞬態的。

你應該標記瞬變的變量?
既然我們知道transient關鍵字的目的或者有瞬態變量,那麼考慮哪個變量應該被標記為transient是有意義的。 我的規則是任何可以從其他變量中計算出來的變量都不需要保存。 例如,如果您有一個名為“interest”的字段,其值可以來自其他字段,例如原理,速率,時間等,則不需要序列化它。
另一個例子是字數統計,如果你保存文章,那麼不需要保存字數,因為它可以在文章被反序列化時創建。 由於大多數情況下您有用於登錄Java的記錄器實例,但是您肯定不希望它序列化正確,因此transient關鍵字的另一個很好的示例是“記錄器”。


序列化是以持久格式(例如文件流或數據庫)保存對象狀態並稍後將其從流中還原(去序列化)的過程。 在Java中,如果類實現java.io.Serializable接口,則類的對像是可序列化的。 這是一個標記接口,它告訴JVM該類有資格進行序列化。

public class User implements Serializable {

    private static final long serialVersionUID = 1234L;

    private String username;
    private String email;
    private transient String password;
    private Date birthday;
    private int age;

    public User(String username, String email, String password, Date birthday,
            int age) {
        this.username = username;
        this.email = email;
        this.password = password;
        this.birthday = birthday;
        this.age = age;
    }

    public void printInfo() {
        System.out.println("username: " + username);
        System.out.println("email: " + email);
        System.out.println("password: " + password);
        System.out.println("birthday: " + birthday);
        System.out.println("age: " + age);
    }

    // getters and setters

}

這個模型類有三個重點:它必須實現Serializable接口。 否則,當試圖序列化類的一個對象時,我們會得到java.io.NotSerializableException。 一個名為serialVersionUID的常量被聲明並賦值為一個long值:

private static final long serialVersionUID = 1234L;

這是一個常規常量,應該在類實現Serializable接口時聲明。 串行版本UID強有力地確保了類的對象序列化和反序列化版本之間的兼容性,因為序列化和反序列化過程可能發生在不同的計算機和系統上。 儘管這個聲明是可選的,但總是建議為可序列化類聲明se​​rialVersionUID。

注意密碼字段被標記為瞬態的:

private transient String password;

因為我們不想在序列化對象時存儲密碼。 規則是,當一個變量被標記為瞬態時,它的對像在序列化過程中不會被序列化。

瞬態變量是不可序列化的變量。 您可以使用transient關鍵字向Java虛擬機指示指示的變量不是對象持久狀態的一部分。

Java支持的訪問修飾符是靜態的,最終的,抽象的,同步的,本地的,易失性的,瞬態的和strictfp。

下表列出了可以應用於變量,方法和類的訪問說明符和修飾符Java的列表。

SPECIFIER/MODIFIER  LOCAL VARIABLE  INSTANCEVARIABLE    METHOD   CLASS
public              NA              A                   A         A
protected           NA              A                   A         NA
default             A               A                   A         A
private             NA              A                   A         NA
final               A               A                   A         A
static              NA              A                   A         NA
synchronized        NA              NA                  A         NA
native              NA              NA                  A         NA
volatile            NA              A                   NA        NA
transient           NA              A                   NA        NA
strictfp            NA              NA                  A         A

Java中的transient關鍵字用於指示不應序列化字段。

Java語言規範,Java SE 7 Edition第8.3.1.3節。 transient領域

變量可能被標記為transient以表明它們不是對象持久狀態的一部分。

例如,您可能具有從其他字段派生的字段,並且只能以編程方式完成,而不是通過序列化來持久化狀態。

這是一個GalleryImage類,其中包含一個圖像和從該圖像派生的縮略圖:

class GalleryImage implements Serializable
{
    private Image image;
    private transient Image thumbnailImage;

    private void generateThumbnail()
    {
        // Generate thumbnail.
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        generateThumbnail();
    }    
}

在此示例中, thumbnailImage是通過調用generateThumbnail方法生成的縮略圖圖像。

thumbnailImage字段被標記為transient ,所以只有原始image被序列化,而不是同時保留原始圖像和縮略圖圖像。 這意味著需要更少的存儲空間來保存序列化對象。 (當然,根據系統的要求,這可能是也可能不是理想的 - 這僅僅是一個例子。)

在反序列化時,調用readObject方法來執行必要的操作,以將對象的狀態恢復到發生序列化的狀態。 在這裡,需要生成縮略圖,所以readObject方法被重寫,以便通過調用generateThumbnail方法來生成縮略圖。

有關其他信息, 發現Java序列化API文章的秘密 (最初在Sun開發人員網絡上提供)的一個部分有一節討論了使用情況,並介紹了使用transient關鍵字來防止某些字段序列化的場景。


根據谷歌短暫的意思==只持續很短的時間; 暫時的。

現在如果想在java中使用瞬態關鍵字做任何瞬態處理。

問:在哪裡使用瞬態?

答:通常在java中,我們可以通過在變量中獲取數據並將這些變量寫入文件來將數據保存到文件中,此過程稱為序列化。 現在,如果我們想避免將可變數據寫入文件,我們會將該變量設為瞬態。

transient int result = 10;

注意:瞬態變量不能是本地的。


當你不想共享一些序列化的敏感數據時,需要它。


除了原生java之外的序列化系統也可以使用這個修飾符。 例如,Hibernate將不會保留標有@Transienttransient修飾符的字段。 兵馬俑也尊重這個修飾符。

我相信修飾符的象徵意義是“這個字段只用於內存中的使用,不要以任何方式持續或移動到特定虛擬機之外,它的非可移植性”。 即你不能依賴它在另一個VM內存空間的值。 就像volatile一樣,你不能依賴某些內存和線程語義。





transient