質問

Eclipseは、 serialVersionUID がない場合に警告を発行します。

  

シリアル化可能なクラスFooは静的なfinalを宣言しません   long型のserialVersionUIDフィールド

serialVersionUID とは何ですか。なぜ重要なのですか? serialVersionUID がないと問題が発生する例を示してください。

役に立ちましたか?

解決

java.io.Serializable は、おそらくあなたが得るのと同じくらい良い説明です:

  

シリアル化ランタイムは、各シリアル化可能クラスに serialVersionUID と呼ばれるバージョン番号を関連付けます。これは、シリアル化されたオブジェクトの送信者と受信者がそのオブジェクトのクラスをロードしたことを確認するために逆シリアル化中に使用されますシリアル化に関して互換性があります。受信者が、対応する送信者のクラスとは異なる serialVersionUID を持つオブジェクトのクラスをロードした場合、逆シリアル化の結果は    InvalidClassException 。シリアル化可能なクラスは、静的で、finalで、タイプが long でなければならない serialVersionUID という名前のフィールドを宣言することにより、独自の serialVersionUID を明示的に宣言できます。

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
     

シリアライズ可能クラスが serialVersionUID を明示的に宣言しない場合、シリアライゼーションランタイムは、クラスのさまざまな側面に基づいて、そのクラスのデフォルトの serialVersionUID 値を計算します。 Java(TM)Object Serialization Specificationで説明されています。ただし、デフォルトの serialVersionUID 計算はさまざまなクラスの詳細に非常に敏感であるため、すべてのシリアライズ可能なクラスが serialVersionUID 値を明示的に宣言することを強くお勧めしますコンパイラの実装に依存するため、逆シリアル化中に予期しない InvalidClassExceptions が発生する可能性があります。したがって、異なるJavaコンパイラの実装間で一貫した serialVersionUID 値を保証するには、シリアライズ可能なクラスが明示的な serialVersionUID 値を宣言する必要があります。また、明示的な serialVersionUID 宣言は、可能な場合はprivate修飾子を使用することを強くお勧めします。このような宣言は、すぐに宣言するクラスの serialVersionUID フィールドにのみ適用されるため、継承されたメンバーとしては役立ちません/ p>

他のヒント

実装のためにシリアル化する必要があるという理由だけでシリアル化する場合(たとえば、 HTTPSession でシリアル化するかどうかを気にする人は...それが保存されているかどうかに関係なく、おそらくフォームオブジェクトを deserializing する必要はありません)、これは無視できます。

実際にシリアル化を使用している場合は、シリアル化を直接使用してオブジェクトを保存および取得する予定がある場合にのみ問題になります。 serialVersionUID はクラスのバージョンを表します。クラスの現在のバージョンが以前のバージョンと後方互換性がない場合は、それをインクリメントする必要があります。

ほとんどの場合、シリアル化を直接使用することはおそらくないでしょう。この場合、クイック修正オプションをクリックしてデフォルトの SerialVersionUID を生成しますが、心配する必要はありません。

この機会を逃してジョシュブロッホの本を差し込むことはできません効果的なJava (第2版)。第11章は、Javaシリアル化に関する不可欠なリソースです。

Joshによると、自動生成されたUIDは、クラス名、実装されたインターフェイス、すべてのパブリックおよび保護されたメンバーに基づいて生成されます。これらのいずれかを変更すると、 serialVersionUID が変更されます。したがって、クラスの複数のバージョンが(プロセス間で、または後でストレージから取得されて)シリアル化されないことが確実な場合にのみ、それらをいじる必要はありません。

今のところそれらを無視し、後で何らかの方法でクラスを変更する必要があるが、クラスの古いバージョンとの互換性を維持する必要がある場合、JDKツール serialver を使用して生成できます old クラスの serialVersionUID に追加し、新しいクラスに明示的に設定します。 (変更に応じて、 writeObject および readObject メソッドを追加してカスタムシリアル化を実装する必要がある場合があります。 Serializable javadocまたは前述の第11章を参照してください。)

