シリアル化(以降「保存」)は、外部ストレージにオブジェクトデータを保存するプロセスです。
この操作は、逆方向のデータ回復とペアになっています。これは、非現実化と呼ばれます(以降の「回復」ではDeserealize
)。
データのバックアップおよびリカバリ操作は非常に頻繁に使用されます。 古典的なプログラミング言語では、オブジェクトのデータを保存および復元するための既製のメカニズムはありません。そのような必要が生じた場合、自分で作成する必要があります。
Javaには、このような既製のメカニズムが存在し、複数のメカニズムが存在します。 Kotlin
プログラムにどのようなメカニズムがあり、どのような機会がプログラムに提供されているかを見てみましょう。
シリアル化の概念は、データが保存されるデータ形式とはまったく関係がないため、結果が何であれ-独自の構造を持つバイナリファイル、 XML
、 JSON
、さらにはテキストファイル-すべてがシリアル化されます。
連載
古典的なプログラミング言語では、構造化オブジェクトを保存するための既製のオプションはありませんが、 データ構造はメモリに直接あり、データを直接保存および復元する簡単な方法があります。 一方で、相互接続を使用して複雑なオブジェクトを保存する必要がある場合にのみ保存する独自の手段を作成する必要がありますが、一方で、ある種の最も単純な既製のメカニズムを使用する場合でも、その形式でデータを保存する実装はこれはかなり面倒な作業です。
Javaでは、1つのオブジェクトの要素のデータはJVM
メモリー全体にランダムに分散されているため、オブジェクトの構造全体を保存できたとしても、データを保存することはできません。したがって、Javaで可能な唯一の方法は、オブジェクトを構成する基本型の要素ごとのデータを書き込むことです。
一方で、Javaでの1つの操作でオブジェクト全体を保存することはできませんが、 RTTI
の開発のおかげで、保存用の既製のツールを使用して非常に簡単に実装できます。
Writer
やPrintStream
などの多くのストリームクラスは、基本データ型を格納するための既製の機能を提供しますが、非常に多くの記述が必要なため、それらを使用することは従来のプログラミング言語と同様に不便です。
ただし、Javaには、基本型の処理に加えて、クラスデータを格納するための既製のメカニズムと、同じ形式で動作する多くのライブラリがいくつかあり、パフォーマンス、ボリューム、機能が異なります。
以下では、データを保存する一般的な方法を検討します。標準Javaライブラリへの組み込み、およびXML
およびJSON
保存JSON
。
シリアライズ可能
標準Javaライブラリに存在する最も単純な機能は、バイナリ形式の完全自動モードでデータを保存および復元することです。 この機能を実装するには、データを自動的に保存および復元するすべてのクラス、実装されたSerializableインターフェイスを指定するだけです。 これは、メソッドの実装を必要としないマーカーインターフェイスです。 このクラスのデータをバックアップおよび復元する必要があることを示すためだけに使用されます。
使用例
このクラスの使用は基本的です-1つの操作で、1つの余分な文字を書く必要はありません。
class DataClass(s : String) : Serializable { @JvmField var strField = "" @JvmField var intField = 0 @JvmField var dbField = 0.0 protected @JvmField var strProt = "" private var strPriv = "" @JvmField val valStr : String protected @JvmField val valProt : String init { valStr = s valProt = "prot=" + s strField = s + ":baseText" intField = s.hashCode() dbField = s.hashCode().toDouble() / 1000 strProt = s+":prot" strPriv = s+":priv" } fun print() { outn("str = [%s]\nint = [%d]\ndb = [%f]", strField, intField, dbField) outn("prot = [%s]\npriv = [%s]", strProt, strPriv) outn("value = [%s]\nprot value = [%s]", valStr, valProt) } } fun Action() { outn( "Simple object IO test" ) val a = DataClass("dataA") outn("Saved contents:") a.print() Holder(ObjectOutputStream(File("out.bin").outputStream())).h.writeObject(a) val b = Holder(ObjectInputStream(File("out.bin").inputStream())).h.readObject() outn("Class: %s", b.javaClass.name) if (b is DataClass) { outn("Loaded contents:") b.print() } }
このテストの結果、次の出力が得られます。
Simple object IO test Saved contents: str = [dataA:baseText] int = [95356375] db = [95356,375000] prot = [dataA:prot] priv = [dataA:priv] value = [dataA] prot value = [prot=dataA] Class: app.test.Externalize.Test$DataClass Loaded contents: str = [dataA:baseText] int = [95356375] db = [95356,375000] prot = [dataA:prot] priv = [dataA:priv] value = [dataA] prot value = [prot=dataA]
すでに結果からわかるように、オブジェクトの保存と復元は成功し、復元後、新しいオブジェクトは保存されたオブジェクトとまったく同じ内容になります。
プログラムが実行されると、ファイル「 out.bin
」がバイナリ形式で244バイトのサイズで作成されました。 形式の説明はさまざまなソースで見つけることができますが、私の意見では、それを理解することは意味がなく、正常に保存および復元するのに十分です。
特徴
上記の例をより詳細に検討すると、次の機能を見ることができます。
- アクセスタイプ "
private
"および "protected
"が指定されているフィールドも含め、すべてのフィールドが保存および復元されました。 - 「
val
」と示されたフィールドも処理されました。Kotlin
標準により不変です。 - 新しいオブジェクトが作成されましたが、パラメーターのないコンストラクターはなく、既存のオブジェクトは呼び出されませんでした。
その結果、プログラムテキストに示されているすべての構文上の制限を回避して、オブジェクトの状態が保存および復元されることは明らかです。 実装のこの機能はプラスの場合もありますが、使用の基本的な制限になる場合もあります。
データを保存するために、特別なObjectOutputStream
ストリーム(およびその類似物)がロードに使用されます。 このストリームは、使用したオブジェクト全体を含む、すべてのデータ型で機能します。 このストリームによって生成されたデータには、独立した情報ブロックのセットが含まれているため、その使用に制限はありません。 1つのストリームに好きなだけオブジェクトまたは基本型を保存できます。最も重要なことは、復元するときにそれらを逆の順序で読み取ることです。
この保存および復元メカニズムの重要な機能は、読み取り機能が記録されたデータの境界を自動的に制御し、データが書き込まれた側以外のデータの読み取りを許可しないことです。
オブジェクトが記録されている場合、そのコンテンツバイトの読み取りは機能しません。
バイト読み取り関数は、バイトとして保存されていないブロックのデータを読み取ろうとするとすぐに、エラーで例外をスローします。 これは基本的なデータ保護メカニズムであり、非常に便利です。 自動データ整合性チェックを提供します。
データを保存および復元するためのクラスはストリームであり、そのコンテンツはストリームを処理する任意のクラスでラップできます。 保存されたデータを圧縮、暗号化、ネットワーク経由で転送、メモリに保存、アーカイブまたは内部コンテナに保存できます。
特徴
この方法は明らかに単純ですが、非常に簡単で使いやすい非常に強力なメカニズムを提供します。 以下に説明する欠点がありますが、多くの場合、その機能はプログラマが必要とするすべてのものに十分です。
一意のオブジェクトは一度だけストリームに保存されます。 同じものへのリンクである複数のオブジェクトが保存される場合、オブジェクトデータはそのうちの1つのみに対して保存され、残りは既に保存されたものへのリンクのみが記録されます。
データを復元すると、すべてのリンクが元のオブジェクトに存在していたのと同じ形式で復元されるように、オブジェクトが復元されます。
オブジェクトを保存すると、相互のリンクが自動的に追跡され、復元すると、類似したオブジェクトは同じオブジェクトを参照します。 つまり オブジェクト
«»
とオブジェクト«»
を保存し、同時にオブジェクト«»
フィールドの1つが保存されたオブジェクト«»
へのリンクである場合、クラス«»
2つの異なるコピーは保存されませんが、1つだけが保存されます。 フィールドを復元する場合、新しいオブジェクト«»
は同じストリームから復元されたオブジェクト«»
参照します«»
つまり、 蜂蜜オブジェクトとの通信が復元されます。
この機能により、リンクを壊したりデータを複製したりすることなく、相互に参照するオブジェクトの接続された階層を完全に透過的に維持できます。
正しい復元で
«enum»
クラスの保存をサポートします。
Serializableマーカーインターフェイスを持つオブジェクトの保存と復元をサポートしています。 特に、リスト、セット、およびマップに基づくすべての標準JDKコレクションは自動的に保存されます。 すべての実装にはこのマーカーがあります。
つまり リストまたはツリーのすべての要素を保存および復元するために、追加のコードを記述する必要はありません。オブジェクトが「Serializable」インターフェースで示されていれば十分です。
- すべての祖先のデータは自動的に保存および復元されます。このクラスから継承すると、現在のデータもすべて保存されます。
継承チェーン全体の保存と復元を保証するための追加のアクションは必要ありません。
データを保存および復元するプロセスをより正確に制御するには、追加のメカニズムを使用できます。
バージョン管理
なぜなら オブジェクトのデータが自動的に保存される場合、保存されたデータとオブジェクトの現在の構造との互換性を制御するメカニズムが必要です。 つまり クラスのフィールドを追加または削除し、フィールドの順序またはタイプを変更した場合、データを復元するときに、保存されたデータが意図されている場所に移動する必要があります。
このような互換性制御メカニズムが存在します。 保存時に、ライブラリは使用中のクラスのコードを自動的に計算します。このクラスは状態を記述し、復元時に、オブジェクトが以前に保存されたデータと互換性があるかどうかをチェックします。 フィールドが復元されたクラスに追加された場合、またはそれらの順序が変更された場合、保存されたコピーからデータを復元できますが、フィールドが削除された場合、またはタイプが変更された場合、そのようなデータを復元することはできず、そのようなオブジェクトを読み取ろうとするとエラーがスローされます
クラスの状態を記述するコードは、オブジェクトの保存時に自動的に計算できますが、クラスが将来変更される予定がない場合、またはこのチェックメカニズムを無効にする場合は、特別なクラスフィールドを使用できます。
class DataClass : Serializable { companion object { const private val serialVersionUID = 1L } }
このフィールドは、クラスで記述されたLong
型の静的定数でなければなりません。
Kotlinの場合、この定数は@JvmStatic
アノテーションまたはconst
修飾子を使用して記述する必要があります。そうしないと、ロードライブラリはそれを@JvmStatic
ません。
データを復元するとき、ストリームからのコードの値は、保存時に目的のクラスによって定数として計算または書き込まれた値とチェックされ、これらの値が一致しない場合、エラーで例外がスローされます。
serialVersionUID
フィールドのアクセスタイプは何の役割も果たさず、パブリックでも非表示でもかまいません。
クラスが最終的な形を取り、その変更が計画されなくなった後、ロードおよび保存のたびにその計算を回避するために、クラスにこの定数を記述することをお勧めします。 この定数の値は、クラスの実際の状態を反映できます。ライブラリメソッドを使用して計算するか、クラスが重要でない場合は任意の値を含める必要があります。
クラス状態値を計算するには、Java «serialver»
ユーティリティを使用できますが、使用する«serialver»
は不便です。そのため、この値をプログラムで取得する方がはるかに簡単です。 これを行うには、必要なクラスを使用するプログラムで、メソッドを呼び出してその状態を計算し、取得した値をserialVersionUID
フィールドに設定します。
fun Action() { println( "ID: %d\n", ObjectStreamClass.lookup(DataClass::class.java).serialVersionUID ) //… }
プログラム出力:
ID: 991989581060349712
保存データ管理
多くの場合、オブジェクトに存在するすべてのデータを保存および復元する必要はなく、それらの一部のみを保存するか、実際のタイプに対応しない形式で復元する必要があります。
最初の制御オプションは例外メカニズムです。
処理済みリストから一部のフィールドを除外するには、特別なタイプの「transient」でマークする必要があります。 Javaではこれに特別なキーワードが使用され、 Kotlin
特別な注釈を使用する必要があります。
class DataClass : Serializable { @JvmField var strField = "" @JvmField var intField = 0 @Transient @JvmField var dbField = 0.0 }
このクラスのオブジェクトを処理するとき、シリアル化ライブラリは「 dbField
」フィールドの値を保存も復元もしません。 他のすべてのフィールドは通常どおり保存および復元されます。
このメカニズムは、値が意味をなさない、または保存できないフィールドオブジェクトの場合に使用すると便利です。
プログラマは、ロード後に自動的に処理されないフィールドの値を設定する必要があります。 これを行うには、以下で説明する「 readResolve
」メソッドを使用できます。
ストレージを管理する2番目の方法は、保存およびロードに使用されるフィールドの名前とタイプを指定できることです。
オブジェクトを開発するとき、オブジェクトの形式がすでに完全に変更されていても、その内容を復元する機能が必要になる場合があります。 これを行うには、クラスに含まれていないフィールドや名前が変更されたフィールドを読み取ることができる必要があります。 これは、フィールドフィルタリングメカニズムを使用して、 serialPersistentFields
という静的定数を記述することで実行できます。
open class DataClass(s : String) : Serializable { @JvmField var strField = "" @JvmField var intField = 0 @JvmField var dbField = 0.0 companion object { const private val serialVersionUID1 = 1L @JvmStatic val serialPersistentFields = arrayOf( ObjectStreamField("strField",String::class.java), ObjectStreamField("intField",Int::class.java) ) } init { strField = s + ":baseText" intField = s.hashCode() dbField = s.hashCode().toDouble() / 1000 } fun print() = outn("str = [%s]\nint = [%d]\ndb = [%f]", strField, intField, dbField) } fun Action() { val a = DataClass("dataA") outn("Saved contents:") a.print() Holder(ObjectOutputStream(File("out.bin").outputStream())).h.writeObject(a) val b = Holder(ObjectInputStream(File("out.bin").inputStream())).h.readObject() if (b is DataClass) { outn("Loaded contents:") b.print() } }
この例では、使用可能な3つのフィールドのうち2つのみを保存します。
Saved contents: str = [dataA:baseText] int = [95356375] db = [95356,375000] Loaded contents: str = [dataA:baseText] int = [95356375] db = [0,000000]
データの手動バックアップとリカバリ
場合によっては、自動ツールがエラーなしで機能するように、構造または構造の変更を説明できないことがあります。 この場合、クラスフィールドの値を手動で保存または復元する必要がありますが、自動化ツールによって提供されるすべての利点を失いたくないでしょう。
フィールドの1つで、フィールドの1つの名前が変更され、同時に確認する必要があるとします
新しい名前と古い名前の両方でデータをロードします。 自動化ツールはこのような変更に対応できませんが、オブジェクトのフィールドを手動で操作できます。 シリアライズ可能なオブジェクトは、その内容をロードおよび保存するために呼び出されるwriteObject
およびreadObject
関数を記述することができwriteObject
。
open class DataClass(s : String) : Serializable { @JvmField var strField = "" @JvmField var intFieldChanged = 0 @JvmField var dbField = 0.0 companion object { const private val serialVersionUID1 = 1L @JvmStatic val serialPersistentFields = arrayOf( ObjectStreamField("strField", String::class.java), ObjectStreamField("intField", Int::class.java) ) } init { strField = s + ":baseText" intFieldChanged = s.hashCode() dbField = s.hashCode().toDouble() / 1000 } fun print() = outn("str = [%s]\nint = [%d]\ndb = [%f]", strField, intFieldChanged, dbField) private fun readObject(s : ObjectInputStream) { val fields = s.readFields() strField = fields.get("strField", "" as Any?) as String intFieldChanged = fields.get("intField", 0) } private fun writeObject(s : ObjectOutputStream) { val fields = s.putFields() fields.put("strField", strField as Any?) fields.put("intField", intFieldChanged) s.writeFields() } }
この例では、クラスフィールドの名前はintFieldChanged
になりましたが、保存されたデータでは、その名前は引き続きintField
として表示されintField
。これにより、古い名前で保存されたデータをロードし、古いクラスがロードできるように保存できます。
writeObject
およびreadObject
のテキストでは、データを保存およびロードするための任意のロジックを実装できます。
上記の例で実装されているライブラリが提供するメカニズムを使用することも、オブジェクトの保存と復元を完全に手動で実装することもできます。 確かに、後者の場合、例で実装されているように、保持される構造の連続性を確保することは困難ですが、多くの場合、そのような必要性はありません。 手動でデータを操作する場合、データが保存された順序と同じ順序で復元されるようにする必要があります。
open class DataClass(s : String) : Serializable { @JvmField var strField = "" @JvmField var intField = 0 companion object { const private val serialVersionUID1 = 1L } init { strField = s + ":baseText" intField = s.hashCode() } fun print() = outn("str = [%s]\nint = [%d]", strField, intField) private fun readObject(s : ObjectInputStream) { strField = s.readUTF() intField = s.readInt() } private fun writeObject(s : ObjectOutputStream) { s.writeUTF(strField) s.writeInt(intField) } }
シングルトン回復
データを復元すると、ライブラリはオブジェクトへのリンクを自動的に復元しますが、これは単一のコピーに存在するオブジェクトを操作するには不十分です。 ロードすると、1つですが、新しいオブジェクトが作成されますが、ロードされた要素はプログラム内の既存の要素を参照する必要があります。
この動作も確認できます。
このためには、一意性を提供するクラスがreadResolve
メソッドを作成するだけで十分です。 このメソッドは、このクラスのオブジェクトをロードした後に呼び出され、別のオブジェクトに置き換えることができます。
class LinkedData private constructor(@JvmField val value : Int) : Serializable { companion object { @JvmField val ZERO = LinkedData(0) @JvmField val NONZERO = LinkedData(1) @JvmStatic fun make(v : Int) = if (v == 0) ZERO else NONZERO } private fun readResolve() : Any = if ( value == 0 ) ZERO else NONZERO } open class DataClass(v : Int) : Serializable { @JvmField val link = LinkedData.make(v) @JvmField var intField = v companion object { const private val serialVersionUID1 = 1L } fun print() = outn("int = [%d]\nlink = [%s]", intField, if (link == LinkedData.ZERO) "ZERO" else if (link == LinkedData.NONZERO) "NONZERO" else "OTHER!" ) }
:
Saved contents: int = [100] link = [NONZERO] Loaded contents: int = [100] link = [NONZERO]
, LinkedData
readResolve
, , .
, .
,
, , (), .
ObjectInputStream
ObjectOutputStream
annotateClass
annotateProxyClass
.
, .
短所
, Serializable
, , .
.
, , . , . , .
,
XML
, .. . Serializable
, .
, , .
, JSON
, .
– .
- , , .
: Serializable !
, .
, «» , , , . , , .
Externalizable
, Java – Externalizable
.
ObjectInput
ObjectOutput
Serializable
, , , .
readExternal
writeExternal
, .
Serializable
, Externalizable
, . , , .
Serializable
Externalizable
, .
. . readResolve
, , .
Externalizable
:
, .
, , . .
, .
, , .
- , .
class LinkedData private constructor(@JvmField val value : Int) { companion object { @JvmField val ZERO = LinkedData(0) @JvmField val NONZERO = LinkedData(1) @JvmStatic fun make(v : Int) = if (v == 0) ZERO else NONZERO } } open class DataClass : Externalizable { @JvmField var link : LinkedData @JvmField var intField : Int constructor() { link = LinkedData.ZERO; intField = 0 } constructor(v : Int) { link = LinkedData.make(v); intField = v } fun print() = outn("int = [%d]\nlink = [%s]", intField, if (link == LinkedData.ZERO) "ZERO" else if (link == LinkedData.NONZERO) "NONZERO" else "OTHER!") override fun readExternal(s : ObjectInput) { link = if ( s.readByte().toInt() == 0 ) LinkedData.ZERO else LinkedData.NONZERO intField = s.readInt() } override fun writeExternal(s : ObjectOutput) { s.writeByte(if(link == LinkedData.ZERO) 0 else 1) s.writeInt(intField) } }
link
.. . link
.
, , , . , .
«DataClass» , .
特徴
Externalizable
, , .
, , , Serializable
.
, , . , , , .
, Externalizable
, , , , - .
, , , , , , . - , .
, , ObjectStream
, . , .
, , , , , Serialilzable
. , .
, , , , , , . , .
,
.. , , . , , .
, , .
:
0) <noname> addCaller.t_ForOrGetPut org.sun.NotNotEmptyGetEach( SetEmptyCombineSplit ) 1) fNotRandom addCaller.For(void, addCaller.t_HasEmpty Has, addCaller.t_Combine GetCombineHas ) 2) fOrSet app.PutHasForGet( app.t_Set HasCombineAdd, app.t_ForNotOrAdd Combine ) 3) fHasSplit org.sun.Set( Set, sec.sun.t_JoinEmptyHasCombineCombine EmptyCombineOr ) 4) fJoinEach sec.sun.t_OrForEmptySet sec.sun.EachPutOrNot( org.sun.t_Combine SetHasSplitJoinEmpty, void ) 5) fEachSet org.sun.t_RandomSplit app.OrIsFor( sec.sun.t_Set CombineGetRandom, void ) 6) <noname> app.t_NotSetForForGet sun.NotHasForSplitAdd( org.sun.t_IsRandomOrHas Each, void) 7) fNotSplit addCaller.t_NotAdd sec.sun.IsHasNot( app.t_HasForSplitHas ForGet, void ) 8) <noname> sun.SetForSplitSet( PutCombine, void, void ) 9) fCombineNot sun.t_SplitRandomGetRandom sun.AddAdd( void, org.sun.t_NotRandomHasEmpty AddPutNotSplit ) 10) <noname> addCaller.t_ForIs sun.EachIs( NotFor, void, void, PutSplitAddNot ) 11) fSetOr app.HasJoin( OrOr, void, void, addCaller.t_NotAddHas Each )
, .
, <noname>
void
, .
, , .. , . , , , .
:
SerialFull
—Serializable
.
Extern+Ser
—Externalizable
, .
ExternFull
—Externalizable
.
JsJsonMini
— «minimal-json»,JSON
.
minimal-json-0.9.4.jar
, : https://github.com/ralfstx/minimal-json .
fasterXML-jackson
JSON
.
2.0.4
, : https://github.com/FasterXML/jackson . . (JsJackAnn
), , ,annotations-databind
. (JsJackSream
) ,stream
.
- Java
XML
«org.w3c.dom.Document
org.w3c.dom.Element
.
.
役職 | バージョン | 出所 | |
---|---|---|---|
XML, Serializable, Externalizable | Java 1.8 | Java | , Java. |
minimal-json | 0.9.4 | https://github.com/ralfstx/minimal-json | minimal-json-0.9.4.jar – 30 |
fasterXML-jackson | 2.0.4 | https://github.com/FasterXML/jackson | jackson-core-2.0.4.jar – 194, jackson-databind-2.0.4.jar – 847, jackson-annotations-2.0.4.jar – 34 |
, , .
:
USAGE: SerializableTest.jar [-opts] Where OPTS are: -Count=<number> - set number of items to generate -Retry=<number> - set number of iterations for each test -Out=<file> - set file name to output -Nout - disable items output -gc - run gc after every test
:
- .
- .
- , , .
- .
- , .
なぜなら , . , , , .
結果
JVM , , .
>sb -n "-c=100000" "-r=10" Output file : test_out Number of elements: 100000 Number of retries : 10 Tests complete in 0:01:28.050 sec :: Save 0:00:31.903, Load 0:00:30.149, Total 0:01:02.103, Waste 0:00:25.947
100.000 , 10 . 1 28
, 25.9
.
場所 | 名 | 読み込み中 | 合計 | ファイル | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
6 | SerialFull | 0:00:07.599 | 2,34 | 0:00:04.217 | 1,05 | 1,45 | 0:00:11.826 | 1,56 | 0,41 | 18 | |
1 | ExternFull | 0:00:02.550 | 0.12 | 1,98 | 0:00:02.061 | 4,02 | 0:00:04.616 | 2,60 | 16 | ||
5 | Extern+Ser | 0:00:05.744 | 1,52 | 0,32 | 0:00:04.112 | 1,00 | 1,51 | 0:00:09.862 | 1,14 | 0,69 | 22.5 |
7 | XMLw3c | 0:00:06.278 | 1,76 | 0,21 | 0:00:10.337 | 4,02 | 0:00:16.620 | 2,60 | 32 | ||
4 | JsJsonMini | 0:00:04.678 | 1,05 | 0,62 | 0:00:04.614 | 1,24 | 1,24 | 0:00:09.302 | 1,02 | 0,79 | 25.9 |
3 | JsJackAnn | 0:00:02.776 | 0.22 | 1.74 | 0:00:02.431 | 0,18 | 3,25 | 0:00:05.215 | 0,13 | 2,19 | 25.9 |
2 | JsJackSream | 0:00:02.278 | 2,34 | 0:00:02.377 | 0,15 | 3,35 | 0:00:04.662 | 0,01 | 2,56 | 25.9 |
.
-
«»
, . -
«»
. -
«»
,«»
«»
, , . -
«»
«»
,«»
. - .
-
«»
, .
コメント
シリアライズ可能
.
. , , , .
, , — . , , .
Externalizable
.
, . ( Extern+Ser
) , . .
.. , , .
, , .
Java , - (, , ), . , Java – EOF
, , .
.. JSON
, .
minimal-json
, .
, . , . .
– , , .
. , JSON
. , , , .
fasterXML-jackson databind
, , .
, .
, , . , Serializable
, , .
, . . , , , .
JavaDOC
, .. , .
, , . , , . – , .
, :
.
JSON
, .
- .
, , .. .
, , , , , , .
fasterXML-jackson stream
JSON
.
.
, JSON
, . , JSON
. , .
, , .
jackson-core
, 200, 4 databind
.
, , .
XML
.
, . 400.000 - , 5 JVM
.
, . fasterXML-jackson
stream
.. , , .
, , , . .