[目次] [前項目] [次項目]

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


トピック:

概要

ストリーム形式は、次の目標を達成するように設計されています。

ストリーム要素

ストリームのオブジェクトを表すには、基本構造が必要です。 オブジェクトの各属性、つまりそのクラス、そのフィールド、およびクラス固有のメソッドによって書き込まれ、後に読み込まれるデータが表されなければなりません。ストリームのオブジェクトの表現は、ある文法によって記述することができます。null オブジェクト、新規オブジェクト、クラス、配列、文字列、およびすでにストリームにあるオブジェクトへのバック参照に対し、特別な表現があります。ストリームに書き込まれた各オブジェクトには、このオブジェクトをバック参照するために使用するハンドルが割り当てられます。ハンドルは、ゼロから始まり順次に割り当てられます。ストリームがリセットされると、ハンドルは再びゼロから始まります。

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

An ObjectStreamClass オブジェクトは次の要素によって表されます。

文字列はそれらの UTF コード化によって表されます。修正された UTF の現在の仕様と実装では、コード化された文字列の合計の長さは 65535 文字に制限されますので注意が必要です。

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

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

クラスによって書き込まれたすべてのプリミティブデータは、ブロックデータレコードにバッファされ、ラップされます。これは、そのデータが writeObject メソッドの中でストリームに書き込まれたのか、writeObject メソッドの外から直接ストリームに書き込まれたのかには関係ありません。このデータは、対応する readObject メソッドによって読み込むか、ストリームから直接読み込むことができます。writeObject によって書き込まれたオブジェクトは、前に書き込まれたブロックデータレコードがあればそれを停止し、正規オブジェクト、null、またはバック参照のうち適切なものとして書き込まれます。ブロックデータレコードでは、エラー回復によって任意指定データを破棄することができます。クラスの中から呼び出された場合には、ストリームはデータやオブジェクトを endBlockData まで破棄することができます。

ストリーム形式の文法

下のテーブルはこの文法を示したものです。非終端記号はイタリックで、終端記号は固定幅のフォントで示します。非終端の定義には、その後に ":"が続きます。定義には 1 つまたは複数の代替定義が続き、それぞれが別の行に示されます。下のテーブルはその表記法を示しています。
表記法 意味
(datatype) このトークンには、バイトなどのデータ型が指定されます。
token[n] このトークンの事前に定義されたオカレンス数。これは配列です。
x0001 16 進数で表したリテラル値。16 進数の桁数がその値のサイズを表します。
<xxx> ストリームから読み込まれた値であり、配列の長さを示すために使用されます。

文法規則

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

stream:
	magic version contents
contents:
	content
	contents content
content:
	object
	blockdata
object:
	newObject
	newClass
	newArray
	newString
	newClassDesc
	prevObject
	nullReference
	exception
	TC_RESET
newClass:
	TC_CLASS classDesc newHandle
classDesc:
	newClassDesc
	nullReference
	(ClassDesc)prevObject	// オブジェクトの型は ClassDescでなければならない。
superClassDesc:
	classDesc
newClassDesc:
	TC_CLASSDESC className serialVersionUID	newHandle classDescInfo
classDescInfo:
	classDescFlags fields classAnnotation superClassDesc 
className:
	(utf)
serialVersionUID:
	(long)
classDescFlags:
	(byte)	// 終端記号と定数で定義される。
fields:
	(short)<count>  fieldDesc[count]	
fieldDesc:
	primitiveDesc
	objectDesc
primitiveDesc:
	prim_typecode fieldName
objectDesc:
	obj_typecode fieldName className
fieldName:
	(utf)
className:
	(String)object		// フィールドの型を含む文字列
classAnnotation:
	endBlockData
	contents endBlockData	// 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[]	// 各クラスのデータ
classdata:
	nowrclass	// SC_WRRD_METHOD & !classDescFlags
	wrclass objectAnnotation	// SC_WRRD_METHOD & classDescFlags 
nowrclass:
	values	// クラス記述子の順序になったフィールド
wrclass:
	nowrclass
objectAnnotation:
	endBlockData
	contents endBlockData	// writeObjectによって書き込まれた内容
blockdata:
	TC_BLOCKDATA (byte)<size> (byte)[size]
blockdatalong:
	TC_BLOCKDATALONG (int)<size> (byte)[size]
endBlockData	:
	TC_ENDBLOCKDATA
newString:
	TC_STRING newHandle (utf)
prevObject	:
	TC_REFERENCE (int)handle
nullReference	:
	TC_NULL
exception:
	TC_EXCEPTION reset (Throwable)object	 reset 
resetContext:	
	TC_RESET
magic:	
	STREAM_MAGIC
version	:
	STREAM_VERSION
values:		// サイズと型は現行オブジェクトに対し
		// classDescによって記述される。
newHandle:		// 順序にある次の番号が直列化または直列化復元
			// されているオブジェクトに割り当てられる。

終端記号と定数

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;
フラグバイト classDescFlags は、次の記号の値をもつことがあります。

	final static byte SC_WRITE_METHOD = 0x01;
	final static byte SC_SERIALIZABLE = 0x02;
	final static byte SC_EXTERNALIZABLE = 0x04;
ストリームを書き込んでいるクラスに writeObject メソッドがあって、それがストリームに追加データを書き込んだ可能性があると、フラグ SC_WRITE_METHOD はオンに設定されます。この場合には、そのクラスのデータは常に TC_ENDBLOCKDATA マーカーで終わっていなければなりません。

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

ストリームを書き込んだクラスが java.io.Externalizable を拡張した場合は、フラグ SC_EXTERNALIZABLE がオンに設定されます。そのデータを読み込むクラスもまた、 Externalizable を拡張しなければなりません。このデータはその writeExternal と readExternal メソッドを使って読み込まれます。

オリジナルクラスと、リンクされたリストの 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 (C) 1996, 1997 Sun Microsystems, Inc. All rights reserved.