これらのserialVersionUID警告を無視するようにEclipseに指示できます。

  

ウィンドウ>設定> Java>コンパイラ>エラー/警告>潜在的なプログラミングの問題

知らなかった場合、このセクションで有効にできる他の多くの警告があります(またはエラーとして報告されることもあります)、多くは非常に便利です:

  • プログラミングの潜在的な問題:偶発的なブール値の割り当ての可能性
  • 潜在的なプログラミングの問題:ヌルポインターアクセス
  • 不要なコード:ローカル変数は読み取られません
  • 不要なコード:冗長なnullチェック
  • 不要なコード:不要なキャストまたは「instanceof」

その他多数。

serialVersionUID は、シリアル化されたデータのバージョン管理を容易にします。その値は、シリアライズ時にデータとともに保存されます。逆シリアル化する場合、同じバージョンがチェックされ、シリアル化されたデータが現在のコードとどのように一致するかが確認されます。

データをバージョン管理する場合、通常は0の serialVersionUID で開始し、クラスに構造的な変更を加えて、シリアル化されたデータを変更します(非一時フィールドの追加または削除) )。

組み込みの逆シリアル化メカニズム( in.defaultReadObject())は、古いバージョンのデータからの逆シリアル化を拒否します。ただし、必要に応じて、独自の readObject()-古いデータを読み戻すことができる関数。このカスタムコードは、 serialVersionUID をチェックして、データのバージョンを確認し、データを逆シリアル化する方法を決定できます。このバージョニング手法は、コードのいくつかのバージョンに耐えるシリアル化されたデータを保存する場合に役立ちます。

ただし、このような長い期間にわたってシリアル化されたデータを保存することはあまり一般的ではありません。シリアル化メカニズムを使用して、たとえばキャッシュに一時的にデータを書き込んだり、コードベースの関連部分の同じバージョンを持つ別のプログラムにネットワーク経由で送信したりすることがはるかに一般的です。

この場合、後方互換性を維持することに関心はありません。あなたは、通信しているコードベースが実際に同じクラスの関連クラスを持っていることを確認することにのみ関心があります。そのようなチェックを容易にするために、前と同じように serialVersionUID を維持し、クラスを変更するときに更新することを忘れないでください。

フィールドの更新を忘れると、構造が異なるが同じ serialVersionUID を持つクラスの2つの異なるバージョンになる可能性があります。この場合、デフォルトのメカニズム( in.defaultReadObject())は違いを検出せず、互換性のないデータの逆シリアル化を試みます。これで、不可解なランタイムエラーまたはサイレントエラー(nullフィールド)が発生する可能性があります。これらのタイプのエラーは見つけるのが難しいかもしれません。

このユースケースを支援するために、Javaプラットフォームでは、 serialVersionUID を手動で設定しないという選択肢が提供されます。代わりに、クラス構造のハッシュがコンパイル時に生成され、IDとして使用されます。このメカニズムにより、同じIDを持つ異なるクラス構造が存在しないことが保証されるため、上記のトレースが困難なランタイムシリアル化エラーは発生しません。

しかし、自動生成されたid戦略には裏側があります。つまり、同じクラスに対して生成されたIDは、コンパイラ間で異なる可能性があります(上記のJon Skeetによると)。したがって、異なるコンパイラでコンパイルされたコード間でシリアル化されたデータを通信する場合は、いずれにしても手動でIDを維持することをお勧めします。

また、前述の最初のユースケースのようにデータとの下位互換性がある場合は、おそらく自分でIDを維持することもできます。これは、読み取り可能なIDを取得し、いつどのように変更するかをより詳細に制御するためです。

  

serialVersionUID とは何ですか。なぜ使用する必要があるのですか?

SerialVersionUID は各クラスの一意の識別子です。 JVM はこれを使用してクラスのバージョンを比較し、シリアル化中に同じクラスが使用されていることを確認します。

1つを指定するとより多くの制御が与えられますが、指定しない場合はJVMが1つを生成します。生成される値は、コンパイラによって異なる場合があります。さらに、何らかの理由で古いシリアル化されたオブジェクトの逆シリアル化を禁止したい場合があります[ backward incompatibility ]。この場合、serialVersionUIDを変更するだけです。

