目次|| Javaオブジェクト直列化仕様
Version 6.0

オブジェクト直列化ストリーム・プロトコル






第6章

トピック:


6.1 概要

このストリーム形式は、次の設計目標を実現しました。


6.2 ストリーム要素

基本構造は、ストリーム内のオブジェクトを表す必要があります。オブジェクトの各属性(クラス、フィールド、およびクラス固有のメソッドによって書き込まれてあとで読み取られるデータ)を表現する必要があります。ストリーム内のオブジェクトの表現は、文法で記述できます。nullオブジェクト、新規オブジェクト、クラス、配列、文字列、およびストリーム内の既存のオブジェクトへの逆参照には、特別な表現があります。ストリームに書き込まれた各オブジェクトには、オブジェクトに逆参照するために使用するハンドルが割り当てられます。ハンドルは、0x7E0000からシーケンシャルに割り当てられます。ストリームがリセットされると、ハンドルはふたたび0x7E0000から始まります。

クラス・オブジェクトは、次の要素によって表されます。

ダイナミック・プロキシ・クラス以外のClassのObjectStreamClassオブジェクトは、次の要素によって表されます。

ダイナミック・プロキシ・クラスのObjectStreamClassオブジェクトは、次の要素によって表されます。

Stringオブジェクトの表現は、長さ情報およびModified UTF-8でエンコードされた文字列の内容で構成されます。Modified UTF-8エンコーディングは、Java仮想マシンとjava.io.DataInputおよびDataOutputインタフェースで使用されるものと同じですが、補助文字とnull文字の表現が標準UTF-8とは異なります。長さ情報の形式は、Modified UTF-8エンコーディング内の文字列の長さに依存します。指定されたStringのModified UTF-8エンコーディング長が65,536バイト未満の場合、長さは符号なし16ビット整数を表す2バイトとして書き込まれます。Java 2 platform, Standard Edition, v1.3以降では、Modified UTF-8エンコーディングでの文字列の長さが65,536バイト以上の場合、長さは符号付き64ビット整数を表す8バイトで書き込まれます。直列化ストリーム内でStringの前にある型コードは、Stringの書込みに使用された形式を表しています。

配列は次の要素によって表されます。

enum定数は次の要素によって表されます。

ストリーム内の新規オブジェクトは次の要素によって表されます。

クラスによって書き込まれたすべてのプリミティブ・データは、バッファリングされてブロック・データ・レコードにラップされます(データがwriteObjectメソッド内でストリームに書き込まれたか、writeObjectメソッドの外部から直接ストリームに書き込まれたのかに関係なく)。このデータは、対応するreadObjectメソッドによって読み込むか、ストリームから直接読み込むことができます。writeObjectメソッドによって書き込まれるオブジェクトは、既存のブロック・データ・レコードを終了し、必要に応じて通常のオブジェクト、null、または逆参照として書き込まれます。ブロック・データ・レコードでは、エラー回復によってオプション・データを破棄できます。クラス内から呼び出された場合には、ストリームはデータやオブジェクトをendBlockDataまで破棄できます。


6.3 ストリーム・プロトコル・バージョン

JDK 1.2での直列化ストリーム形式への変更は、JDK 1.1のすべてのマイナー・リリースと下位互換性のない方法で行う必要がありました。下位互換性が必要な場合に備えるために、直列化ストリームを書き込むときにどのPROTOCOL_VERSIONを使用するかを示す機能が追加されました。ObjectOutputStream.useProtocolVersionメソッドは、直列化ストリームを書き込むときに使用するプロトコル・バージョンをパラメータとしてとります。

ストリーム・プロトコル・バージョンを次に示します。

JDK 1.2は、デフォルトでPROTOCOL_VERSION_2を書き込みます。

JDK 1.1は、デフォルトでPROTOCOL_VERSION_1を書き込みます。

JDK 1.1.7以降は、両方のバージョンを読み取ることができます。

JDK 1.1.7より前のリリースは、PROTOCOL_VERSION_1のみを読み取れます。


6.4 ストリーム形式の文法

以下の表は、ストリーム形式の文法を示しています。非ターミナル・シンボルは、イタリックで示されます。ターミナル・シンボルは固定幅フォントで示されます。非ターミナルの定義は、その後に「:」が続きます。定義のあとには1つまたは複数の代替定義が続き、それぞれが別の行に示されます。次の表に表記法を示します。

表記法
意味

(データ型)

このトークンにはbyteなどのデータ型が指定される。

