web-dev-qa-db-ja.com

単純な1Lではなく長いserialVersionUIDを生成するのはなぜですか?

クラスがEclipseでSerializableを実装する場合、2つのオプションがあります。デフォルトのserialVersionUID(1L)または生成されたserialVersionUID(3567653491060394677L)を追加します。最初のものはもっとクールだと思いますが、多くの場合、2番目のオプションを使用している人を見ました。 long serialVersionUIDを生成する理由はありますか?

203
IAdapter

私の知る限り、それは以前のリリースとの互換性のためだけです。これは、以前にserialVersionUIDを使用することを怠り、 compatible である必要があることがわかっているがシリアル化が中断する変更を行った場合にのみ役立ちます。

詳細については、 Java Serialization Spec を参照してください。

85
Michael Myers

シリアル化バージョンUIDの目的は、オブジェクトの有効なシリアル化を実行するために、クラスのさまざまなバージョンを追跡することです。

アイデアは、クラスの特定のバージョンに固有のIDを生成することであり、シリアル化されたオブジェクトの構造に影響を与える新しいフィールドなど、クラスに新しい詳細が追加されると変更されます。

常に同じID(1Lなど)を使用することは、将来、クラス定義が変更されてシリアル化されたオブジェクトの構造が変更されると、オブジェクトを逆シリアル化しようとしたときに問題が発生する可能性が高いことを意味します。

IDが省略された場合、Javaは実際にオブジェクトのフィールドに基づいてIDを計算しますが、高価なプロセスであると思うので、手動で提供するとパフォーマンスが向上します。

クラスのシリアル化とバージョン管理について説明している記事へのリンクを次に示します。

69
coobird

生成されたものの主な理由は、既に永続化されたコピーを持つクラスの既存のバージョンと互換性を持たせるためです。

18
Robin

serialVersionUIDの「長い」デフォルトは、 Java Serialization Specification で定義されているデフォルト値であり、デフォルトのシリアル化動作から計算されます。

したがって、デフォルトのバージョン番号を追加すると、構造的に何も変更されていない限り、クラスはより高速に(デ)シリアル化されますが、クラスを変更する(フィールドを追加/削除する)場合も更新することに注意する必要がありますシリアルナンバー。

既存のビットストリームと互換性がある必要がない場合は、そこに1Lを配置し、何かが変更されたときに必要に応じてバージョンを増やすことができます。つまり、変更されたクラスのデフォルトのシリアル化バージョンが古いクラスのデフォルトのバージョンと異なる場合。

14
David Schmitt

Java.io.Serializableを実装するクラスを定義するたびに、serialVersionUIDを作成する必要があります。そうしないと、自動的に作成されますが、これは悪いことです。自動生成されたserialVersionUIDは、クラスのメソッドシグネチャに基づいているため、将来クラスを変更して(たとえば)メソッドを追加すると、「古い」バージョンのクラスの逆シリアル化は失敗します。起こりうることは次のとおりです。

  1. SerialVersionUIDを定義せずに、クラスの最初のバージョンを作成します。
  2. クラスのインスタンスを永続ストアにシリアル化します。 serialVersionUIDが自動的に生成されます。
  3. クラスを変更して新しいメソッドを追加し、アプリケーションを再デプロイします。
  4. 手順2でシリアル化されたインスタンスを逆シリアル化しようとしますが、別の自動生成されたserialVersionUIDがあるため、失敗します(成功するはずです)。
10
Pankaj Kumar

SerialVersionUIDを指定しない場合、Javaはすぐに作成します。生成されたserialVersionUIDはその番号です。クラスを変更して、以前のシリアル化されたバージョンと実際には互換性がなく、ハッシュを変更する場合は、生成された非常に大きな数のserialVersionUID(またはエラーメッセージからの「期待される」数)を使用する必要があります。それ以外の場合、自分ですべてを追跡する場合は、0、1、2 ...の方が優れています。

6
joeforker

SerialVersionUID(3567653491060394677L)を生成するのではなく、serialVersionUID(1L)を使用すると、何か言います。

このクラスのバージョン番号が1で、互換性のないシリアル化されたバージョンを持つこのクラスに触れるシステムはないと、100%確信しているということです。

シリアル化されたバージョン履歴が不明であるという言い訳を考えることができる場合、自信を持って言うのは難しいかもしれません。一生のうちに、成功したクラスは多くの人々によって維持され、多くのプロジェクトに住み、多くのシステムに常駐します。

それに苦しむことができます。または、失うことを望んで宝くじをすることができます。バージョンを生成すると、問題が発生する可能性がわずかにあります。 「誰もまだ1を使っていないに違いない」と仮定すると、オッズは小さいよりも大きくなります。 0と1がクールだと思うからこそ、ヒットする確率が高くなります。

-

SerialVersionUID(1L)を使用するのではなく、serialVersionUID(3567653491060394677L)を生成すると、何かを言っています。

あなたは、人々がこのクラスの歴史上、他のバージョン番号を手動で作成または生成したかもしれないと言っていますが、ロングズは大きな数字を驚かせているので気にしません。

いずれにせよ、クラスが存在する、または存在する世界全体でクラスをシリアル化するときに使用されるバージョン番号の履歴を完全に知らない限り、チャンスをつかんでいます。 1がAOKであることを100%確認する時間がある場合は、それを選択します。それが多くの仕事である場合、先に進み、盲目的に番号を生成します。あなたは宝くじに勝つ可能性があります。もしそうなら、私に知らせてください、そして、私はあなたにビールを買います。

宝くじをするというこのすべての話で、serialVersionUIDはランダムに生成されるという印象を与えたかもしれません。実際、数値の範囲がLongのすべての可能な値に均等に分配されている限り、それは問題ありません。ただし、実際には次のように行われます。

http://docs.Oracle.com/javase/6/docs/platform/serialization/spec/class.html#41

それで得られる唯一の違いは、ランダムのソースが必要ないことです。クラス自体の変更を使用して結果を変更しています。しかし、鳩の巣の原則によれば、それが間違って衝突する可能性がまだあります。信じられないほどありそうもない。幸運を祈ります。

ただし、クラスが1つのシステムと1つのコードベースのみに存在する場合でも、手動で数を増やすと衝突の可能性がゼロになると考えると、人間を理解できません。 :)

4
SomeGuy

まあ、serialVersionUIDは「静的フィールドがシリアル化されない」というルールの例外です。 ObjectOutputStreamは、serialVersionUIDの値を毎回出力ストリームに書き込みます。 ObjectInputStreamはそれを読み戻し、ストリームから読み取られた値がクラスの現在のバージョンのserialVersionUID値と一致しない場合、InvalidClassExceptionをスローします。さらに、シリアル化されるクラスにserialVersionUIDが正式に宣言されていない場合、コンパイラは、クラスで宣言されたフィールドに基づいて生成された値を自動的に追加します。

1
Lucky

多くの場合、デフォルトIDは一意ではありません。ユニークなコンセプトを作成するためにidを作成します。

0

@David Schmittsの回答に追加するために、経験則として、慣例ではないデフォルトの1Lを常に使用します。戻ってそれらの一部を数回変更するだけで済みましたが、変更を行うたびにデフォルトの番号が1つずつ更新されることを知っていました。

私の現在の会社では、自動生成された番号が必要なので、慣習としてそれを使用しますが、デフォルトを好みます。何らかの理由でシリアル化されたクラスの構造を絶えず変更していると思わない限り、私の慣習では、それがあなたが働く慣習ではない場合、デフォルトを使用します。

0
James Drinkard