Serializableのjavadocs 発言

  

デフォルトのserialVersionUID計算はクラスに非常に敏感です   コンパイラーの実装によって異なる可能性のある詳細   したがって、予期しない InvalidClassException が発生します   逆シリアル化。

したがって、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
}

オブジェクトをバイト配列にシリアライズして送信/保存する必要がない場合は、心配する必要はありません。その場合、オブジェクトのデシリアライザーがクラスローダーのオブジェクトのバージョンと一致させるため、serialVersionUIDを考慮する必要があります。詳細については、Java言語仕様をご覧ください。

シリアル化について考えたことがなく、 Serializable 実装を宣言しなかったクラスでこの警告が表示された場合、多くの場合、スーパークラスから継承しているためです。シリアライズ可能。多くの場合、継承を使用するよりも、そのようなオブジェクトに委任した方が良いでしょう。

したがって、

の代わりに
public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

する

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

および関連するメソッドで this.foo()(または super.foo())の代わりに myList.foo()を呼び出します。 (これはすべての場合に当てはまるわけではありませんが、それでもかなり頻繁に起こります。)

JFrameなどを拡張する人がよく見かけますが、実際にこれに委任するだけでよい場合があります。 (JFrameには何百ものメソッドがあるため、IDEでの自動補完にも役立ちます。クラスでカスタムメソッドを呼び出す場合は必要ありません。)

警告(またはserialVersionUID)が避けられない場合の1つは、通常は匿名クラスでAbstractActionから拡張し、actionPerformed-methodのみを追加する場合です。この場合、警告はないはずだと思います(通常、クラスの異なるバージョン間でこのような匿名クラスを確実にシリアル化および非シリアル化することはできないため)が、コンパイラーがこれをどのように認識できるかわかりません。

serialVersionUIDフィールドの重要性を理解するには、Serialization / Deserializationの仕組みを理解する必要があります。

Serializableクラスオブジェクトがシリアル化されると、Java Runtimeはシリアルバージョン番号(serialVersionUIDと呼ばれる)をこのシリアル化されたオブジェクトに関連付けます。このシリアル化されたオブジェクトを逆シリアル化すると、Java Runtimeは、シリアル化されたオブジェクトの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を指定する必要があります。

まず、シリアル化について説明する必要があります。
シリアル化により、オブジェクトをネットワークに送信するためにオブジェクトをストリームに変換したり、ファイルに保存したり、レターで使用するためにDBに保存したりできます。

シリアル化にはいくつかのルールがあります

  • オブジェクトは、そのクラスまたはスーパークラスがSerializableインターフェイスを実装している場合にのみシリアル化可能です

  • オブジェクトは、スーパークラスがそうでない場合でも直列化可能です(それ自体がSerializableインターフェースを実装します)。ただし、Serializableインターフェイスを実装しない、直列化可能クラスの階層内の最初のスーパークラスには、引数なしのコンストラクタが必要です。これに違反すると、readObject()は実行時にjava.io.InvalidClassExceptionを生成します

  • すべてのプリミティブ型はシリアル化可能です。

  • 一時フィールド(一時修飾子付き)はシリアル化されません(つまり、保存または復元されません)。 Serializableを実装するクラスは、シリアル化をサポートしないクラス(ファイルストリームなど)の一時フィールドをマークする必要があります。

  • 静的フィールド(静的修飾子付き)はシリアル化されません。

オブジェクトがシリアル化される場合JAVAランタイムserialVersionIDと呼ばれるシリアルバージョン番号を関連付けます。

serialVersionIDが必要な場所: 逆シリアル化中に、送信側と受信側がシリアル化に関して互換性があることを確認します。受信側が異なるserialVersionIDでクラスをロードした場合、逆シリアル化は終了します InvalidClassCastException で。
 シリアル化可能なクラスは、&#8220; serialVersionUID&#8221;という名前のフィールドを宣言することにより、独自のserialVersionUIDを明示的に宣言できます。静的で、finalで、long型である必要があります。

