シーケンス化、逆シーケンス化:serializable

10603 ワード

シーケンス化と逆シーケンス化の簡単な理解
ディレクトリ(?)[+]一、シーケンス化と逆シーケンス化の概念
オブジェクトをバイトシーケンスに変換するプロセスをオブジェクトのシーケンス化と呼ぶ.バイトシーケンスをオブジェクトに復元するプロセスをオブジェクトの逆シーケンス化と呼ぶ.
オブジェクトのシーケンス化には、主に2つの用途があります.
1)オブジェクトのバイトシーケンスをハードディスクに永続的に保存し、通常は1つのファイルに保存する.
2)ネットワーク上でオブジェクトのバイトシーケンスを転送する.
多くのアプリケーションでは、メモリ領域から離れ、長期保存のために物理ハードディスク(HDD)にチェックインするオブジェクトをシーケンス化する必要があります.例えば、最も一般的なのはWebサーバのSessionオブジェクトで、10万人のユーザーが同時にアクセスすると、10万人のSessionオブジェクトが現れる可能性があります.メモリが消費されない可能性があります.そこで、Webコンテナはいくつかのseesionをハードディスクにシーケンス化し、使用する必要がある場合は、ハードディスクに保存されているオブジェクトをメモリに復元します.
2つのプロセスがリモート通信を行う場合、互いに様々なタイプのデータを送信することができる.どのタイプのデータでも、ネットワーク上でバイナリシーケンスとして転送されます.送信側はこのJavaオブジェクトをバイトシーケンスに変換してこそ、ネットワーク上で伝送することができる.受信者はバイトシーケンスをJavaオブジェクトに復元する必要がある.
二、JDKクラスライブラリにおけるシーケンス化API
ObjectOutputStreamはオブジェクト出力ストリームを表し、そのwriteObject(Object obj)メソッドはパラメータで指定されたobjオブジェクトをシーケンス化し、得られたバイトシーケンスをターゲット出力ストリームに書き込むことができる.
ObjectInputStreamはオブジェクト入力ストリームを表し、readObject()メソッドはソース入力ストリームからバイトシーケンスを読み出し、逆シーケンス化してオブジェクトに戻ります.
SerializableとExternalizableインタフェースを実装したクラスのオブジェクトのみがシーケンス化されます.ExternalizableインタフェースはSerializableインタフェースから継承され、Externalizableインタフェースを実現するクラスは完全に自身でシーケンス化の動作を制御し、Serializableインタフェースを実現するクラスだけはデフォルトのシーケンス化方式を採用することができる.
オブジェクトのシーケンス化には、次の手順があります.
1)ファイル出力ストリームなどの他のタイプのターゲット出力ストリームをパッケージできるオブジェクト出力ストリームを作成します.
2)オブジェクト出力ストリームのwriteObject()メソッドでオブジェクトを書き込みます.
オブジェクトを逆シーケンス化するには、次の手順に従います.
1)ファイル入力ストリームなどの他のタイプのソース入力ストリームをパッケージできるオブジェクト入力ストリームを作成します.
2)オブジェクト入力ストリームのreadObject()メソッドでオブジェクトを読み込む.
オブジェクトのシーケンス化と逆シーケンスの例:
Personクラスを定義し、Serializableインタフェースを実現
[java] view plain copy
import java.io.Serializable;  

public class Person implements Serializable {  

    private static final long serialVersionUID = 4603642343377807741L;  
    private int age;  
    private String name;  
    private String sex;  

    public int getAge() {  
        return age;  
    }  

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

    public String getName() {  
        return name;  
    }  

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

    public String getSex() {  
        return sex;  
    }  

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

Personクラスオブジェクトのシーケンス化と逆シーケンス化
[java] view plain copy
import java.io.*;  
import java.text.MessageFormat;  

public class TestObjSerializeAndDeserialize {  

    public static void main(String[] args) throws Exception {  
        SerializePerson();//   Person    
        Person p = DeserializePerson();//   Perons    
        System.out.println(MessageFormat.format("name={0},age={1},sex={2}",  
                p.getName(), p.getAge(), p.getSex()));  
    }  


