すべての抽象クラスを持serialVersionUID
-
23-08-2019 - |
質問
Javaの場合のクラスはSerializableを実装しが抽象的でしserialVersionUID長宣言されるようにするかどうかのサブクラスだけを必要とした。
この場合にはこのようにすべての授業の対応を直列化して、目的のタイプに使用するRMIます。
解決
のserialVersionUIDはdeseralizedオブジェクトおよびクラスの現在のバージョン間の互換性を判定するために設けられています。 <ストライキ>はそのようなものとして、それは抽象基底クラスでは、クラスの最初のバージョンで、またはこの場合、実際に必要ではありません。それはserialVersionUIDのを必要としないようにするには、/デシリアライズをシリアル化するためにその抽象クラスのインスタンスを持っていることは決してないだろう。ストライキ>
(もちろん、それは右、あなたが取り除くしたいコンパイラ警告を生成しますか?)
これは、ジェームズコメントが正しいことが判明しました。抽象ベースクラスのserialVersionUIDをのないのは、サブクラスに伝播されます。その光の中で、あなたがをは、基本クラスでのserialVersionUIDが必要なのです。
試験にコード:
import java.io.Serializable;
public abstract class Base implements Serializable {
private int x = 0;
private int y = 0;
private static final long serialVersionUID = 1L;
public String toString()
{
return "Base X: " + x + ", Base Y: " + y;
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Sub extends Base {
private int z = 0;
private static final long serialVersionUID = 1000L;
public String toString()
{
return super.toString() + ", Sub Z: " + z;
}
public static void main(String[] args)
{
Sub s1 = new Sub();
System.out.println( s1.toString() );
// Serialize the object and save it to a file
try {
FileOutputStream fout = new FileOutputStream("object.dat");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject( s1 );
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
Sub s2 = null;
// Load the file and deserialize the object
try {
FileInputStream fin = new FileInputStream("object.dat");
ObjectInputStream ois = new ObjectInputStream(fin);
s2 = (Sub) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println( s2.toString() );
}
}
これはオブジェクトを作成し、保存するために取得するには、一度サブメインを実行します。次に、基本クラスでserialVersionUIDのを変更します(それが再びそれを保存しないように、あなただけの古いものをロードする)オブジェクトを保存するメインの行をコメントアウトし、再度実行します。これは、例外が発生します。
java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
他のヒント
はい、一般的に、他のクラスのシリアルIDを必要と同じ理由 - 一つはそれのために生成されることを回避します。基本的にはSerializableを実装する任意のクラスは、(インタフェースではありません)シリアルバージョンIDを定義する必要がありますか、同じ.classファイルのコンパイルは、サーバとクライアントのJVMにないときは、デシリアライズ・エラーの危険を冒すます。
あなたは空想何かをしようとしている場合は、他のオプションがあります。私はあなたが何を意味するかわからないんだけど「それは、サブクラスの意図であります...」。カスタムシリアル化の方法(例えば。のwriteObject、readObjectメソッド)を書くつもりですか?その場合は、スーパークラスに対処するための他のオプションがあります。
を参照してください。 http://java.sun.com/javase/6 /docs/api/java/io/Serializable.htmlする
HTHトム
行方不明serialVersionID
が実際に直列化して算出されている場合、実際には、ランタイムつまりトムのリンクの外に向いていないコンパイル時に
直列化可能クラスが明示的に宣言しない場合 serialVersionUIDのは、その後、直列化ランタイムが計算されます さまざまな側面に基づいて、そのクラスのデフォルトのserialVersionUID値 クラスの...
これはさらに複雑JREの異なるバージョンを持つ事になります。
概念的には、直列化されたデータのようなものです:
subClassData(className + version + fieldNames + fieldValues)
parentClassData(className + version + fieldNames + fieldValues)
... (up to the first parent, that implements Serializable)
なんとなく直列化復元ミスマッチバージョンのクラスの階層に直列化復元に失敗します。何が格納された界面で必要はありませんの指定バージョンです。
回答: あんを提供する必要があり serialVersionUID
の抽象クラスです。していないにもかかわらず、い分野className + version
保管場合もあります。
また、次の点に注意してください:
- 場合にクラスは、フィールドは、直列化されたデータを削除分野では無視されます。
- 場合にクラス分野ですが、実はそうではありません現在直列化されたデータは、新しい分野で0に設定される/false/nullの場合は、デフォルト値は、こうなると予想されるでしょう).
- 場合分野の変化データ型の直列化復元の値に割り当に新しいタイプです。E.g.した場合は、
Object
分野String
値を変更する分野タイプString
成功するものへの変更Integer
はしないしかし、変化の分野からint
へlong
なにも仕事を割り当てることができint
価値をlong
可変となります。 - ば、サブクラスなの親クラスというのも、直列化されたデータでは無視されます(例1)です。
- 場合にサブクラスは現を拡張したクラスですが、実はそうではありませんから直列化されたデータは、親クラス分野での復元を0/false/null値(例2).
簡単な言葉:並べ替えができます分野の追加および削除しても、変更のクラス上位の階層となります。べきではない名前の変更やクラスでいたが、価値観なの直列化復元).大きさを変えることはできません型のプリミティブ型、変更できます参照型の分野での新しいタイプに割り当から全ての値です。
注意:る場合の基底クラスを実装しない直列化可能のサブクラスは、その分野からの基底クラスのばして行動する transient
.