Serializable and serialVersionUID

5131 ワード

class implements Serializableの場合、EclipseはserialVersionUIDの生成を要求します.多くの場合、私は「はい」を選択します.しかし、これはいったい何なのでしょうか.
package com.home.demo;

import java.io.Serializable;

public class Item implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	private int data;

    public Item (int data) {
        this.data = data;
    }

    public int getData() {
        return data;
    }

}

Eclipseは再びserialVersionUIDが必要だと注意した.はい、テストである以上、彼に1の値をあげます.
テストクラスを書いてserialize and deserialize Itemを試してみましょう
package com.home.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class UIDTest {
	
	public void save2Disk(String fileName) throws IOException{
	File file = new File(fileName);
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //set value to 101
        Item serializeMe = new Item(101); 
        oos.writeObject(serializeMe);
        oos.close();
        System.out.println("done!");
	}
	
	public void readFromDisk(String fileName) throws ClassNotFoundException, IOException{
	FileInputStream fis = new FileInputStream(fileName);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Item dto = (Item) ois.readObject();
        System.out.println("data : " + dto.getData());
        ois.close();
	}

	/**
	 * @param args
	 * @throws IOException 
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) {
		UIDTest test = new UIDTest();
		String name = "D:/out.dat";
		try{
			// write file
			//test.save2Disk(name);   //--1
			
			test.readFromDisk(name);  // --2
		}catch(Exception e){
			e.printStackTrace();
		}
     
	}

}

実行結果
101

完全に正しい!
Dディスクを見てください.ファイルがあります.dat. 書き込みファイルを閉じてoutを直接読み出す.dat 
実行結果
101

serialVersionUID=2 Lを
private static final long serialVersionUID = 2L;

さいうんてん
java.io.InvalidClassException: 
com.home.demo.Item; local class incompatible: 
stream classdesc serialVersionUID = 1, 
local class serialVersionUID = 2

ああ....エラー!
Java documentによると、
Serialization is for serializing instances, not classes. Static fields (methods are irrelevant since they are part of the class definition so they aren't serialized) will be reinitialized to whatever value they are set to when the class is loaded.
この説によると、ItemがserialVersionUIDの値を知っているはずがないのに、なぜ間違っているのか.
ドキュメントを読み続けます! 
serialVersionUIDは例外です.この値は確かに「get serialized」です. 
ObjectOutputStream writes every time the value ofserialVersionUID to the output stream. 
ObjectInputStream reads it back and if the value read from the stream does not agree with the serialVersionUID value in the current version of the class, then it throws the InvalidClassException.
Moreover, if there is no serialVersionUID officially declared in the class to be serialized, compiler automatically adds it with a value generated based on the fields declared in the class.
もしあなたが機械Aにデータをserializeして、B機械にdeserializeを送ったら、データの正確性を確定するのに一定の情報が必要です.serialVersionUIDはこの仕事をするために使われています.そのため、Eclipseは私たちが使用するserialVersionUIDを提案し、serializationに対して最も簡単な検査と制御を行うことができます.
戻ってEclipseのヒントを見てみましょう
Eclipseでは、SerialVersionUIDを迅速に追加する2つの方法があります.
add default serial version ID: Adds a default serial version ID to the selected type Use this option to add a user-defined ID in combination with custom serialization code if the type did undergo structural change since its first release.
Default値は1 Lで、互換性があることを前提に、古いバージョン番号を保持することができます.互換性がない場合、または互換性がないようにするには、手動でバージョン番号を増やします.
add generated serial version ID: Adds a generated serial version ID to the selected type Use this option to add a compiler-generated ID if the type didnot undergo structural change since its first release.
クラスの構造に基づいて生成されるhash値.属性やメソッドを増減すると、この値が変化する可能性があります.
シーンに合わせる
開発者はクラスを変更するたびに新しいバージョン番号を生成する必要があると考えており,下に互換性を持たないようにするには,既存のserialVesionUID宣言文を削除し,自動的に生成する.
個人的にはdefaultが簡単だと思います.2つ目は、クラス構造を変更するたびにバージョン番号を変更することを保証することができます.coolのように見えますが、実際には迷っています.
serialVersionUIDの使い方
What you should do is to change serialVersionUID (for example increase it by 1 or make your IDE generate automatically a new value) every time there is some change in the definition of data stored in the class. For example if you change data types, variable names or add new data – hence every time you want to have ‘backward incompatibility’ for deserialization.
Reference
http://stackoverflow.com/questions/6429462/java-static-serialization-rules
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it
http://www.javablogging.com/what-is-serialversionuid/
http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/