Javaに一時フィールドがあるのはなぜですか?


回答:


1673

transientJava のキーワードは、フィールドがシリアル化(ファイルのように保存されることを意味する)プロセスの一部であってはならないことを示すために使用されます。

Java言語仕様のJava SE 7版セクション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();
    }    
}

この例では、thumbnailImagegenerateThumbnailメソッドを呼び出すことによって生成されるサムネイル画像です。

thumbnailImage以下のようにフィールドがマークされているtransientので、唯一のオリジナルは、image原画像とサムネイル画像の両方を永続化ではなく、シリアル化されています。つまり、シリアル化されたオブジェクトを保存するために必要なストレージが少なくなります。(もちろん、これはシステムの要件に応じて望ましい場合と望ましくない場合があります。これは単なる例です。)

逆シリアル化時に、readObjectメソッドが呼び出されて、オブジェクトの状態をシリアル化が行われた状態に戻すために必要な操作が実行されます。ここでは、サムネイルを生成する必要があるため、readObjectメソッドをオーバーライドして、generateThumbnailメソッドを呼び出すことでサムネイルが生成されるようにします。

追加情報については、JavaシリアライゼーションAPIの記事(Sun Developer Networkで最初に公開されました)の秘密の発見に、transient特定のフィールドのシリアライゼーションを防ぐためにキーワードを使用するシナリオを示すセクションがあります。


221
しかし、それが注釈ではなくキーワードなのはなぜ@DoNotSerializeですか?
Elazar Leibovich

333
これは、Javaに注釈がなかった時代に所有されていたと思います。
Peter Wippermann、2011

46
シリアライズ可能がJavaの内部にあるのは奇妙です。これは、ユーザーが読み取りおよび書き込みメソッドをオーバーライドする必要があるインターフェースまたは抽象クラスとして実装できます。
カレブ

7
@MJafar:readObjectは通常、逆シリアル化メカニズムにチェーンされているため、自動的に呼び出されます。さらに、多くの場合、それをオーバーライドする必要はありません-デフォルトの実装でうまくいきます。
Mike Adler

13
@calebはおそらく、符号なし整数がないために、バイナリ形式を自分で処理することがJavaで非常に困難なためです。
2014年

435

transientキーワードを理解する前に、シリアル化の概念を理解する必要があります。読者がシリアル化について知っている場合は、最初のポイントをスキップしてください。

シリアル化とは何ですか?

シリアライゼーションは、オブジェクトの状態を永続化するプロセスです。これは、オブジェクトの状態がバイトのストリームに変換され、永続化(ファイルへのバイトの格納など)または転送(ネットワークでのバイトの送信など)に使用されることを意味します。同様に、逆シリアル化を使用して、オブジェクトの状態をバイトから戻すことができます。シリアライゼーションは主にネットワークプログラミングで使用されるため、これはJavaプログラミングの重要な概念の1つです。ネットワーク経由で送信する必要があるオブジェクトは、バイトに変換する必要があります。そのためには、すべてのクラスまたはインターフェースがインターフェースを実装する必要がありSerializableます。これは、メソッドのないマーカーインターフェイスです。

さて、transientキーワードとその目的は何ですか?

デフォルトでは、オブジェクトのすべての変数が永続的な状態に変換されます。場合によっては、変数を永続化する必要がないため、一部の変数の永続化を避けたいことがあります。したがって、これらの変数をとして宣言できますtransient。変数がとして宣言されている場合、transient永続化されません。それがtransientキーワードの主な目的です。

上記2点について、以下の例で説明したいと思います。

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ため、永続ストレージには保存されません。

ソース


26
この例はこのコードから取得したものであり、ここで読むことができます。javabeat.net
Krishna

11
この部分は、奇妙で混乱する可能性があると私に思わせます。「つまり、オブジェクトの状態がバイトのストリームに変換され、ファイルに保存されます」。ほとんどの場合、シリアライゼーションはファイルへの書き込みを含まないようです(適切なケース:以下のネットワークの例)
Garcia Hurtado 2014年

5
ミドルネームは明らかに一時的なプロパティではないため、この例は悪い例です。
Raphael

1
@Raphael私にとって、この例は役に立ち、少なくとも概念を説明しています。あなたが気づいているなら、あなたにもっと良い例がありますか?
Chaklader Asfak Arefe

@依田NameFormatter中古車への参照があるかもしれませんtoString()。または、データとは対照的に、構成、表示、またはビジネスロジックに関連するもの。
ラファエル

