目次 | 前の項目 | 次の項目 | Java オブジェクト直列化仕様 Version 6.0 |
第 4 章 |
ObjectStreamClass
は、直列化ストリームに保管されるクラスの情報を返します。その記述子には、そのクラスの完全修飾名とその直列化バージョン UID が示されます。SerialVersionUID
は、このクラスがストリームを書き込んだり、読み込んだりできる固有のオリジナルクラスバージョンを特定します。package java.io; public class ObjectStreamClass { public static ObjectStreamClass lookup(Class cl); public static ObjectStreamClass lookupAny(Class cl); public String getName(); public Class forClass(); public ObjectStreamField[] getFields(); public long getSerialVersionUID(); public String toString(); }lookup
メソッドは、仮想マシンの指定されたクラスに対するObjectStreamClass
記述子を返します。このクラスにserialVersionUID
が定義されていれば、それがこのクラスから取り出されます。serialVersionUID
がクラスによって定義されていなければ、仮想マシンにあるこのクラスの定義から計算されます。指定されたクラスが Serializable でも Externalizable でもない場合、null が返されます。
lookupAny
メソッドの動作はlookup
メソッドの動作と同じですが、Serializable
を実装するかどうかに関係なく、任意のクラスの記述子を返す点だけが異なります。Serializable
を実装しないクラスのserialVersionUID
は 0L です。
getName
メソッドが返すクラス名の形式は、Class.getName
メソッドが使用する形式と同じになります。
forClass
メソッドは、ObjectInputStream.resolveClass
メソッドがローカルの仮想マシン内にClass
を検出した場合に、そのClass
を返します。それ以外の場合は、null を返します。
getFields
メソッドは、このクラスの直列化可能フィールドを表すObjectStreamField
オブジェクトの配列を返します。
getSerialVersionUID
メソッドは、このクラスのserialVersionUID
を返します。「4.6 ストリーム固有識別子」を参照してください。このクラスによって定義されていない場合は、米国国立標準技術研究所によって定義されている Secure Hash Algorithm (SHA) を使って、クラスの名前、インタフェース、メソッド、フィールドから計算されたハッシュ値が返されます。
toString
メソッドは、クラス記述子のプリント可能な表現を返します。クラス記述子としては、クラスの名前とserialVersionUID
があります。
ObjectStreamClass 記述子を使って、直列化ストリームに保存されているダイナミックプロキシクラス (java.lang.reflect.Proxy の getProxyClass メソッドへの呼び出しを介して取得されるクラスなど) についての情報を提供することもできます。ダイナミックプロキシクラス自体は直列化可能フィールドを持たず、0L の serialVersionUID を持ちます。つまり、ダイナミックプロキシクラスの Class オブジェクトが ObjectStreamClass の static lookup メソッドに渡されると、返される ObjectStreamClass インスタンスは、次のプロパティーを持ちます。
ObjectStreamClass の直列化された形式は、その形式が表現する Class オブジェクトが直列化可能であるかどうか、外部化可能であるかどうか、またはダイナミックプロキシクラスであるかどうかによって異なります。ダイナミックプロキシクラスを表現しない
ObjectStreamClass
インスタンスがストリームに書き込まれるとき、クラス名とserialVersionUID
、フラグ、およびフィールド数が書き込まれます。クラスによっては、その他の情報が書き込まれることもあります。
- 直列化が不可能なクラスは、フィールド数が常にゼロです。
SC_SERIALIZABLE
およびSC_EXTERNALIZABLE
フラグビットは設定されません。- 直列化可能クラスでは、
SC_SERIALIZABLE
フラグが設定され、フィールド数には直列化可能フィールドの数がカウントされ、そのあとに各直列化可能フィールドの記述子が続きます。記述子は、標準的な順序で書き込まれます。最初に、プリミティブ型のフィールドの記述子がフィールド名でソートされて書き込まれ、次に、オブジェクト型のフィールドの記述子がフィールド名でソートされて書き込まれます。名前のソートには、String.compareTo
が使われます。この形式の詳細については、「6.4 ストリーム形式の文法」を参照してください。- 外部化可能クラスでは、フラグは
SC_EXTERNALIZABLE
フラグを含み、フィールド数は常にゼロです。- enum 型では、フラグは
SC_ENUM
フラグを含み、フィールド数は常にゼロです。
ObjectOutputStream がダイナミックプロキシクラスの ObjectStreamClass 記述子を直列化するとき、Class オブジェクトを java.lang.reflect.Proxy の isProxyClass メソッドに渡すことによって決定されるとおり、ダイナミックプロキシクラスが実装するインタフェース数を記述し、その後にインタフェースの名前を続けます。ダイナミックプロキシクラスの Class オブジェクトの getInterfaces メソッドの呼び出しから返される順序に従ってインタフェースがリストされます。ダイナミックプロキシクラスおよび非ダイナミックプロキシクラスの ObjectStreamClass 記述子の直列化表現は、使用するタイプコードの種類 (TC_PROXYCLASSDESC および TC_CLASSDESC のどちらか) によって異なります。 文法の仕様についての詳細は「6.4 ストリーム形式の文法」を参照してください。
ObjectStreamField
は、直列化可能クラスの直列化可能フィールドを表現します。クラスの直列化可能フィールドは、ObjectStreamClass
から取得できます。特別な静的直列化可能フィールド (
serialPersistentFields
) はObjectStreamField
コンポーネントの配列であり、デフォルトの直列化可能フィールドのオーバーライドに使用されます。package java.io; public class ObjectStreamField implements Comparable { public ObjectStreamField(String fieldName, Class fieldType); public ObjectStreamField(String fieldName, Class fieldType, boolean unshared); public String getName(); public Class getType(); public String getTypeString(); public char getTypeCode(); public boolean isPrimitive(); public boolean isUnshared(); public int getOffset(); protected void setOffset(int offset); public int compareTo(Object obj); public String toString(); }ObjectStreamField
オブジェクトは、クラスの直列化可能フィールドの指定、またはストリームに存在するフィールドの記述に使われます。そのコンストラクタは、表現するフィールドを記述する引数を受け取ります。引数には、フィールドの型を指定する文字列、フィールドのタイプを指定するClass
オブジェクト、および、デフォルトの直列化/直列化復元が使用中の場合にフィールドの値を非共有オブジェクトとして読み書きする必要があるかどうかを示すboolean
フラグ (2 つの引数をとるコンストラクタでは暗黙的にfalse
) があります (3.1 および 2.1 の各節でObjectInputStream.readUnshared
メソッドおよびObjectOutputStream.writeUnshared
メソッドの説明を参照)。
getName
メソッドは、直列化可能フィールドの名前を返します。
getTypeString
メソッドは、フィールドの型のシグニチャーを返します。
getTypeCode
メソッドは、フィールドの型の文字エンコーディングを返します (`B''
はbyte
、`C'
はchar
、`D'
はdouble
、`F'
はfloat
、`I'
はint
、`J'
はlong
、`L'
非配列オブジェクト型、`S'
はshort
、`Z'
はboolean
、`[`
は配列)。
isPrimitive
メソッドは、フィールドがプリミティブ型の場合はtrue
を返し、それ以外の場合はfalse
を返します。
isUnshared
メソッドは、フィールドの値を非共有オブジェクトとして書き込む必要がある場合はtrue
を返し、それ以外の場合はfalse
を返します。
getOffset
メソッドは、フィールドを定義するクラスのインスタンスデータ内でのフィールド値のオフセットを返します。
setOffset
メソッドは、getOffset
メソッドから返されたオフセット値をObjectStreamField
サブクラスで変更できるようにします。
compareTo
メソッドは、ソートに使うためにObjectStreamFields
を比較します。プリミティブフィールドは、非プリミティブフィールドよりも「小さい」順位にランク付けられます。同じ型のフィールドは、アルファベット順にランク付けられます。
toString
メソッドは、名前、および型とともに、プリント可能な表現を返します。
プログラム serialver を使うと、クラスが直列化可能かどうかを判断し、そのserialVersionUID
を得ることができます。-show オプションを指定して呼び出すと、このプログラムは簡単なユーザーインタフェースを表示します。クラスが直列化可能かどうかを知り、その serialVersionUID を得るには、そのクラス名全体を指定し、Enter キーか [Show] ボタンを押します。表示された文字列は、コピーして、展開されたクラスにペーストすることができます。
serialver は、コマンド行から呼び出されたときに 1 つまたは複数のクラス名が指定されていると、展開中のクラスにそれぞれのクラスのserialVersionUID
をコピーできるような形式で表示します。引数が指定されていないと、このプログラムの使用方法が表示されます。
バージョン管理された各クラスでは、オリジナルクラスバージョンを指定する必要があり、それによってストリームの書き込み、読み込みが可能になります。たとえば、バージョン管理されたクラスは、次のように宣言する必要があります。private static final long serialVersionUID = 3487495895819393L;ストリーム固有識別子は、クラス名、インタフェースクラス名、メソッド、およびフィールドをハッシュした 64 ビットの値です。最初のバージョンを除くクラスのすべてのバージョンで、この値を宣言する必要があります。この値は、オリジナルクラスに宣言することもできますが、必須ではありません。互換性のあるすべてのクラスで、この値は一定です。クラスに対してこの SUID を宣言しないと、この値はそのクラスのハッシュになります。ダイナミックプロキシクラスおよび enum 型のserialVersionUID
は、常に値 0L になります。配列クラスはserialVersionUID
を明示的に宣言できないため、常にデフォルトの計算値を持ちますが、配列クラスに関してはserialVersionUID
値の一致要件は適用されません。
注 - すべての直列化可能なクラスは、serialVersionUID
の値を明示的に宣言することを強くお勧めします。 これは、デフォルトのserialVersionUID
の算出は、コンパイラ実装により異なることがあるクラスの詳細によって大きく変わり、そのため直列化復元中にserialVersionUID
の予期しない競合が発生して直列化復元が失敗する可能性があるためです。
Externalizable
クラスの初期バージョンでは、将来的に拡張可能なストリームデータ形式を出力する必要があります。readExternal
メソッドの初期バージョンは、writeExternal
メソッドの将来のすべてのバージョンの出力形式を読み取り可能でなければなりません。
serialVersionUID
は、そのクラス定義を反映したバイトストリームのシグニチャーを使って計算されます。ストリームのシグニチャーの計算には、米国国立標準技術研究所 (NIST) の Secure Hash Algorithm (SHA-1) が使用されます。64 ビットハッシュには、最初の 2 つの 32 ビットが使われます。プリミティブデータ型からバイト列への変換には、java.lang.DataOutputStream
が使用されます。このストリームに入力される値は、クラスに対する JavaTM 仮想マシン (VM) の指定によって定義されます。クラスの修飾子にはACC_PUBLIC
、ACC_FINAL
、ACC_INTERFACE
、およびACC_ABSTRACT
フラグがあります。 その他のフラグは無視され、serialVersionUID
の計算に影響しません。同様にフィールドの修飾子では、ACC_PUBLIC
、ACC_PRIVATE
、ACC_PROTECTED
、ACC_STATIC
、ACC_FINAL
、ACC_VOLATILE
、およびACC_TRANSIENT
フラグだけがserialVersionUID
の値の計算に使用されます。コンストラクタおよびメソッドの修飾子の場合は、ACC_PUBLIC
、ACC_PRIVATE
、ACC_PROTECTED
、ACC_STATIC
、ACC_FINAL
、ACC_SYNCHRONIZED
、ACC_NATIVE
、ACC_ABSTRACT
、およびACC_STRICT
フラグだけが使用されます。名前と記述子は、java.io.DataOutputStream.writeUTF
メソッドが使用する形式で記述されます。
private static
と private transient
のフィールドを除く)
<clinit>
java.lang.reflect.Modifier.STATIC
()V
private
でない各コンストラクタの場合
<init>
private
でない各メソッドの場合
DataOutputStream
によって作成されたバイトストリームに対して実行され、5 つの 32 ビット値からなる sha[0..4]
を作成します。
H0 H1 H2 H3 H4
は、sha
という名前の 5 つの int
値の配列で、ハッシュ値は次のように計算されます。
long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) << 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) << 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) << 56;