Javaに transient フィールドがあるのはなぜですか?
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 Serialization APIの秘密の発見 (Sun Developer Networkで最初に公開されていました)に、transient
キーワードを使用してシリアライゼーションを防止するシナリオについてのセクションがあります。特定の分野の。
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
として宣言されているため、永続記憶域には格納されません。
直列化したくない変数を定義できるようにするため。
オブジェクトには、シリアライズ/永続化したくないという情報(おそらく親ファクトリオブジェクトへの参照)があるかもしれません。これらを「一時的」とマークすることは、直列化メカニズムがこれらのフィールドを無視することを意味します。
私の小さな貢献:
過渡場とは何ですか?
基本的に、transient
キーワードで変更されたフィールドはすべて一時フィールドです。
Javaに一時フィールドが必要なのはなぜですか? transient
キーワードを使用すると、シリアル化プロセスをある程度制御でき、このプロセスから一部のオブジェクトプロパティを除外できます。シリアライゼーションプロセスは、主にJavaオブジェクトを永続化するために使用されます。そのため、ほとんどの場合、オブジェクトの状態は転送中でも非アクティブ中でも保持できます。場合によっては、オブジェクトの特定の属性を直列化しないことが理にかなっています。
どのフィールドに一時的なマークを付けますか?
これでtransient
キーワードとtransientフィールドの目的がわかりました。どのフィールドをtransientとマークするかを知ることが重要です。静的フィールドも直列化されていないため、対応するキーワードでもうまくいきます。しかし、これはあなたのクラスデザインを台無しにするかもしれません。これがtransient
キーワードが助けになるところです。値を他のフィールドから派生させることができるフィールドを直列化できないようにするため、それらを一時的なものとしてマークします。 interest
という名前のフィールドがあり、その値は他のフィールド(principal
、rate
、およびtime
)から計算できる場合は、それをシリアル化する必要はありません。
もう1つの良い例は、Wordの記事を数えることです。あなたが記事全体を保存しているのであれば、Wordのカウントを保存する必要は全くありません。またはロガーについて考えます。 Logger
インスタンスはシリアライズする必要がほとんどないため、一時的にすることができます。
transient
変数は、直列化できない変数です。
これが有用になる可能性がある場合の1つの例は、特定のオブジェクトインスタンスのコンテキストでのみ意味を持ち、オブジェクトをシリアル化およびシリアル化解除すると無効になる変数です。その場合は、必要に応じて有用なデータを使用してそれらを再初期化できるように、それらの変数を代わりにnull
にすると便利です。
transient
name__は、クラスフィールドをシリアル化する必要がないことを示すために使用されます。おそらく最良の例はThread
name__フィールドです。 Thread
name__をシリアライズする理由は通常ありません。その状態は「フロー固有」であるためです。
ネイティブJava以外のシリアライゼーションシステムもこの修飾子を使用できます。たとえば、Hibernateは @Transient または transient 修飾子のいずれかでマークされたフィールドを永続化しません。 Terracottaもこの修飾子を尊重します。
修飾子の比喩的な意味は、「このフィールドはメモリ内での使用のみを目的としています。永続化したり、この特定のVMの外側に移動しないでください。つまり、別のVMメモリスペースの値には頼れません。 volatile とよく似ているのは、特定のメモリやスレッドのセマンティクスに頼ることができないということです。
すべての変数が直列化可能というわけではないため
この質問に答える前に、シリアライゼーションについて説明する必要があります。科学コンピュータでのシリアライゼーションの意味を理解していれば、このキーワードを簡単に理解できるからです。
Serialization オブジェクトがネットワークを介して転送されたり、物理メディア(ファイルなど)に保存されている場合は、そのオブジェクトを "シリアル化"する必要があります。シリアル化はバイトステータスオブジェクトシリーズを変換します。これらのバイトはネットワーク上に送信されるか保存され、オブジェクトはこれらのバイトから再作成されます。
例
public class Foo implements Serializable
{
private String attr1;
private String attr2;
...
}
このオブジェクトのTRANSFERRT/SAVEDフィールドをSOしない場合は、keywordtransient
を使用できます。
private transient attr2;
シリアル化に伴う機密データを共有したくない場合に必要です。
簡単に言うと、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;
}
}
Google の一時的な意味として==短期間だけ持続します。永遠です。
Javaで一時的なものを作成したい場合は、transientキーワードを使用してください。
Q:どこでトランジェントを使うのですか?
A: 一般的にJavaでは、変数にそれらを取得してそれらの変数をファイルに書き込むことによってファイルにデータを保存することができます。変数データがファイルに書き込まれるのを避けたい場合は、その変数を一時的なものにします。
transient int result=10;
注意: 一時変数はローカルにはできません。
物事を明確にするためにもう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を使用できます。
それが役に立てば幸い。!
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);
}
}