トークン[n]

このトークンの事前定義オカレンス数(配列)。

x0001

16進数で表したリテラル値。16進数の数字が値のサイズを表す。

<xxx>

配列の長さを示すために使用される、ストリームから読み込まれた値。

シンボル(utf)は、2バイトの長さ情報を使用して書き込まれた文字列を示すために使用され、(long-utf)は、8バイトの長さ情報を使用して書き込まれた文字列を示すために使用されます。詳細については、セクション6.2「ストリーム要素」を参照してください。

6.4.1 文法規則

直列化されたストリームは、ストリーム規則を満たすストリームによって表されます。

stream:
  magic version contents

contents:
  content
  contents content

content:
  object
  blockdata

object:
  newObject
  newClass
  newArray
  newString
  newEnum
  newClassDesc
  prevObject
  nullReference
  exception
  TC_RESET

newClass:
  TC_CLASS classDesc newHandle

classDesc:
  newClassDesc
  nullReference
  (ClassDesc)prevObject      // an object required to be of type
                             // ClassDesc

superClassDesc:
  classDesc

newClassDesc:
  TC_CLASSDESC className serialVersionUID newHandle classDescInfo
  TC_PROXYCLASSDESC newHandle proxyClassDescInfo
classDescInfo:
  classDescFlags fields classAnnotation superClassDesc 

className:
  (utf)

serialVersionUID:
  (long)

classDescFlags:
  (byte)                  // Defined in Terminal Symbols and
                            // Constants

proxyClassDescInfo:
  (int)<count> proxyInterfaceName[count] classAnnotation
      superClassDesc
proxyInterfaceName:
  (utf)
fields:
  (short)<count>  fieldDesc[count]

fieldDesc:
  primitiveDesc
  objectDesc

primitiveDesc:
  prim_typecode fieldName

objectDesc:
  obj_typecode fieldName className1

fieldName:
  (utf)

className1:
  (String)object             // String containing the field's type,
                             // in field descriptor format
classAnnotation:
  endBlockData
  contents endBlockData      // contents written by annotateClass

prim_typecode:
  `B'       // byte
  `C'       // char
  `D'       // double
  `F'       // float
  `I'       // integer
  `J'       // long
  `S'       // short
  `Z'       // boolean