    private static void SerializePerson() throws FileNotFoundException, IOException {  
        Person person = new Person();  
        person.setName("gacl");  
        person.setAge(25);  
        person.setSex(" ");  
        // ObjectOutputStream      , Person     E  Person.txt   ,   Person          
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("E:/Person.txt")));  
        oo.writeObject(person);  
        System.out.println("Person       !");  
        oo.close();  
    }  

    private static Person DeserializePerson() throws Exception, IOException {  
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:/Person.txt")));  
        Person person = (Person) ois.readObject();  
        System.out.println("Person        !");  
        return person;  
    }  

}  

コードの実行結果は次のとおりです.
シーケンス化Personが成功した後、EディスクでPersonを生成した.txtファイル、逆シーケンス化PersonはEディスクを読み出すPersonである.txt後にPersonオブジェクト3,serialVersionUIDを生成する役割
s e r i a l V e r s i o n U I D:字面の意味ではシーケンス化されたバージョン番号であり、Serializableインタフェースを実現するクラスにはシーケンス化されたバージョン識別子を表す静的変数がある
1 private static final long serialVersionUID
シリアル化によるserialVersionUIDの生成方法
1)eclipse環境において,Serializableインタフェースを実装するクラス仮定クラスにserialVersionUIDが入っていない.次のような警告メッセージが表示されます
マウスでクリックするとserialVersionUIDを生成するダイアログボックスがポップアップします.たとえば、次の図に示します.
serialVersionUIDには、次の2つの生成方法があります.
このようにして生成されるserialVersionUIDは、1 Lであり、例えば、
private static final long serialVersionUID = 1L;
このようにして生成されるserialVersionUIDはクラス名,インタフェース名に基づいている.メソッドやプロパティなど、次のように生成されます.
private static final long serialVersionUID = 4603642343377807741L;
加入するとその警告メッセージは表示されません.たとえば、次のようになります.
2)Android Studioの開発環境の下で、SerialVersionUIDを自動的に生成するには、関連する構成が必要です.
ステップ1:File->setting->Inspections->Serializationissues、それを展開した後にserialzableclasswithout"serialVersionUID"をチェックする.
次の図を示します.
ステップ2:implements Serializable済みのエンティティクラスにカーソルを置き、alt+を押すとシーケンスバージョンIDを生成するダイアログボックスが表示されます.
では、serialVersionUID(シリアル化バージョン番号)はいったい何の役に立つのでしょうか.serialVersionUIDの役割を以下の例で説明します.次のコードを見てみましょう.
[java] view plain copy
public class TestSerialVersionUID {  
    public static void main(String[] args) throws Exception {  
        SerializeCustomer();//    Customer    
        Customer customer = DeserializeCustomer();//    Customer    
        System.out.println(customer);  
    }  

    private static void SerializeCustomer() throws FileNotFoundException, IOException {  
        Customer customer = new Customer("gacl", 25);  
        // ObjectOutputStream        
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(  
                new File("E:/Customer.txt")));  
        oo.writeObject(customer);  
        System.out.println("Customer       !");  
        oo.close();  
    }  

    private static Customer DeserializeCustomer() throws Exception, IOException {  
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(  
                new File("E:/Customer.txt")));  
        Customer customer = (Customer) ois.readObject();  
        System.out.println("Customer        !");  
        return customer;  
    }  

}  

class Customer implements Serializable {  
    //Customer      serialVersionUID  
    private String name;  
    private int age;  

    public Customer(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
    @Override  
    public String toString() {  
        return "name=" + name + ", age=" + age;  
    }  
}  

実行結果:
シーケンス化と逆シーケンス化は成功しました.
次に、Customerクラスを変更し、次のようにsexプロパティを追加します.
[java] view plain copy
class Customer implements Serializable {  

    //Customer      serialVersionUID  
    private String name;  
    private int age;  
    //    sex    
    private String sex;  