84

シリアル化したくない変数を定義できるようにするため。

オブジェクト内に、シリアル化/永続化したくない情報(おそらく親ファクトリオブジェクトへの参照)がある場合や、シリアル化しても意味がない場合があります。これらを「一時的」としてマークすると、シリアル化メカニズムがこれらのフィールドを無視します。


36

私の小さな貢献:

一時的なフィールドとは何ですか?
基本的に、transientキーワードで変更されたフィールドは一時的なフィールドです。

Javaで一時フィールドが必要なのはなぜですか?キーワードは、あなたのシリアル化プロセスをある程度制御を与え、あなたは、このプロセスからいくつかのオブジェクトのプロパティを除外することができます。シリアライゼーションプロセスは、Javaオブジェクトを永続化するために使用されます。これにより、ほとんどの場合、それらの状態は、転送中または非アクティブでも保持できます。場合によっては、オブジェクトの特定の属性をシリアル化しないことが理にかなっています。どのフィールドを一時的としてマークする必要がありますか? 今、私たちはの目的を知っています
transient


transientキーワードと一時的なフィールドの場合、一時的なものとしてマークするフィールドを知ることが重要です。静的フィールドもシリアル化されないので、対応するキーワードも役立ちます。しかし、これはクラスの設計を台無しにするかもしれません。ここでtransientキーワードが役に立ちます。他のフィールドから値を導出できるフィールドがシリアル化されないようにするため、一時的なものとしてマークを付けます。interest他のフィールド(principalratetime)から値を計算できるという名前のフィールドがある場合、それをシリアル化する必要はありません。

別の良い例は、記事の単語数です。記事全体を保存する場合は、記事が「逆シリアル化」されたときに計算されるため、実際には単語数を保存する必要はありません。またはロガーについて考えてください。Logger インスタンスをシリアル化する必要はほとんどないため、一時的なものにすることができます。


63
あなたの「単純な文」は単にトートロジーです。それは何も説明しません。あなたはそれなしで良いほうがいいでしょう。
ローン侯爵

1
これは、フィールドがどこにあるべきかについての良い説明ですtransient
Chaklader Asfak Arefe

1
インタレストフィールドとワードカウントは、一時フィールドの良い例です。
Tarun

1
別の良い使用例:オブジェクトにソケットのようなコンポーネントがあり、シリアル化したい場合、ソケットはどうなりますか?持続する場合、シリアル化解除した後、ソケットは何を保持しているでしょうか?そのソケットオブジェクトを次のようにするのは理にかなっていますtransient
Mohammed Siddiq

28

transient変数がシリアライズされない場合があり変数です。

これが役立つと思われる1つの例は、特定のオブジェクトインスタンスのコンテキストでのみ意味があり、オブジェクトをシリアル化および逆シリアル化すると無効になる変数です。その場合、それらの変数をnull代わりにして、必要なときに有用なデータで再初期化できるようにすると便利です。


ええ、クラスの "passwordまたはcrediCardPin"フィールドメンバーのようなもの。
Mateen

17

transientクラスフィールドをシリアル化する必要がないことを示すために使用されます。おそらく最良の例はThreadフィールドです。のThread状態は非常に「フロー固有」であるため、通常、をシリアル化する理由はありません。


私が間違っている場合は修正してください。ただし、スレッドはシリアル化できないため、とにかくスキップされますか?
TFennis 2013

3
@TFennis:直列化可能クラスの場合はA参照直列化可能でないクラスB(のようなThreadあなたの例では)、その後Aのいずれかの参照をマークする必要がありますtransientXORをして、合理的な何かをするために、デフォルトのシリアル化プロセスをオーバーライドする必要がありますBXORの唯一の直列化可能サブクラスがいることを前提としB、実際に参照されています(したがって、実際のサブクラスは「悪い」親を処理する必要がありますB)XORは、直列化が失敗することを受け入れます。1つだけのケース(一時的としてマークされている)Bは、自動的かつサイレントにスキップされます。
AH

3
@TFennisいいえ、例外が発生します。
ローン侯爵

1
@AH:なぜXORなのか?私はそれらの任意の組み合わせを実行するコードが機能し、いくつかの組み合わせが役立つかもしれないと思います(たとえば、Bのシリアル化可能なサブクラスのみが参照されている場合でも、デフォルトのシリアル化プロセスのオーバーライドが役立つ場合があり、その逆も同様です)。
スーパーキャット2017年