obj_typecode:
  `[`   // array
  `L'       // object

newArray:
  TC_ARRAY classDesc newHandle (int)<size> values[size]

newObject:
  TC_OBJECT classDesc newHandle classdata[]  // data for each class

classdata:
  nowrclass                 // SC_SERIALIZABLE & classDescFlag &&
                            // !(SC_WRITE_METHOD & classDescFlags)
  wrclass objectAnnotation  // SC_SERIALIZABLE & classDescFlag &&
                            // SC_WRITE_METHOD & classDescFlags
  externalContents          // SC_EXTERNALIZABLE & classDescFlag &&
                            // !(SC_BLOCKDATA  & classDescFlags
  objectAnnotation          // SC_EXTERNALIZABLE & classDescFlag&& 
                            // SC_BLOCKDATA & classDescFlags

nowrclass:
  values                    // fields in order of class descriptor

wrclass:
  nowrclass

objectAnnotation:
  endBlockData
  contents endBlockData     // contents written by writeObject
                            // or writeExternal PROTOCOL_VERSION_2.

blockdata:
  blockdatashort
  blockdatalong

blockdatashort:
  TC_BLOCKDATA (unsigned byte)<size> (byte)[size]

blockdatalong:
  TC_BLOCKDATALONG (int)<size> (byte)[size]

endBlockData   :
  TC_ENDBLOCKDATA

externalContent:          // Only parseable by readExternal
  ( bytes)                // primitive data
    object

externalContents:         // externalContent written by 
  externalContent         // writeExternal in PROTOCOL_VERSION_1.
  externalContents externalContent

newString:
  TC_STRING newHandle (utf)
  TC_LONGSTRING newHandle (long-utf)

newEnum:
  TC_ENUM classDesc newHandle enumConstantName
enumConstantName:
  (String)object
prevObject
  TC_REFERENCE (int)handle

nullReference
  TC_NULL

exception:
  TC_EXCEPTION reset (Throwable)object         reset 

magic:
  STREAM_MAGIC

version
  STREAM_VERSION

values:          // The size and types are described by the
                 // classDesc for the current object

newHandle:       // The next number in sequence is assigned
                 // to the object being serialized or deserialized

reset:           // The set of known objects is discarded
                 // so the objects of the exception do not
                 // overlap with the previously sent objects 
                 // or with objects that may be sent after 
                 // the exception


6.4.2 ターミナル・シンボルと定数

java.io.ObjectStreamConstantsの次のシンボルは、ストリームで予期されるターミナル値と定数値を定義します。

    final static short STREAM_MAGIC = (short)0xaced;
    final static short STREAM_VERSION = 5;
    final static byte TC_NULL = (byte)0x70;
    final static byte TC_REFERENCE = (byte)0x71;
    final static byte TC_CLASSDESC = (byte)0x72;
    final static byte TC_OBJECT = (byte)0x73;
    final static byte TC_STRING = (byte)0x74;
    final static byte TC_ARRAY = (byte)0x75;
    final static byte TC_CLASS = (byte)0x76;
    final static byte TC_BLOCKDATA = (byte)0x77;
    final static byte TC_ENDBLOCKDATA = (byte)0x78;
    final static byte TC_RESET = (byte)0x79;
    final static byte TC_BLOCKDATALONG = (byte)0x7A;
    final static byte TC_EXCEPTION = (byte)0x7B;
    final static byte TC_LONGSTRING = (byte) 0x7C;
    final static byte TC_PROXYCLASSDESC = (byte) 0x7D;
    final static byte TC_ENUM = (byte) 0x7E;
    final static  int   baseWireHandle = 0x7E0000;
フラグbyte classDescFlagsは、次の値を含めることができます。

    final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE
     final static byte SC_BLOCK_DATA = 0x08;    //if SC_EXTERNALIZABLE
    final static byte SC_SERIALIZABLE = 0x02;
    final static byte SC_EXTERNALIZABLE = 0x04;
    final static byte SC_ENUM = 0x10;
フラグSC_WRITE_METHODは、ストリームを書き込んでいるSerializableクラスにwriteObjectメソッドがあり、それがストリームに追加データを書き込んだ可能性がある場合に設定されます。この場合、TC_ENDBLOCKDATAマーカーが常にそのクラスのデータを終了することが期待されます。

フラグSC_BLOCKDATAは、STREAM_PROTOCOL_2を使ってExternalizableクラスがストリームに書き込まれる場合に設定されます。デフォルトでは、これがJDK 1.2でExternalizableオブジェクトをストリームに書き込むために使用されるプロトコルです。JDK 1.1は、STREAM_PROTOCOL_1を書き込みます。

フラグSC_SERIALIZABLEは、ストリームを書き込んだクラスがjava.io.Serializableを拡張したけれども、java.io.Externalizableは拡張しなかった場合に設定されます。そのストリームを読み込むクラスもjava.io.Serializableを拡張してデフォルト直列化メカニズムを使用しなければいけません。

フラグSC_EXTERNALIZABLEは、ストリームを書き込んだクラスがjava.io.Externalizableを拡張した場合に設定されます。そのデータを読み込むクラスもExternalizableを拡張する必要があり、データはそのwriteExternalおよびreadExternalメソッドを使って読み込まれます。

フラグSC_ENUMは、ストリームを書き込んだクラスがenum型だった場合に設定されます。受け取り側の対応するクラスもenum型でなければいけません。enum型の定数のデータは、セクション1.12「Enum定数の直列化」で説明するように読み書きされます。


オリジナル・クラスと、リンクされたリスト内の2つのインスタンスの場合を想定します。

class List implements java.io.Serializable {
    int value;
    List next;
    public static void main(String[] args) {
        try {
            List list1 = new List();
            List list2 = new List();
            list1.value = 17;
            list1.next = list2;
            list2.value = 19;
            list2.next = null;

            ByteArrayOutputStream o = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(o);
            out.writeObject(list1);
            out.writeObject(list2);
            out.flush();
            ...
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
結果のストリームの内容は次のようになります。

00: ac ed 00 05 73 72 00 04 4c 69 73 74 69 c8 8a 15 >....sr..Listi...<
10: 40 16 ae 68 02 00 02 49 00 05 76 61 6c 75 65 4c >Z......I..valueL<
20: 00 04 6e 65 78 74 74 00 06 4c 4c 69 73 74 3b 78 >..nextt..LList;x<
30: 70 00 00 00 11 73 71 00 7e 00 00 00 00 00 13 70 >p....sq.~......p<
40: 71 00 7e 00 03                                  >q.~..<


目次||
Copyright © 2005, 2010, Oracle and/or its affiliates. All rights reserved.