例を使ってこれを試してみましょう。

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)

気にしないでください、デフォルトの計算は本当に良く、99,9999%のケースで十分です。また、問題が発生した場合は、既に述べたように、必要が生じたときにUIDを導入できます(これは非常にまれです)。

serialVersionUIDが欠落していると問題が発生する可能性がある例の場合:

EJB モジュールを使用するWebモジュールで構成されるこのJava EEアプリケーションで作業しています。 Webモジュールは、 EJB モジュールをリモートで呼び出し、 Serializable を引数として実装する POJO を渡します。

この POJOのクラスは、EJB jar内およびWebモジュールのWEB-INF / lib内の独自のjar内にパッケージ化されました。実際には同じクラスですが、EJBモジュールをパッケージ化するとき、このPOJOのjarをアンパックしてEJBモジュールと一緒にパックします。

serialVersionUID を宣言していないため、 EJB の呼び出しは以下の例外で失敗しました:

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

通常、1つのコンテキストで serialVersionUID を使用します。JavaVMのコンテキストを離れることがわかっている場合。

アプリケーションで ObjectInputStream および ObjectOutputStream を使用するとき、または使用するライブラリ/フレームワークがわかっている場合、これを知っています。 serialVersionIDは、さまざまなバージョンまたはベンダーのさまざまなJava VMが正しく相互運用することを保証します。たとえば、 HttpSession のようにVMの外部に格納および取得された場合、アプリケーションの再起動およびアップグレード中でもセッションデータを保持できますサーバー。

他のすべてのケースでは、

を使用します
@SuppressWarnings("serial")

ほとんどの場合、デフォルトの serialVersionUID で十分です。これには、 Exception HttpServlet が含まれます。

フィールドデータは、クラスに格納されている情報を表します。 クラスは Serializable インターフェースを実装し、 そのため、 serialVersionUID フィールドを宣言するためにEclipseが自動的に提供されます。そこに設定されている値1から始めましょう。

その警告を表示したくない場合は、これを使用してください:

@SuppressWarnings("serial")

SerialVersionUIDは、オブジェクトのバージョン管理に使用されます。クラスファイルでserialVersionUIDを指定することもできます。 serialVersionUIDを指定しないと、クラスのフィールドを追加または変更すると、新しいクラスと古いシリアル化されたオブジェクトに対して生成されたserialVersionUIDが異なるため、既にシリアル化されたクラスは回復できません。 Javaシリアル化プロセスは、シリアル化されたオブジェクトの状態を回復するために正しいserialVersionUIDに依存し、serialVersionUIDが一致しない場合にjava.io.InvalidClassExceptionをスローします

詳細: http://javarevisited.blogspot.com/ 2011/04 / top-10-java-serialization-interview.html#ixzz3VQxnpOPZ

CheckStyleが、Serializableを実装するクラスのserialVersionUIDに適切な値があること、つまり、シリアルバージョンIDジェネレーターが生成するものと一致することを確認できれば便利です。たとえば、多くのシリアル化可能なDTOを含むプロジェクトがある場合、既存のserialVersionUIDを削除して再生成することを覚えておくのは苦痛ですが、現在これを検証する唯一の方法(私が知っていること)は、クラスごとに再生成して比較することです古いもの。これは非常に苦痛です。

Javaの Serializable クラス内で SerialVersionUID を使用する理由

serialization 中に、Javaランタイムはクラスのバージョン番号を作成します。これにより、後でシリアル化を解除できます。このバージョン番号は、Javaでは SerialVersionUID として知られています。

SerialVersionUID は、シリアル化されたデータのバージョン管理に使用されます。シリアル化されたインスタンスと SerialVersionUID が一致する場合にのみ、クラスを逆シリアル化できます。クラスで SerialVersionUID を宣言しない場合、Javaランタイムが生成しますが、推奨されません。デフォルトのメカニズムを避けるために、 SerialVersionUID private static final long 変数として宣言することをお勧めします。

