SerializableインタフェースとserialVersionUID

3697 ワード

クラスは、Serializableインタフェースを実装した後にシーケンス化することができる.このインタフェースにはメソッドとフィールドはありません.ただ、このクラスがシーケンス化できることを示すために使用されます.
親がserializableインタフェースを実装している場合、サブクラス実装もインタフェースを実装していない場合も同じです.サブクラスと親クラスのすべての非static、非transientのフィールドの値は保存および復元できます.
親がserializableインタフェースを実装していない場合、親には参照可能でクラスにアクセス可能なコンストラクション関数が必要ですが、親のすべてのフィールドの値は保存されません.
逆シーケンス化の場合、serializableインタフェースを実装していないクラスは、パラメトリック構造関数を呼び出してインスタンス化します.パラメータのないコンストラクション関数は、サブクラスのフィールドが復元される前にクラス(逆シーケンス化されたクラス)にアクセスできる必要があります.親がSerializableインタフェースを実装しない場合は、デフォルトのパラメトリックなコンストラクタが必要です.これは、Javaオブジェクトの構造には親オブジェクトが必要であり、子オブジェクトがあり、逆シーケンス化も例外ではないからです.逆シーケンス化の場合、親オブジェクトを構築するには、デフォルトの親として親クラスの非パラメトリックコンストラクション関数のみを呼び出すことができます.したがって、親オブジェクトの変数値を取得すると、親クラスの無パラメトリック関数を呼び出した値になります.この場合、シーケンス化時に必要に応じて親無パラメトリック構造関数で変数を初期化します.そうしないと、親変数値はint型のデフォルトが0、string型のデフォルトがnullなどのデフォルト宣言値になります.
シーケンス化と逆シーケンス化の特殊な処理が必要な場合は、クラスにはこれらの方法が必要です.
private void writeObject(java.io.ObjectOutputStream out)  throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;

writeObjectは、readObjectリカバリのためにクラスのステータス情報を記録することができる.このメソッドでoutを呼び出すことができます.defaultWriteObjectは、デフォルトのクラス情報を記録します.
シーケンス化されたクラスにObject writeReplace()メソッドがある場合、シーケンス化時に呼び出されます.現在のクラスを置換する
クラスのclass情報、クラス署名、transient以外の静的でないフィールド値を読み込みます.
objectInputStream.readObject();

親:
public class ParentPer  {
    private String p1;
    private static String p2;

    protected int p3;
    public int p4;
    ParentPer(){
        System.out.println("         ");
    }
    @Override
    public String toString() {
        return p1+"_"+p2+"_"+p3+"_"+p4;
    }
    public String getP1() {
        return p1;
    }

    public void setP1(String p1) {
        this.p1 = p1;
    }

    public static String getP2() {
        return p2;
    }

    public static void setP2(String p2) {
        ParentPer.p2 = p2;
    }
}

サブクラス:
public class ChildPtr extends ParentPer implements Serializable{
    private String c1;
    private static String c2;

    protected int c3;
    public int c4;

    public ChildPtr(String c1, String c2) {
        super();
        this.c1 = c1;
        ChildPtr.c2 = c2;
        super.setP1("p1");
        setP2("p2");
        p3=5;
        p4=6;
    }

    @Override
    public String toString() {
        return c1+"_"+c2+"_"+c3+"_"+c4+" "+super.toString();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ChildPtr childPtr = new ChildPtr("c1", "c2");
        childPtr.c3=9;
        childPtr.c4=10;
        byte[] c = SerializableUtil.serialiable(childPtr);

        ByteArrayInputStream bi = new ByteArrayInputStream(c);
        ObjectInputStream objectInputStream = new ObjectInputStream(bi);
        ChildPtr cc = (ChildPtr) objectInputStream.readObject();
        System.out.println(childPtr);
        System.out.println(cc);
    }
}

serialVersionUIDフィールドは、クラスのシーケンス化バージョンを表し、逆シーケンス化時の検証に使用されます.逆シーケンス化時のクラスのserialVersionUIDがシーケンス化時と異なる場合、InvalidClassException例外が放出されます.finalとstatic修飾でなければなりません.private修飾を使用することをお勧めします.継承されて使用する必要はありません.シーケンス化と逆シーケンス化の場合にのみ使用します.ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
クラスにこのフィールドがない場合、実行時にjvmが値の計算を手伝います.シーケンス化されたクラスごとにserialVersionUIDを明確に指定することをお勧めします.デフォルトの計算方法はコンパイラの実装に大きく依存するため、逆シーケンス化時にInvalidClassException異常を放出する可能性があります.
配列タイプはserialVersionUIDを明示的に指定できないため、デフォルトの計算値を使用しますが、逆シーケンス化時にserialVersionUIDを検証する必要はありません.