ホームページ  >  記事  >  Java  >  Javaでのtransientキーワードの使用分析(コード)

Javaでのtransientキーワードの使用分析(コード)

不言
不言オリジナル
2018-09-08 17:02:251872ブラウズ

この記事の内容は、Java における一時的なキーワードの使用分析 (コード) に関するものです。必要な方は参考にしていただければ幸いです。

1. transient の役割と用途

オブジェクトが Serilizable インターフェイスを実装している限り、このクラスのすべてのプロパティとメソッドはシリアル化できます。自動的にシリアル化されます。

しかし、実際の開発プロセスでは、このクラスの一部の属性はシリアル化する必要があるが、他の属性はシリアル化する必要がないという問題によく遭遇します。 以下に 2 つの例を示します:

(1)ユーザーはいくつかの機密情報 (パスワード、銀行カード番号など) を持っていますが、セキュリティ上の理由から、ネットワーク操作 (主にシリアル化操作が含まれるため、ローカルのシリアル化キャッシュも適用されます) 中に送信されることは望ましくありません。これらの情報に一時的なキーワード を追加できます。つまり、このフィールドのライフサイクルは呼び出し元のメモリ内にのみ存在し、永続化のためにディスクに書き込まれることはありません。

(2) クラス内のフィールド値は、他のフィールドに基づいて派生できます。たとえば、長方形のクラスには、長さ、幅、面積の 3 つの属性があります (単なる例であり、通常はこのように設計されていません)。シリアル化中に、属性をシリアル化する必要はありません。つまり、Java の transient キーワードを使用すると、Serilizable インターフェイスを実装し、必要のない属性の前にキーワード transient を追加するだけで済みます。オブジェクトをシリアル化する場合、このプロパティは指定された宛先にシリアル化されません。

サンプル コードは次のとおりです。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
/**
 * @description 使用transient关键字不序列化某个变量
 *        注意读取的时候,读取数据的顺序一定要和存放数据的顺序保持一致
 *       
 */
public class TransientTest {
 
    public static void main(String[] args) {
 
        User user = new User();
        user.setUsername("Alexia");
        user.setPasswd("123456");
 
        System.out.println("read before Serializable: ");
        System.out.println("username: " + user.getUsername());
        System.err.println("password: " + user.getPasswd());
 
        try {
            ObjectOutputStream os = new ObjectOutputStream(
                    new FileOutputStream("C:/user.txt"));
            os.writeObject(user); // 将User对象写进文件
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            ObjectInputStream is = new ObjectInputStream(new FileInputStream(
                    "C:/user.txt"));
            user = (User) is.readObject(); // 从流中读取User的数据
            is.close();
 
            System.out.println("\nread after Serializable: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());
 
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 
class User implements Serializable {
    private static final long serialVersionUID = 8294180014912103005L;  
 
    private String username;
    private transient String passwd;
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getPasswd() {
        return passwd;
    }
 
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
 
}

出力は

read before Serializable: 
username: Alexia
password: 123456
read after Serializable: 
username: Alexia
password: null

です。パスワード フィールドは null で、逆シリアル化中にファイルから情報がまったく取得されなかったことを示します。

2. 一時的な使用の結果

1) 変数が一時的に変更されると、その変数はオブジェクトの永続化の一部ではなくなり、シリアル化後には変数の内容にアクセスできなくなります。

2) 静的変数は、一時変数によって変更されたかどうかに関係なく、シリアル化できません。

3) transient キーワードはスコープを変更します。

変更できるのは変数のみであり、メソッドやクラスは変更できません

。ローカル変数は transient キーワードでは変更できないことに注意してください。変数がユーザー定義のクラス変数の場合、クラスは Serializable インターフェイスを実装する必要があります。

2 番目の点は、一部の人にとっては混乱するかもしれません。User クラスのユーザー名フィールドの前に static キーワードを追加した後、プログラムの実行結果は変化しないことがわかりました。つまり、静的ユーザー名も「Alexia」として読み取られるからです。これは3番目の点と矛盾しませんか?これは実際に当てはまります。3 番目の点は確かに正しいです (静的変数は、非シリアル化の後、クラス内の静的変数 username の値は、現在のクラス内の対応する静的変数になります)。 JVM 値、この値は JVM 内にあり、デシリアライゼーションから派生したものではありません、信じられませんか?さて、以下で証明してみましょう:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
/**
 * @description 使用transient关键字不序列化某个变量
 *        注意读取的时候,读取数据的顺序一定要和存放数据的顺序保持一致
 *        
 */
public class TransientTest {
 
    public static void main(String[] args) {
 
        User user = new User();
        user.setUsername("Alexia");
        user.setPasswd("123456");
 
        System.out.println("read before Serializable: ");
        System.out.println("username: " + user.getUsername());
        System.err.println("password: " + user.getPasswd());
 
        try {
            ObjectOutputStream os = new ObjectOutputStream(
                    new FileOutputStream("C:/user.txt"));
            os.writeObject(user); // 将User对象写进文件
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            // 在反序列化之前改变username的值
            User.username = "jmwang";
 
            ObjectInputStream is = new ObjectInputStream(new FileInputStream(
                    "C:/user.txt"));
            user = (User) is.readObject(); // 从流中读取User的数据
            is.close();
 
            System.out.println("\nread after Serializable: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());
 
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 
class User implements Serializable {
    private static final long serialVersionUID = 8294180014912103005L;  
 
    public static String username;
    private transient String passwd;
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getPasswd() {
        return passwd;
    }
 
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
 
}

実行結果は次のとおりです:

read before Serializable: 
username: Alexia
password: 123456
read after Serializable: 
username: jmwang
password: null
これは、逆シリアル化後のクラスの静的変数 username の値が、現在の JVM の対応する静的変数の値であることを示しています。シーケンスではなく jmwang を変更しました。 変換されたときのアレクシアの値。

3. transient の使用法の詳細 - transient キーワードによって変更された変数はシリアル化できないというのは本当ですか?

import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
 
/**
 * @descripiton Externalizable接口的使用
 *
 */
public class ExternalizableTest implements Externalizable {
 
    private transient String content = "是的,我将会被序列化,不管我是否被transient关键字修饰";
 
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(content);
    }
 
    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        content = (String) in.readObject();
    }
 
    public static void main(String[] args) throws Exception {
 
        ExternalizableTest et = new ExternalizableTest();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
                new File("test")));
        out.writeObject(et);
 
        ObjectInput in = new ObjectInputStream(new FileInputStream(new File(
                "test")));
        et = (ExternalizableTest) in.readObject();
        System.out.println(et.content);
 
        out.close();
        in.close();
    }
}

コンテンツ変数はシリアル化されますか?さて、すべての答えを出力しました。はい、結果は次のようになります:

1これは、transient キーワードで変更されたクラス変数はシリアル化できないという意味ではないでしょうか?

是的,我将会被序列化,不管我是否被transient关键字修饰

Java では、オブジェクトのシリアル化は 2 つのインターフェイスを実装することで実現できます:

(1) Serializable インターフェイスが実装されている場合、すべてのシリアル化は自動的に実行されます (2) Serializable インターフェイスが実装されている場合、外部化可能なインターフェイスの場合これは、一時的に変更されるかどうかとは関係ありません。したがって、2 番目の例では、null ではなく、変数 content の初期化された内容が出力されます。

関連する推奨事項:

Java 一時キーワードの使用法の概要

Java 一時キーワードの使用コード例の概要

Java マルチスレッド プログラミングにおける synchronized キーワードの基本的な使用方法の説明

以上がJavaでのtransientキーワードの使用分析(コード)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。