マーカーインターフェイス java.io.Serializable を実装してクラスを Serializable として宣言すると、Javaランタイムはデフォルトのシリアル化メカニズムを使用して、そのクラスのインスタンスをディスクに永続化します。 Externalizable インターフェースを使用してプロセスをカスタマイズしていない。

も使用する理由JavaのSerializableクラス内のSerialVersionUID

コード: javassist.SerialVersionUID

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 

SerialVersionUIDが設定されていない膨大な数のクラスを修正したい場合、IntelliJ Idea、Eclipseなどのツールは古いクラスとの互換性を維持しながら、乱数を生成し、一度にたくさんのファイル。次のbashスクリプト(Windowsユーザーには申し訳ありませんが、Macの購入またはLinuxへの変換を検討してください)を作成して、serialVersionUIDの問題を簡単に修正します。

add_serialVersionUID.sh < myJavaToAmend.lst

このスクリプトを保存します。たとえば、add_serialVersionUID.shを〜/ binに保存します。次に、MavenまたはGradleプロジェクトのルートディレクトリで次のように実行します。

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

この.lstには、次の形式でserialVersionUIDを追加するJavaファイルのリストが含まれています。

<*>

このスクリプトは、内部でJDK serialVerツールを使用します。したがって、$ JAVA_HOME / binがPATHにあることを確認してください。

; printf qq{%s\n}, q{ private $seruidstr} if /public class/" $src_dir/$f done

このスクリプトを保存します。たとえば、add_serialVersionUID.shを〜/ binに保存します。次に、MavenまたはGradleプロジェクトのルートディレクトリで次のように実行します。

<*>

この.lstには、次の形式でserialVersionUIDを追加するJavaファイルのリストが含まれています。

<*>

このスクリプトは、内部でJDK serialVerツールを使用します。したがって、$ JAVA_HOME / binがPATHにあることを確認してください。

この質問は、Joshua BlochによるEffective Javaで非常によく文書化されています。非常に良い本で、必読です。以下にいくつかの理由の概要を示します。

シリアル化ランタイムは、シリアル化可能なクラスごとにシリアルバージョンと呼ばれる番号を出します。この番号は、serialVersionUIDと呼ばれます。この数値の背後には数学があり、クラスで定義されているフィールド/メソッドに基づいて計算されます。同じクラスの場合、毎回同じバージョンが生成されます。この番号は、シリアル化されたオブジェクトの送信者と受信者が、シリアル化に関して互換性のあるそのオブジェクトのクラスをロードしたことを確認するために、逆シリアル化中に使用されます。受信者が、対応する送信者のクラスとは異なるserialVersionUIDを持つオブジェクトのクラスをロードした場合、逆シリアル化によりInvalidClassExceptionが発生します。

クラスがシリアル化可能である場合、&quot; serialVersionUID&quot;という名前のフィールドを宣言することにより、独自のserialVersionUIDを明示的に宣言することもできます。静的、最終、およびlong型でなければなりません。 EclipseのようなほとんどのIDEは、この長い文字列を生成するのに役立ちます。

オブジェクトがシリアル化されるたびに、オブジェクトにはオブジェクトのクラスのバージョンID番号がスタンプされます。このIDは serialVersionUID そして、クラス構造に関する情報に基づいて計算されます。従業員クラスを作成し、バージョンIDが#333(JVMによって割り当てられている)であると仮定します。今、そのクラスのオブジェクト(従業員オブジェクトをシリアル化する)で、JVMはUIDを#333として割り当てます。