15

ネイティブJava以外のシリアル化システムでもこの修飾子を使用できます。たとえば、Hibernateは@Transientまたは一時的な修飾子でマークされたフィールドを永続化しません。テラコッタもこの修飾子を尊重します。

修飾子の比喩的な意味は「このフィールドはメモリ内でのみ使用することです。永続化したり、この特定のVMの外部に移動したりしないでください。その移植性はありません」です。つまり、別のVMメモリ空間でその値に依存することはできません。volatileによく似ているということは、特定のメモリやスレッドのセマンティクスに依存できないことを意味します。


14
transient現時点で設計されていれば、それはキーワードにはならないと思います。彼らはおそらく注釈を使用するでしょう。
Joachim Sauer


7

私はこの質問に応じる前に、私はあなたに説明しなければならないSERIALIZATIONをあなたはそれはあなたが簡単にこのキーワードを理解することができ、科学コンピュータ内の直列化を意味するものを理解していればいるので、。

シリアル化 オブジェクトが物理メディアに保存/ネットワークを介して転送される(ファイル、...)は、オブジェクトは、「連載」でなければなりません。シリアライゼーションは、バイトステータスオブジェクトシリーズを変換します。これらのバイトはネットワーク上で送信/保存され、オブジェクトはこれらのバイトから再作成されます。

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

このオブジェクトSOの転送 / 保存フィールドを実行しない場合は、キーワードを使用できます transient

private transient attr2;


6

シリアル化に伴う機密データを共有したくない場合に必要です。


7
機密データ以外の使用例で、フィールドをシリアル化したくない場合があります。たとえば、Thread(@ AHへのクレジットなど)をシリアル化したくない場合は、一時的なものとしてマークします。ただし、スレッド自体は機密データではないため、シリアル化しても論理的には意味がありません(シリアル化できません)。
glen3b 2014年

1
@ glen3bそのケースはこの回答では除外されません。ポスターが言及した場合、物事が立つので、それは確かに必要です。
ローン侯爵

3

グーグルの一時的な意味によると==短時間だけ持続する; 永久的でない。

ここで、Javaで何かを一時的にする場合は、transientキーワードを使用します。

Q:一時的に使用する場所は?

A:一般に、Javaでは、変数にデータを取得してそれらの変数をファイルに書き込むことにより、データをファイルに保存できます。このプロセスは、シリアル化と呼ばれます。変数データが​​ファイルに書き込まれるのを避けたい場合は、その変数を一時的なものにします。

transient int result=10;

注:一時変数をローカルにすることはできません。


0

簡単に言えば、transient javaキーワードは、非一時的なフィールドが対応するときに直列化されたフィールドを保護します。

このコードスニペットでは、抽象クラスBaseJobがSerializableインターフェースを実装しています。BaseJobから拡張していますが、リモートおよびローカルのデータソースをシリアル化する必要はありません。organizationNameおよびisSyncedフィールドのみをシリアル化します。

public abstract class BaseJob implements Serializable{
   public void ShouldRetryRun(){}
}

public class SyncOrganizationJob extends BaseJob {

   public String organizationName;
   public Boolean isSynced

   @Inject transient RemoteDataSource remoteDataSource;
   @Inject transient LocalDaoSource localDataSource;

   public SyncOrganizationJob(String organizationName) {
     super(new 
         Params(BACKGROUND).groupBy(GROUP).requireNetwork().persist());

      this.organizationName = organizationName;
      this.isSynced=isSynced;

   }
}

0

一時的なキーワードの簡略化されたサンプルコード。

import java.io.*;

class NameStore implements Serializable {
    private String firstName, lastName;
    private transient String fullName;

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

    private void buildFullName() {
        // assume building fullName is compuational/memory intensive!
        this.fullName = this.firstName + " " + this.lastName;
    }

    public String toString(){
        return "First Name : " + this.firstName
            + "\nLast Name : " + this.lastName
            + "\nFull Name : " + this.fullName;
    }

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

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

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("ns"));
        NameStore ns = (NameStore)in.readObject();
        System.out.println(ns);
    }
}

0

一時的な修飾子で宣言されたフィールドは、シリアル化されたプロセスに参加しません。オブジェクトがシリアル化(任意の状態で保存)されると、その一時フィールドの値はシリアル表現で無視されますが、一時フィールド以外のフィールドはシリアル化プロセスに参加します。これが、transientキーワードの主な目的です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.