web-dev-qa-db-ja.com

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

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

1330
Animesh

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();
    }    
}

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

thumbnailImageフィールドはtransientとしてマークされているので、元のimageだけが元の画像とサムネイル画像の両方を永続化するのではなくシリアライズされます。これは、直列化されたオブジェクトを保存するために必要なストレージが少なくなることを意味します。 (もちろん、これはシステムの要件によっては望ましくない場合もありますが、これは単なる例です)。

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

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

1515
coobird

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として宣言されているため、永続記憶域には格納されません。

出典

386
Rahul Saxena

直列化したくない変数を定義できるようにするため。 

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

80
Brian Agnew

私の小さな貢献:

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

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

どのフィールドに一時的なマークを付けますか?
これでtransientキーワードとtransientフィールドの目的がわかりました。どのフィールドをtransientとマークするかを知ることが重要です。静的フィールドも直列化されていないため、対応するキーワードでもうまくいきます。しかし、これはあなたのクラスデザインを台無しにするかもしれません。これがtransientキーワードが助けになるところです。値を他のフィールドから派生させることができるフィールドを直列化できないようにするため、それらを一時的なものとしてマークします。 interestという名前のフィールドがあり、その値は他のフィールド(principalrate、およびtime)から計算できる場合は、それをシリアル化する必要はありません。

もう1つの良い例は、Wordの記事を数えることです。あなたが記事全体を保存しているのであれば、Wordのカウントを保存する必要は全くありません。またはロガーについて考えます。 Loggerインスタンスはシリアライズする必要がほとんどないため、一時的にすることができます。

31
Shreyos Adikari

transient変数は、直列化できない変数です。 

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

21
Adrian Grigore

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

13
Andrei Ciobanu

ネイティブJava以外のシリアライゼーションシステムもこの修飾子を使用できます。たとえば、Hibernateは @Transient または transient 修飾子のいずれかでマークされたフィールドを永続化しません。 Terracottaもこの修飾子を尊重します。

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

12
DragonFax

すべての変数が直列化可能というわけではないため

8
Silfverstrom

この質問に答える前に、シリアライゼーションについて説明する必要があります。科学コンピュータでのシリアライゼーションの意味を理解していれば、このキーワードを簡単に理解できるからです。

Serialization オブジェクトがネットワークを介して転送されたり、物理メディア(ファイルなど)に保存されている場合は、そのオブジェクトを "シリアル化"する必要があります。シリアル化はバイトステータスオブジェクトシリーズを変換します。これらのバイトはネットワーク上に送信されるか保存され、オブジェクトはこれらのバイトから再作成されます。

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

このオブジェクトのTRANSFERRT/SAVEDフィールドをSOしない場合は、keywordtransientを使用できます。 

private transient attr2;

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

3
setzamora

簡単に言うと、transient Javaキーワードは、非一時的フィールドの対応物として、フィールドを以前のSerializeから保護します。

このコードスニペットでは、抽象クラス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;

   }
}
1
nyulan

Google の一時的な意味として==短期間だけ持続します。永遠です。

Javaで一時的なものを作成したい場合は、transientキーワードを使用してください。

Q:どこでトランジェントを使うのですか?  

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

transient int result=10;

注意: 一時変数はローカルにはできません。

1
Mateen

物事を明確にするためにもう1つ例を挙げてください。受け入れられた答えを読んでください。

    class Employee{
    String name;
    Date dob;
    transient int age;
    public int calculateAge(Date dob){
        int age = 0;
        //calculate age based on Date of birth
        return age;
    }
}

上記の例では、「年齢」を一時的なものにしました。年齢をファイルに書き込むとき、その値を保存する必要はありません。私はDOBに基づいて年齢を計算する機能をここに持っています。 ディスクに書き込まれたくないメンバー変数にはtransientを使用できます。 

それが役に立てば幸い。!

0
nandeesh

Transient-keywordの簡単なサンプルコード。

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
Habeeb Perwad