状況を考慮してください-将来、クラスを編集または変更する必要があります。その場合、クラスを変更すると、JVMは新しいUIDを割り当てます(仮定#444)。 これで、従業員オブジェクトをデシリアライズしようとすると、JVMは、シリアライズされたオブジェクト(従業員オブジェクト)のバージョンID(#333)とクラスのバージョンID(#444(変更されたため))を比較します。比較すると、JVMは両方のバージョンUIDが異なるため、デシリアライゼーションは失敗します。 したがって、各クラスのserialVersionIDがプログラマー自身によって定義されている場合。将来クラスが進化しても同じになるため、クラスが変更されても、JVMは常にそのクラスがシリアル化されたオブジェクトと互換性があることを検出します。詳細については、HEAD FIRST JAVAの第14章を参照してください。

簡単な説明:

  1. データをシリアル化していますか?

    シリアル化は、基本的にクラスデータをファイル/ストリームなどに書き込むことです。逆シリアル化は、そのデータをクラスに読み戻します。

  2. 本番に移行する予定ですか?

    重要ではない/偽のデータを使って何かをテストしているだけであれば、心配する必要はありません(シリアル化を直接テストしている場合を除く)。

  3. これは最初のバージョンですか?

    その場合、 serialVersionUID = 1L を設定します。

  4. これは2番目、3番目などのprodバージョンですか?

    今、 serialVersionUID を心配する必要があり、それを詳しく調べる必要があります。

基本的に、書き込み/読み取りが必要なクラスを更新するときにバージョンを正しく更新しないと、古いデータを読み取ろうとするとエラーが発生します。

長文を簡単に言うと、このフィールドは、シリアル化されたデータを正しく逆シリアル化できるかどうかを確認するために使用されます。シリアル化と逆シリアル化は、多くの場合、プログラムの異なるコピーによって行われます。たとえば、サーバーはオブジェクトを文字列に変換し、クライアントは受信した文字列をオブジェクトに変換します。このフィールドは、両方がこのオブジェクトが何であるかについて同じ考えで動作することを示します。このフィールドは、次の場合に役立ちます。

  • さまざまな場所(1つのサーバーと100のクライアントなど)にプログラムのさまざまなコピーがあります。オブジェクトを変更し、バージョン番号を変更し、このクライアントを更新するのを忘れると、彼はデシリアライズができないことがわかります

  • データを何らかのファイルに保存した後、変更されたオブジェクトを使用してプログラムの更新バージョンでデータを開こうとしました-バージョンを正しく保つと、このファイルには互換性がないことがわかります

それはいつ重要ですか?

最も明白-オブジェクトにいくつかのフィールドを追加すると、古いバージョンではオブジェクト構造にこれらのフィールドがないため、それらを使用できません。

わかりにくい-オブジェクトをデシリアライズすると、文字列に存在しないフィールドはNULLのままになります。オブジェクトからフィールドを削除した場合、古いバージョンはこのフィールドをall-NULLのままにしておくため、古いバージョンがこのフィールドのデータに依存している場合は誤動作につながる可能性があります(とにかく、楽しみのためだけに作成したのではありません:-))

あまり明白ではない-ある分野の意味に入れた考えを変えることがあります。たとえば、12歳の場合、「自転車」という意味です。 &quot; bike&quot;の下にありますが、18歳のときは&quot; motorcycle&quot;を意味します。 -友達が「街を自転車で走る」ように誘う場合自転車に乗ったのはあなただけです。フィールド間で同じ意味を維持することがどれほど重要かを理解できます:-)

まず、クラスでSerialVersionUIDを宣言しない場合、Javaランタイムがそれを生成しますが、そのプロセスは、フィールドの数、フィールドのタイプ、フィールドのアクセス修飾子を含む多くのクラスメタデータに敏感です、クラスなどによって実装されるインターフェイス。したがって、自分で宣言することをお勧めします。Eclipseは同じことを警告しています。

シリアル化: 状態(オブジェクトの変数内のデータ)が非常に重要である重要なオブジェクトで作業することが多く、オブジェクトの状態を他のマシンに送信する場合、電源/システム障害(またはネットワーク障害)によって失われるリスクはありません。この問題の解決策の名前は&quot; Persistence&quot;です。これは単にデータの永続化(保持/保存)を意味します。シリアル化は、(データをディスク/メモリに保存することにより)永続性を実現する他の多くの方法の1つです。オブジェクトの状態を保存するときは、オブジェクトのIDを作成して、適切に読み取れるようにすることが重要です(逆シリアル化)。この一意のIDはSerialVersionUIDです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top