    public Customer(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  

    public Customer(String name, int age, String sex) {  
        this.name = name;  
        this.age = age;  
        this.sex = sex;  
    }  

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

その後、逆シーケンス操作を実行すると、次のような異常情報が放出されます.
[plain] view plain copy
Exception in thread "main" java.io.InvalidClassException: Customer; local class incompatible:  
stream classdesc serialVersionUID = -88175599799432325, local class serialVersionUID = -5182532647273106745  

つまり、ファイルストリームのclassとclasspathのclass、つまり修正されたclassは、互換性がなく、セキュリティメカニズムの考慮でプログラムがエラーを投げ出し、ロードを拒否しているということです.では、シーケンス化後にフィールドやメソッドを追加する必要がある場合は?どうすればいいですか.それは自分でserialVersionUIDを指定することです.TestSerialversionUIDの例では、CustomerクラスのserialVersionUIDを指定していない場合、javaコンパイラは自動的にこのclassに要約アルゴリズムを行い、指紋アルゴリズムに似ています.このファイルにスペースが1つ増えると、得られるUIDはまったく異なり、このような多くのクラスでは、この番号が唯一であることが保証されます.したがって、フィールドを追加すると、serialVersionUIDが明示的に指定されていないため、コンパイラはまたUIDを生成してくれました.もちろん、前にファイルに保存したものとは異なり、2つのシーケンス化バージョン番号が一致しないエラーが発生しました.したがって、serialVersionUIDを自分で指定すれば、シーケンス化後、後期のリストアに影響を与えることなく、フィールドやメソッドを追加することができ、リストア後のオブジェクトはそのまま使用でき、メソッドやプロパティも多く使用できます.
次に、Customerクラスの変更を続行し、CustomerにserialVersionUIDを指定します.変更後のコードは次のとおりです.
[java] view plain copy
class Customer implements Serializable {  

    private static final long serialVersionUID = -3907552831844917246L;  

    //Customer      serialVersionUID  
    private String name;  
    private int age;  
    //    sex    
//  private String sex;  

    public Customer(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  

//    public Customer(String name, int age, String sex) {  
//        this.name = name;  
//        this.age = age;  
//        this.sex = sex;  
//    }  

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

シーケンス化操作を再実行し、Customerオブジェクトをローカルハードディスク(HDD)のCustomerにシーケンス化します.txtファイルを保存し、Customerクラスを変更し、sexプロパティを追加します.変更後のCustomerクラスコードは次のとおりです.
[java] view plain copy
class Customer implements Serializable {  

    private static final long serialVersionUID = -3907552831844917246L;  

    //Customer      serialVersionUID  
    private String name;  
    private int age;  
    //    sex    
    private String sex;  

    public Customer(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  

    public Customer(String name, int age, String sex) {  
        this.name = name;  
        this.age = age;  
        this.sex = sex;  
    }  

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

逆シーケンス操作を実行すると、今回は逆シーケンスに成功します.四、serialVersionUIDの取値
serialVersionUIDの値は、Javaランタイム環境がクラスの内部詳細に基づいて自動的に生成します.クラスのソースコードを変更し、再コンパイルすると、新しく生成されたクラスファイルの
serialVersionUIDの値も変化する可能性があります.
クラスのserialVersionUIDのデフォルト値はJavaコンパイラの実装に完全に依存し、同じクラスに対して異なるJavaコンパイラでコンパイルすると、異なるserialVersionUIDにつながる可能性があります.
同じかもしれません.serialVersionUIDの独立性と決定性を向上させるために、シーケンス化可能なクラスに表示される定義serialVersionUIDに明確な値を与えることを強くお勧めします.
serialVersionUIDを明示的に定義するには、次の2つの目的があります.
1、場合によっては、クラスの異なるバージョンがシーケンス化に互換性があることが望ましいため、クラスの異なるバージョンが同じserialVersionUIDを持っていることを確保する必要がある.
2、場合によっては、クラスの異なるバージョンがシーケンス化に互換性を持たないようにする必要があります.そのため、クラスの異なるバージョンが異なるserialVersionUIDを持っていることを確認する必要があります.
友情の推薦:
JAvaベース->Serializableの使用:http://www.cnblogs.com/huhx/p/serializable.html
JAvaアドバンスド->Serializableのプロセス分析:http://www.cnblogs.com/huhx/p/serializable.html