serialVersionUIDを理解する
The serializable class xxx does not declare a static final serialVersionUID field of type long
だから… serialVersionUIDとは何ですか?
serialVersionUIDは、Serializableクラスのバージョンコントロールとして使用されます。 serialVersionUIDを明示的に宣言していない場合、JVMは、http://docs.oracle.com/javase/1.5.0/docs/api/に記載されているように、Serializableクラスのさまざまな側面に基づいて自動的に行います。 java/io/Serializable.html[Java(TM)オブジェクト直列化仕様]
1. SerialVersionUIDの例
上記のステートメントは、最初はわかりにくいです(少なくとも私はそうでした)。Serializableクラスがバージョン管理を実装するためにSerialVersionUIDをどのように使用するかを理解するための例を始めましょう。
1.1 Address.java
serialVersionUIDが1Lの直列化可能クラス。
import java.io.Serializable; public class Address implements Serializable{ private static final long serialVersionUID = 1L; String street; String country; public void setStreet(String street){ this.street = street; } public void setCountry(String country){ this.country = country; } public String getStreet(){ return this.street; } public String getCountry(){ return this.country; } @Override public String toString() { return new StringBuffer(" Street : ") .append(this.street) .append(" Country : ") .append(this.country).toString(); } }
1.2 WriteObject.java
Addressオブジェクトをファイル “c:\\ address.ser”に書き込み/シリアライズするためのシンプルなクラスです。
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class WriteObject{ public static void main (String args[]) { Address address = new Address(); address.setStreet("wall street"); address.setCountry("united states"); try{ FileOutputStream fout = new FileOutputStream("c:\\address.ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(address); oos.close(); System.out.println("Done"); }catch(Exception ex){ ex.printStackTrace(); } } }
1.3 ReadObject.java
単純なクラスで、ファイル “c:\\ address.ser”からAddressオブジェクトを読み込み/逆シリアル化します。
import java.io.FileInputStream; import java.io.ObjectInputStream; public class ReadObject{ public static void main (String args[]) { Address address; try{ FileInputStream fin = new FileInputStream("c:\\address.ser"); ObjectInputStream ois = new ObjectInputStream(fin); address = (Address) ois.readObject(); ois.close(); System.out.println(address); }catch(Exception ex){ ex.printStackTrace(); } } }
2.テスト
serialVersionUIDの使用方法を示すためにいくつかのテストをしましょう。
2.1同じserialVersionUID
同じserialVersionUID、デシリアライズ処理中は問題ありません
javac Address.java javac WriteObject.java javac ReadObject.java java WriteObject java ReadObject Street : wall street Country : united states
2.2異なるserialVersionUID
Address.javaでは、serialVersionUIDを2Lに変更します(1Lでした)。もう一度コンパイルしてください。
javac Address.java java ReadObject java.io.InvalidClassException: Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 ... at ReadObject.main(ReadObject.java:14)
-
serialVersionUID “1L”
を使用してシリアライゼーションクラスを作成しますが、更新されたシリアライズクラス
serialVersionUID “2L” ** を使用してそれを取得しようとするため、 “InvalidClassException”が発生します。
The serialVersionUID have to match during the serialization and
deserialization process.
-
あなたのserialVersionUIDを更新する必要がありますか?** +シリアライズ可能クラスのいくつかの互換性のないJavaタイプの変更でシリアライゼーションクラスが更新されると、serialVersionUIDを更新する必要があります。
シリアライズ可能クラスへの互換性のある互換性のないJavaタイプの変更の詳細は、http://docs.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html[Javaオブジェクトのシリアライズ仕様]を参照してください。
3.デフォルトのserialVersionUIDの何が問題になっていますか?
serialVersionUIDが宣言されていない場合、JVMは独自のアルゴリズムを使用してデフォルトのSerialVersionUIDを生成します。アルゴリズムはhttp://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100で確認できます。[ここに]。
-
デフォルトのserialVersionUIDの計算はクラスの詳細に非常に敏感で、異なるJVM実装** と異なる場合があり、デシリアライズ処理中に予期しないInvalidClassExceptionsが発生する可能性があります。
3.1クライアント/サーバ環境
__クライアントはWindowsでSUNのJVMを使用しています。 – LinuxでJRockitを使用しているサーバー。
クライアントは、デフォルトで生成されたserialVersionUID(例えば123L)を有する直列化可能クラスをソケットを介してサーバに送信し、サーバは直列化解除処理中に異なるserialVersionUID(例えば124L)を生成し、予期しないInvalidClassExceptionsを発生させる。
3.2ファイル/データベース環境
– App#1は、WindowsでSUNのJVMを使用しています。 – App#2はLinuxでJRockitを使用しています.
シリアライゼーションはファイルまたはデータベースに保存できました。 App#2は、直列化可能クラスをデータベースに格納し、デフォルトではserialVersionUID(例えば123L)を生成し、App#2は逆直列化処理中に異なるserialVersionUID(例えば124L)を生成し、予期しないInvalidClassExceptionsを発生させる。
ここでは、http://en.wikipedia.org/wiki/List
of
JVM__implementations[JVM実装の一覧]を確認できます。
4. serialVersionUIDの生成方法
JDKの「serialver」またはEclipse IDEを使用して、自動的にserialVersionUIDを生成することができます。リンク://java/how-to-generate-serialversionuid/[詳細を参照]。
結論
上記の異なるJVMの問題を避けるために、serialVersionUIDを宣言することを強くお勧めしますが、serialVersionUIDがバージョン管理をどのように実装するのか、そしてクラスがシリアル化を使用する必要があるのかを理解することをお勧めします。 serialVersionUIDの概念を理解することは、どのような推奨事項にも目をつぶっているよりも優れています。
参考文献
-
http://en.wikipedia.org/wiki/List
of
JVM__implementations -
http://java.sun.com/javase/6/docs/platform/serialization/spec/class.html#4100
-
http://stackoverflow.com/questions/419796/explicit-serialversionuid-considered-harmful
-
http://www.javaworld.com/javaworld/jw-02-2006/jw-0227-control.html?page=1
-
http://www.java-forums.org/new-java/8196-serialversionuid.html
リンク://タグ/java/[java]
serialversionuid