回答:
のドキュメントはjava.io.Serializable
、おそらくあなたが得るのと同じくらい良い説明です:
シリアル化ランタイムは、シリアル化可能な各クラスにと呼ばれるバージョン番号を関連付けます
serialVersionUID
。これは、シリアル化されたオブジェクトの送信者と受信者が、そのオブジェクトに対して、シリアル化に関して互換性のあるクラスを読み込んだことを確認するために使用されます。受信serialVersionUID
者が、対応する送信者のクラスとは異なるオブジェクトのクラスをロードした場合、逆シリアル化の結果はになりInvalidClassException
ます。直列化可能クラスは、static、final、およびtypeである必要があるserialVersionUID
という名前のフィールドを宣言することにより、それ自体を明示的に宣言serialVersionUID
できますlong
。ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
直列化可能クラスがを明示的に宣言しない場合、直列
serialVersionUID
化ランタイムはserialVersionUID
、Java(TM)オブジェクト直列化仕様で説明されているように、クラスのさまざまな側面に基づいてそのクラスのデフォルト値を計算します。ただし、デフォルトの計算は、コンパイラーの実装によって異なる可能性があるクラスの詳細に非常に敏感であり、逆シリアル化中に予期しない結果になる可能性があるため、すべての直列化可能クラスで値を明示的に宣言することを強くお勧めしserialVersionUID
ます。したがって、異なるJavaコンパイラーの実装全体で一貫した値を保証するには、シリアライズ可能なクラスで明示的な値を宣言する必要があります。また、明示的であることを強くお勧めしますserialVersionUID
InvalidClassExceptions
serialVersionUID
serialVersionUID
serialVersionUID
宣言は、可能な場合はプライベート修飾子を使用します。そのような宣言は、すぐに宣言するクラスserialVersionUID
フィールドにのみ適用されるため、継承されたメンバーとしては役に立ちません。
実装のためにシリアル化する必要があるという理由だけでシリアル化している場合(HTTPSession
たとえば、のシリアル化を考慮している場合、それが格納されているかどうかに関係なく、おそらくde-serializing
フォームオブジェクトは気にしません)。これは無視してください。
実際にシリアライゼーションを使用している場合は、シリアライゼーションを直接使用してオブジェクトを格納および取得することを計画している場合にのみ問題になります。はserialVersionUID
クラスのバージョンを表します。クラスの現在のバージョンが以前のバージョンと下位互換性がない場合は、バージョンを増やす必要があります。
ほとんどの場合、シリアル化を直接使用することはおそらくないでしょう。この場合は、SerialVersionUID
クイックフィックスオプションをクリックしてデフォルトを生成し、それを心配する必要はありません。
serialVersionUID
互換性のない変更からユーザーを保護するという@TomAndersonの主張は有効だと思います。@SuppressWarnings
クラスを永続的なストレージに使用したくない場合は、ドキュメントを使用する方が意図がよくなります。
serialVersionUID
最後の手段であり、絶望の助言です。
Josh Blochの著書「Effective Java(2nd Edition)」をプラグインするこの機会を逃すことはできません。第11章は、Javaシリアライゼーションに関する不可欠なリソースです。
Joshによると、自動生成されたUIDは、クラス名、実装されたインターフェース、およびすべてのパブリックメンバーと保護されたメンバーに基づいて生成されます。これらのいずれかを何らかの方法で変更すると、が変更されserialVersionUID
ます。したがって、クラスのバージョンが1つしかシリアル化されない(プロセス間で、または後でストレージから取得される)ことが確実である場合にのみ、それらをいじる必要はありません。
今のところそれらを無視し、後でクラスを何らかの方法で変更する必要があるが古いバージョンのクラスとの互換性を維持する必要があることがわかった場合は、JDKツールserialverを使用serialVersionUID
して古いクラスにを生成し、明示的に設定することができます。新しいクラスで。(変更によっては、メソッドwriteObject
とreadObject
メソッドを追加してカスタムシリアライゼーションを実装する必要がある場合もありますSerializable
。javadocまたは前述の第11章を参照してください。)
これらのserialVersionUID警告を無視するようにEclipseに指示できます。
「ウィンドウ」>「設定」>「Java」>「コンパイラー」>「エラー/警告」>「潜在的なプログラミングの問題」
ご存知ない場合は、このセクションで有効にできる他の警告がたくさんあります(またはエラーとして報告される場合もあります)。多くは非常に便利です。
などなど。
serialVersionUID
シリアル化されたデータのバージョン管理を容易にします。その値は、シリアライズ時にデータとともに保存されます。逆シリアル化すると、同じバージョンがチェックされ、シリアル化されたデータが現在のコードとどのように一致するかが確認されます。
データをバージョン管理したい場合は、通常serialVersionUID
、0 から始め、クラスの構造を変更するたびにバンプして、シリアル化されたデータを変更します(非一時フィールドの追加または削除)。
組み込みの逆シリアル化メカニズム(in.defaultReadObject()
)は、古いバージョンのデータからの逆シリアル化を拒否します。ただし、必要に応じて、古いデータを読み戻す独自のreadObject()関数を定義できます。次に、このカスタムコードはをチェックしてserialVersionUID
、データがどのバージョンにあるかを確認し、それを逆シリアル化する方法を決定できます。このバージョン管理手法は、コードのいくつかのバージョンが残っているシリアル化されたデータを格納する場合に役立ちます。
しかし、シリアル化されたデータをそのような長い期間保存することはあまり一般的ではありません。シリアル化メカニズムを使用してデータを一時的にキャッシュなどに一時的に書き込むか、コードベースの関連する部分の同じバージョンを持つ別のプログラムにネットワーク経由で送信するのがはるかに一般的です。
この場合、下位互換性を維持する必要はありません。実際に通信しているコードベースが、関連するクラスの同じバージョンを持っていることを確認することだけに関心があります。このようなチェックを容易にするために、serialVersionUID
以前と同じように維持し、クラスを変更するときにチェックを更新することを忘れないでください。
フィールドを更新するのを忘れた場合、異なる構造を持つが同じを持つ、クラスの2つの異なるバージョンになる可能性がありますserialVersionUID
。これが発生した場合、デフォルトのメカニズム(in.defaultReadObject()
)は違いを検出せず、互換性のないデータのシリアル化解除を試みます。これで、不可解なランタイムエラーまたはサイレントエラー(nullフィールド)が発生する可能性があります。これらのタイプのエラーを見つけるのは難しいかもしれません。
したがって、このユースケースを支援するために、JavaプラットフォームではserialVersionUID
手動で設定しないという選択肢があります。代わりに、クラス構造のハッシュがコンパイル時に生成され、IDとして使用されます。このメカニズムにより、同じIDで異なるクラス構造が存在することがなくなり、上記のトレースが困難なランタイムシリアル化の失敗が発生しなくなります。
しかし、自動生成されたID戦略には裏側があります。つまり、同じクラスに対して生成されたIDはコンパイラ間で異なる可能性があります(上記のJon Skeetが言及)。したがって、異なるコンパイラでコンパイルされたコード間でシリアル化されたデータを通信する場合は、とにかく手動でIDを維持することをお勧めします。
また、前述の最初の使用例のようにデータと下位互換性がある場合は、IDを自分で維持することもできます。これは、読み取り可能なIDを取得し、変更のタイミングと方法をより詳細に制御するためです。
serialVersionUIDとは何ですか?なぜそれを使用する必要があるのですか?
SerialVersionUID
は各クラスの一意の識別子です。JVM
これを使用してクラスのバージョンを比較し、直列化中に同じクラスが使用されたことを確認して、直列化解除中に同じクラスがロードされるようにします。
1つを指定するとより多くの制御が得られますが、JVMは指定しなければ制御を生成します。生成される値は、コンパイラによって異なる場合があります。さらに、古いシリアル化されたオブジェクト[ backward incompatibility
]の逆シリアル化を何らかの理由で禁止したい場合もあります。この場合は、serialVersionUIDを変更する必要があります。
say のjavadocSerializable
:
デフォルトのserialVersionUIDの計算は、コンパイラーの実装によって異なるクラスの詳細に非常に敏感であるため、
InvalidClassException
逆シリアル化中に予期しないが発生する可能性があります。
したがって、serialVersionUIDを宣言する必要があります。これにより、制御が強化されます。
serialVersionUID
理由を知らずに盲目的に含めることにより、意図しない結果を引き起こす可能性があることです。トムアンダーソンのMetroidFan2002の回答に関するコメントは、次のように述べています。互換性のない変更からユーザーを保護するためのserialVersionUIDメカニズム。」
serialVersionUID
「各クラスの一意の識別子」ではありません。完全修飾クラス名はそれです。これは、あるバージョンインジケータ。
元の質問では、「なぜそれが重要なのか」と「これSerial Version ID
が役立つ例」が求められました。さて、私はそれを見つけました。
Car
クラスを作成し、インスタンス化して、オブジェクトストリームに書き出すとします。平坦化された自動車オブジェクトは、しばらくの間ファイルシステムに存在します。一方、Car
新しいフィールドを追加してクラスを変更した場合。後で、平坦化されたCar
オブジェクトを読み取ろうとする(つまり、逆シリアル化する)と、java.io.InvalidClassException
すべてのクラスに自動的に一意の識別子が与えられるためれます。この例外は、クラスの識別子がフラット化されたオブジェクトの識別子と等しくない場合にスローされます。本当に考えれば、新しいフィールドが追加されたため、例外がスローされます。明示的なserialVersionUIDを宣言してバージョン管理を自分で制御することで、この例外がスローされるのを回避できます。明示的に宣言することで、パフォーマンス上の小さな利点もあります。serialVersionUID
(計算する必要がないため)。そのため、次に示すように、作成した直後に独自のserialVersionUIDをSerializableクラスに追加することをお勧めします。
public class Car {
static final long serialVersionUID = 1L; //assign a long value
}
1
。
最初に、シリアル化とは何かを説明する必要があります。
シリアル化により、オブジェクトをストリームに変換して、そのオブジェクトをネットワーク経由で送信したり、ファイルに保存したり、DBに保存して文字を使用したりできます。
シリアライゼーションにはいくつかのルールがあります。
オブジェクトが直列化可能であるのは、そのクラスまたはそのスーパークラスがSerializableインターフェースを実装している場合のみです
スーパークラスがそうでなくても、オブジェクトは直列化可能です(それ自体がSerializableインターフェースを実装します)。ただし、Serializableインターフェースを実装しない、直列化可能クラスの階層の最初のスーパークラスには、引数なしのコンストラクターが必要です。これに違反した場合、readObject()は実行時にjava.io.InvalidClassExceptionを生成します
すべてのプリミティブ型はシリアライズ可能です。
一時フィールド(transient修飾子付き)はシリアライズされません(つまり、保存または復元されません)。Serializableを実装するクラスは、シリアル化をサポートしないクラス(ファイルストリームなど)の一時フィールドをマークする必要があります。
静的フィールド(静的修飾子付き)はシリアライズされません。
ときにObject
シリアライズされ、Javaランタイムは、別名シリアルバージョン番号を関連付けますserialVersionID
。
serialVersionIDが必要な場合:
シリアル化に関して送信側と受信側に互換性があることを確認するための逆シリアル化中。レシーバーが別のクラスをロードした場合、serialVersionID
逆シリアル化はで終了しInvalidClassCastException
ます。
直列化可能クラスは、static、final、およびlong型である必要があるserialVersionUID
という名前のフィールドを宣言することにより、独自のクラスを明示的に宣言serialVersionUID
できます。
例を挙げて試してみましょう。
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;
public String getEmpName() {
return name;
}
public void setEmpName(String empname) {
this.empname = empname;
}
public byte getEmpAge() {
return empage;
}
public void setEmpAge(byte empage) {
this.empage = empage;
}
public String whoIsThis() {
StringBuffer employee = new StringBuffer();
employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old "));
return employee.toString();
}
}
シリアル化オブジェクトを作成
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
Employee employee = new Employee();
employee.setEmpName("Jagdish");
employee.setEmpAge((byte) 30);
FileOutputStream fout = new
FileOutputStream("/users/Jagdish.vala/employee.obj");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(employee);
oos.close();
System.out.println("Process complete");
}
}
オブジェクトを逆シリアル化する
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException,
IOException {
Employee employee = new Employee();
FileInputStream fin = new
FileInputStream("/users/Jagdish.vala/employee.obj");
ObjectInputStream ois = new ObjectInputStream(fin);
employee = (Employee) ois.readObject();
ois.close();
System.out.println(employee.whoIsThis());
}
}
注:ここで、EmployeeクラスのserialVersionUIDを変更して保存します。
private static final long serialVersionUID = 4L;
そして、Readerクラスを実行します。Writerクラスを実行しないと、例外が発生します。
Exception in thread "main" java.io.InvalidClassException:
com.jagdish.vala.java.serialVersion.Employee; local class incompatible:
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
オブジェクトをバイト配列にシリアル化して送信/保存する必要がない場合は、心配する必要はありません。その場合、オブジェクトのデシリアライザがクラスローダーが持つオブジェクトのバージョンと一致させるため、serialVersionUIDを考慮する必要があります。詳細については、Java言語仕様を参照してください。
クラスでこの警告が表示された場合、シリアル化について考えたことはなく、自分で宣言しなかったことを implements Serializable
で場合は、多くの場合、Serializableを実装するスーパークラスから継承したためです。多くの場合、継承を使用するよりも、そのようなオブジェクトに委任する方が良いでしょう。
したがって、代わりに
public class MyExample extends ArrayList<String> {
public MyExample() {
super();
}
...
}
行う
public class MyExample {
private List<String> myList;
public MyExample() {
this.myList = new ArrayList<String>();
}
...
}
および関連するメソッドmyList.foo()
でthis.foo()
(またはsuper.foo()
)の代わりに呼び出します。(これはすべての場合に当てはまるわけではありませんが、それでもかなり頻繁です。)
本当にこれに委任する必要があるだけのときに、JFrameなどを拡張している人をよく目にします。(JFrameには何百ものメソッドがあるため、これはIDEでのオートコンプリートにも役立ちます。クラスでカスタムメソッドを呼び出すときに必要ないメソッドです。)
警告(またはserialVersionUID)が避けられない1つのケースは、AbstractActionから拡張する場合で、通常は匿名クラスで、actionPerformedメソッドを追加するだけです。この場合は警告は出ないはずです(通常、クラスの異なるバージョン間でこのような匿名クラスを信頼性の高い方法でシリアル化および逆シリアル化することはできないため)が、コンパイラがこれをどのように認識できるかはわかりません。
__AUTOLOAD
私にはわかりません。
フィールドserialVersionUIDの重要性を理解するには、Serialization / Deserializationの仕組みを理解する必要があります。
Serializableクラスオブジェクトがシリアル化されると、Javaランタイムはシリアルバージョン番号(serialVersionUIDと呼ばれる)をこのシリアル化されたオブジェクトに関連付けます。このシリアル化されたオブジェクトを逆シリアル化するときに、Javaランタイムは、シリアル化されたオブジェクトのserialVersionUIDをクラスのserialVersionUIDと一致させます。両方が等しい場合は、逆シリアル化の次のプロセスのみが続行され、そうでない場合はInvalidClassExceptionがスローされます。
したがって、シリアライゼーション/デシリアライゼーションプロセスを成功させるには、シリアライズされたオブジェクトのserialVersionUIDがクラスのserialVersionUIDと同等である必要があると結論付けます。プログラマーがプログラムでserialVersionUID値を明示的に指定した場合、同じ値がシリアル化されたオブジェクトとクラスに関連付けられます。シリアル化と逆シリアル化のプラットフォームに関係なく(例:シリアル化は、WindowsのようなプラットフォームでsunまたはMS JVMとデシリアライゼーションは、Zing JVMを使用する別のプラットフォームLinuxにある場合があります)。
ただし、プログラマがserialVersionUIDを指定していない場合、オブジェクトのSerialization \ DeSerializationを実行している間、Javaランタイムは独自のアルゴリズムを使用してそれを計算します。このserialVersionUID計算アルゴリズムは、JREによって異なります。オブジェクトがシリアル化される環境が1つのJRE(例:SUN JVM)を使用していて、逆シリアル化が発生する環境がLinux Jvm(zing)を使用している可能性もあります。このような場合、シリアル化されたオブジェクトに関連付けられたserialVersionUIDは、逆シリアル化環境で計算されたクラスのserialVersionUIDとは異なります。逆シリアル化は成功しません。そのため、このような状況/問題を回避するには、プログラマは常にSerializableクラスのserialVersionUIDを指定する必要があります。
欠落しているserialVersionUIDが問題を引き起こす可能性がある例については、次のとおりです。
モジュールを使用するWebモジュールで構成されるこのJava EEアプリケーションに取り組んでいEJB
ます。WebモジュールはEJB
モジュールをリモートで呼び出し、POJO
実装Serializable
するを引数として渡します。
このPOJO's
クラスは、EJB jar内およびWebモジュールのWEB-INF / lib内の独自のjar内にパッケージ化されていました。それらは実際には同じクラスですが、EJBモジュールをパッケージ化するときに、このPOJOのjarをアンパックして、EJBモジュールと一緒にパックします。
の呼び出しEJB
が失敗したのは、次の例外が宣言されていないためですserialVersionUID
。
Caused by: java.io.IOException: Mismatched serialization UIDs : Source
(Rep.
IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
= 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
= 6227F23FA74A9A52
私は通常serialVersionUID
、1つのコンテキストで使用します。JavaVMのコンテキストから離れることがわかっている場合。
私が使用したときに私はこれを知っているだろうObjectInputStream
し、ObjectOutputStream
自分のアプリケーションのためか、私が知っていれば、ライブラリ/フレームワークIの使用は、それを使用します。serialVersionIDは、さまざまなバージョンまたはベンダーのさまざまなJava VMが正しく相互運用することを保証します。たとえばHttpSession
、VMの外部に保存および取得された場合、アプリケーションサーバーの再起動およびアップグレード中にもセッションデータが残る可能性があります。
他のすべてのケースでは、私は使用します
@SuppressWarnings("serial")
ほとんどの場合、デフォルトserialVersionUID
で十分です。これにはException
、HttpServlet
。
CheckStyleが、Serializableを実装するクラスのserialVersionUIDが適切な値を持っていること、つまり、シリアルバージョンIDジェネレーターが生成するものと一致することを確認できると便利です。たとえば、多数のシリアル化可能なDTOを含むプロジェクトがある場合、既存のserialVersionUIDを削除して再生成することを思い出すのは面倒で、現在これを確認する唯一の方法(私が知っている)は、クラスごとに再生成して比較することです。古いもの。これは非常に痛いです。
serialver
生成されるものと一致させる必要はありません。-1
serialVersionUID
1 に設定します。クラスの新しいバージョンに互換性がなくても、古いデータを処理できる必要がある場合は、バージョン番号を増やし、特別なコードを追加します古いフォーマットを扱います。serialVersionUID
乱数(役に立たない)であったか、クラスが10を超える異なるバージョンを処理する必要があるため、1桁を超える数字が表示されるたびに泣きます。
SerialVersionUIDは、オブジェクトのバージョン管理に使用されます。クラスファイルでserialVersionUIDを指定することもできます。serialVersionUIDを指定しないことの結果は、クラスのフィールドを追加または変更すると、新しいクラスと古いシリアル化オブジェクトに対して生成されたserialVersionUIDが異なるため、既にシリアル化されたクラスが回復できないことです。Javaシリアル化プロセスは、シリアル化されたオブジェクトの状態を回復するために正しいserialVersionUIDに依存し、serialVersionUIDが一致しない場合はjava.io.InvalidClassExceptionをスローします
詳しくはこちら:http : //javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ
なぜJavaのSerialVersionUID
内部Serializable
クラスを使用するのですか?
のserialization
実行中、Javaランタイムはクラスのバージョン番号を作成して、後で逆シリアル化できるようにします。このバージョン番号はSerialVersionUID
、Javaと同じです。
SerialVersionUID
シリアル化されたデータのバージョン管理に使用されます。SerialVersionUID
シリアル化されたインスタンスと一致する場合にのみ、クラスを逆シリアル化できます。SerialVersionUID
クラスで宣言しない場合、Javaランタイムが生成しますが、お勧めしません。デフォルトのメカニズムを回避するためにSerialVersionUID
、private static final long
変数として宣言することをお勧めします。
Serializable
マーカーインターフェイスを実装してクラスを宣言すると、インターフェイスjava.io.Serializable
を使用してプロセスをカスタマイズしていなければ、Javaランタイムはデフォルトのシリアル化メカニズムを使用して、そのクラスのインスタンスをディスクに永続化しExternalizable
ます。
古いクラスとの互換性を維持しながら、最初にserialVersionUIDが設定されていない膨大な数のクラスを修正したい場合、IntelliJ Idea、Eclipseなどのツールは乱数を生成し、ファイルの束で機能しないため不十分です一度に。次のbashスクリプト(Windowsユーザーには申し訳ありませんが、Macを購入するかLinuxに変換することを検討してください)を考えて、serialVersionUIDの問題を簡単に修正します。
base_dir=$(pwd)
src_dir=$base_dir/src/main/java
ic_api_cp=$base_dir/target/classes
while read f
do
clazz=${f//\//.}
clazz=${clazz/%.java/}
seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
perl -ni.bak -e "print $_; printf qq{%s\n}, q{ private $seruidstr} if /public class/" $src_dir/$f
done
このスクリプトを保存すると、〜/ binにadd_serialVersionUID.shと言います。次に、MavenまたはGradleプロジェクトのルートディレクトリで次のように実行します。
add_serialVersionUID.sh < myJavaToAmend.lst
この.lstには、次の形式でserialVersionUIDを追加するためのJavaファイルのリストが含まれています。
com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java
このスクリプトは、内部でJDK serialVerツールを使用します。したがって、$ JAVA_HOME / binがPATHに含まれていることを確認してください。
この質問は、Joshua Blochによる「Effective Java」に非常によく文書化されています。とても良い本で必読です。以下にいくつかの理由を概説します。
シリアライゼーションランタイムには、シリアル化可能なクラスごとにシリアルバージョンと呼ばれる番号が表示されます。この番号は、serialVersionUIDと呼ばれます。これで、この数値の背後にある数学があり、クラスで定義されているフィールド/メソッドに基づいて計算されます。同じクラスの場合、毎回同じバージョンが生成されます。この番号は、逆シリアル化中に、シリアル化されたオブジェクトの送信者と受信者が、そのオブジェクトに対して、シリアル化に関して互換性のあるクラスを読み込んだことを確認するために使用されます。レシーバーが、対応するセンダーのクラスとは異なるserialVersionUIDを持つオブジェクトのクラスをロードした場合、デシリアライズはInvalidClassExceptionになります。
クラスがシリアル化可能である場合、静的で、最終的な、long型の「serialVersionUID」という名前のフィールドを宣言することにより、独自のserialVersionUIDを明示的に宣言することもできます。EclipseなどのほとんどのIDEは、その長い文字列を生成するのに役立ちます。
オブジェクトがシリアル化されるたびに、オブジェクトにはオブジェクトのクラスのバージョンID番号がスタンプされます。このIDはserialVersionUIDと呼ばれ、クラス構造に関する情報に基づいて計算されます。Employeeクラスを作成し、バージョンIDが#333(JVMによって割り当てられている)であるとします。次に、そのクラスのオブジェクト(Suppose Employeeオブジェクト)をシリアル化すると、JVMはそれにUIDを#333として割り当てます。
状況を検討してください。将来、クラスを編集または変更する必要があり、その場合、クラスを変更すると、JVMが新しいUIDを割り当てます(仮定#444)。これで、従業員オブジェクトを逆シリアル化しようとすると、JVMはシリアル化されたオブジェクト(従業員オブジェクト)のバージョンID(#333)をクラスのバージョンID#444と比較します(変更されたため)。比較すると、JVMは両方のバージョンのUIDが異なるため、逆シリアル化は失敗します。したがって、各クラスのserialVersionIDがプログラマー自身によって定義されている場合。クラスが将来進化しても同じであり、したがって、クラスが変更されても、JVMは常にそのクラスがシリアル化されたオブジェクトと互換性があることを検出します。詳細については、HEAD FIRST JAVAの第14章を参照してください。
serialVersionUID
送信されます。すべてのオブジェクトと一緒に送信されるわけではありません。
簡単な説明:
データをシリアル化していますか?
シリアライゼーションとは、基本的にクラスデータをファイル/ストリームなどに書き込むことです。逆シリアル化とは、そのデータをクラスに読み込むことです。
生産に入るつもりですか?
重要でないデータや偽のデータを使用して何かをテストしているだけの場合は、心配しないでください(直接シリアル化をテストしている場合を除く)。
これは最初のバージョンですか?
その場合は、を設定しserialVersionUID=1L
ます。
これは2番目、3番目などの製品バージョンですか?
今、あなたはについて心配する必要がありserialVersionUID
、それを詳細に調べる必要があります。
基本的に、書き込み/読み取りが必要なクラスを更新するときにバージョンを正しく更新しないと、古いデータを読み取ろうとするとエラーが発生します。
'serialVersionUID'は、逆シリアル化プロセス中にクラスを一意に識別するために使用される64ビットの数値です。オブジェクトをシリアル化すると、クラスのserialVersionUIDもファイルに書き込まれます。このオブジェクトを逆シリアル化するたびに、Javaランタイムはシリアル化されたデータからこのserialVersionUID値を抽出し、クラスに関連付けられた同じ値を比較します。両方が一致しない場合、「java.io.InvalidClassException」がスローされます。
シリアル化可能なクラスがserialVersionUIDを明示的に宣言していない場合、シリアル化ランタイムは、フィールド、メソッドなどのクラスのさまざまな側面に基づいて、そのクラスのserialVersionUID値を計算します。デモアプリケーションについては、このリンクを参照してください。
簡単に言えば、このフィールドは、シリアル化されたデータを正しく逆シリアル化できるかどうかを確認するために使用されます。シリアル化と非シリアル化は、多くの場合、プログラムの異なるコピーによって行われます。たとえば、サーバーはオブジェクトを文字列に変換し、クライアントは受信した文字列をオブジェクトに変換します。このフィールドは、両方がこのオブジェクトが何であるかについて同じ考えで動作することを示します。このフィールドは次の場合に役立ちます。
あなたはあなたのプログラムの多くの異なるコピーを異なる場所に持っています(1つのサーバーと100のクライアントのような)。オブジェクトを変更し、バージョン番号を変更し、このクライアントの1つを更新するのを忘れた場合は、彼が逆シリアル化できないことを認識します
データを何らかのファイルに保存し、後でオブジェクトを変更したプログラムの更新バージョンでそれを開こうとした場合-バージョンを正しく維持すると、このファイルに互換性がないことがわかります
それはいつ重要ですか?
最も明白です-オブジェクトにいくつかのフィールドを追加した場合、古いバージョンではオブジェクト構造にこれらのフィールドがないため、それらを使用できません。
あまり明確でない-オブジェクトを逆シリアル化すると、文字列に存在しないフィールドはNULLとして保持されます。オブジェクトからフィールドを削除した場合、古いバージョンはこのフィールドを常にNULLのままにするため、古いバージョンがこのフィールドのデータに依存している場合、誤動作につながる可能性があります(とにかく、楽しみのためだけでなく、何かのために作成したものです:-))。
自明ではない-ある分野の意味に入れるアイデアを変更することがあります。たとえば、12歳のときは「自転車」の下の「自転車」を意味しますが、18歳のときは「オートバイ」を意味します-友達が「街を自転車で走る」ようにあなたを招待し、あなただけが1人になります自転車に乗ったら、分野を超えて同じ意味を保つことがどれほど重要であるか理解できます:-)
最初にあなたの質問に答えるために、クラスでSerialVersionUIDを宣言しない場合、Javaランタイムはそれを生成しますが、そのプロセスは、フィールドの数、フィールドのタイプ、フィールドのアクセス修飾子、実装されたインターフェイスを含む多くのクラスメタデータの影響を受けますクラスごとなど。したがって、自分で宣言することをお勧めします。Eclipseは同じことを警告しています。
シリアライゼーション:状態(オブジェクトの変数のデータ)が非常に重要である重要なオブジェクトを使用することがよくあります。そのため、オブジェクトの状態を他のオブジェクトに送信する場合に、電源/システムの障害(または)ネットワークの障害が原因でデータを失うリスクはありません。機械。この問題の解決策は「永続性」と呼ばれ、データを永続化(保持/保存)することを意味します。シリアル化は、(データをディスク/メモリに保存することにより)永続性を実現する他の多くの方法の1つです。オブジェクトの状態を保存するときは、オブジェクトを正しく読み取ることができるように、オブジェクトのIDを作成することが重要です(逆シリアル化)。この一意のIDは、ID is SerialVersionUIDです。
SerialVersionUIDとは何ですか?回答:-HQとODCの2人がそれぞれシリアライゼーションとデシリアライゼーションをそれぞれ実行するとします。この場合、ODCにいる受信者が認証された人物であることを認証するために、JVMはSerialVersionUIDと呼ばれる一意のIDを作成します。
これはシナリオに基づいた素晴らしい説明です、
なぜSerialVersionUIDなのか?
シリアル化:直列化の時点では、すべてのオブジェクトの送信側でJVMが一意識別子を保存します。JVMは、送信側システムに存在する対応する.classファイルに基づいてその一意のIDを生成する責任があります。
デシリアライズ:デシリアライゼーションの際に、受信側JVMはまた、受信機システム内に存在する対応する.classファイルに基づいて一意のIDを作成するローカルクラス固有ID、すなわちJVMを持つオブジェクトに関連付けられた一意のIDを比較します。両方の一意のIDが一致した場合、逆シリアル化のみが実行されます。そうでない場合は、InvalidClassExceptionと言うランタイム例外が発生します。この一意の識別子はSerialVersionUIDにすぎません