Java〜シリアル化と逆シリアル化がSerializableインターフェースを実装する理由

シリアル化と逆シリアル化

シリアル化:オブジェクトをバイトのシーケンスに変換するプロセスは、オブジェクト
のシリアル化と呼ばれます。逆シリアル化:バイトのシーケンスをオブジェクトに復元するプロセスは、オブジェクトの逆シリアル化と呼ばれます。

いつシリアル化と逆シリアル化を使用する必要がありますか?

ローカルJVMでJavaインスタンスを実行します。今回は、シリアル化と逆シリアル化の必要はありません。

ただし、オブジェクトをメモリ内、データベース内、ブラウザと対話する必要がある場合、またはRPCを実装する必要がある場合は、この時点でシリアル化と逆シリアル化が必要です。

オブジェクトをJVMヒープメモリに永続化または送信する限り、この時点でシリアル化と逆シリアル化が必要です。

JSON形式は実際にはオブジェクトを文字列に変換するため、サーバーがブラウザと対話するときのデータ形式は実際には文字列です。文字列タイプのソースコードを見てみましょう。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
    
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

String型は、Serializableインターフェースを実装し、指定されたserialVersionUIDの値を表示します。
つまり、Jsonを使用して文字列データを転送すると、JVMは文字列データをシリアル化します。

なぜSerializableインターフェースを実装するのですか?

JavaでSerializableインターフェースを実装した後、JVMは、クラスがロードされたときにこのインターフェースを実装したことを検出し、インスタンスオブジェクトが初期化されたときに下部でシリアル化と逆シリアル化を実現するのに役立ちます。

serialVersionUIDの値を指定するのはなぜですか?

指定されたserialVersionUIDが表示されない場合、JVMはシリアル化中に属性に従ってserialVersionUIDを自動的に生成し、それを属性と一緒にシリアル化してから、永続性またはネットワーク送信を実行します。

デシリアライズ中に、JVMは属性に従って新しいバージョンのserialVersionUIDを自動的に生成し、この新しいバージョンのserialVersionUIDをシリアル化中に生成された古いバージョンのserialVersionUIDと比較します。同じ場合はデシリアライズが成功し、そうでない場合はエラーが発生します。報告されます。

serialVersionUIDが指定されていることが示されている場合、JVMはシリアル化および逆シリアル化中にserialVersionUIDを生成しますが、値は表示される値であり、serialVersionUID値は上書きされるため、新旧バージョンのserialVersionUIDは次のようになります。デシリアライズ中も同じです。

serialVersionUIDを指定しない場合の問題

  1. 異なるコンピューターにPersonクラスがあり、ネットワーク経由で送信する場合は、コンピューターAでシリアル化を実装し、コンピューターBで逆シリアル化する必要があります。次に、serialVersionUIDを指定しない場合、Failureを逆シリアル化できます。

  2. インスタンス開発の過程で、クラスは頻繁に変更されます。JVMによって自動的に生成されたserialVersionUIDを使用する場合、このクラスにすでにいくつかのシリアル化されたオブジェクトがある場合、このクラスを変更すると、これらのオブジェクトが逆シリアル化されるとエラーが報告されます

テストする例を書いてください:
(1)ユーザークラス

指定されたserialVersionUIDを表示しません。

public class User implements Serializable {
    
    

    private String name;
    private Integer age;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

(2)テストクラス

最初にシリアル化し、次に逆シリアル化します。

public class DemoSerialVersionUID {
    
    

    private static void serialize(User user) throws Exception {
    
    
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\test\\111.txt")));
        oos.writeObject(user);
        oos.close();
    }

    private static User deserialize() throws Exception{
    
    
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\test\\111.txt")));
        return (User) ois.readObject();
    }


    public static void main(String[] args) throws Exception {
    
    
        User user = new User();
        user.setName("Listen");
        user.setAge(22);
        System.out.println("序列化前的结果: " + user);

        serialize(user);

        User dUser = deserialize();
        System.out.println("反序列化后的结果: "+ dUser);
    }

}

(3)結果

最初に逆シリアル化コードをコメントアウトし、シリアル化コードを実行してから、プロパティsexをUserクラスに追加します

public class User implements Serializable {
    
    

    private String name;
    private Integer age;
    private String sex;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public String getSex() {
    
    
        return sex;
    }

    public void setSex(String sex) {
    
    
        this.sex = sex;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

次に、シリアル化コードをコメントアウトして逆シリアル化コードを実行すると、最終結果は次のようになります。

Exception in thread "main" java.io.InvalidClassException: User; local class incompatible: stream classdesc serialVersionUID = -8511650324417820915, local class serialVersionUID = -29281549270299246

エラーの結果は、シリアル化と逆シリアル化によって生成されたserialVersionUIDに一貫性がないことです。

次に、上記のUserクラスに基づいてserialVersionUIDを表示して指定します

上記の手順を再度実行すると、テスト結果は次のようになります。

序列化前的结果: User{
    
    name='Listen', age=22, sex='null'}
反序列化后的结果: User{
    
    name='Listen', age=22, sex='null'}

Process finished with exit code 0

指定されたserialVersionUIDを表示した後、シリアル化と逆シリアル化によって生成される不整合なserialVersionUIDの問題が解決されます。

Javaシリアル化の他の機能

transientキーワードによって変更された属性はシリアル化されず、静的属性もシリアル化されません。

静的属性がシリアル化されないのはなぜですか?

シリアル化はインスタンスオブジェクトであり、静的属性はオブジェクトよりも優先して存在し、クラスのロードとともにロードされるため、シリアル化されません。

誰かが尋ねるかもしれません、serialVersionUIDも静的によって変更されます、なぜserialVersionUIDがシリアル化されるのですか?

実際、serialVersionUID属性はシリアル化されていません。JVMはオブジェクトをシリアル化するときにserialVersionUIDを自動的に生成し、表示および指定するserialVersionUID属性値を自動生成されたserialVersionUIDに割り当てます。

おすすめ

転載: blog.csdn.net/Shangxingya/article/details/113744323