為什麼Java有瞬態字段?




java volatile (9)

為什麼Java有瞬態字段?


transient用於指示類字段不需要序列化。 可能最好的例子是Thread字段。 通常沒有理由序列化一個Thread ,因為它的狀態非常“特定於流程”。


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

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


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

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


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


在理解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中,如果類實現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中使用瞬態關鍵字做任何瞬態處理。

問:在哪裡使用瞬態?

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

transient int result = 10;

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


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


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

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





transient