Javaにおけるmap内部記憶方式の解析

3919 ワード

Map、つまりマッピングして、キーパッドのペアとも称して、1つのKeyがあって、1つのValue。
例えばGrouvy言語では、  def  map=''name'''liudehua'、'age':50'ではmap['name']  の値は'liudehua'です。
では、Mapの内部メモリはどうやって実現されますか?   これからゆっくり説明します
一、ファスナー式で保管する
これはJavaの中のHashMapを例にとって説明します。   HashMapの内部には配列Entry[]があります。  テーブル、この配列はデータを保存するものです。
Entry類の定義は大体次の通りです。

class Entry {
Object key
Object value
Entry next;
}
ですから、Entry[]  テーブル  の各要素はチェーンテーブルであり、つまりハーシェルMapの内部記憶は配列+チェーンテーブルであり、ファスナー式記憶装置である。
HaspMapにput(key、  データの場合は、先に行います。  key.hashCode()  &  (table.length()-1)を得て、table.length()より小さい値を得て、indexと呼ぶと、この新しいEntryはtable[index]のチェーンに属します。  そして始まる前から  table[index]このチェーン表は、key.equals(entry.key)なら、このkeyがすでに古い値があるという意味で、valueの値を置き換えればいいです。
さもなくば、この新しいEntryをtable[index]チェーンの一番前に挿入します。
以上はHashMapの保存方法を紹介しました。また、hashMapのKeyとして、hashCode()とequals()の方法が使われています。
二、配列記憶
1.分散された配列記憶
これはThreadLocalで  とThreadLocal.Values  例をあげて説明します。Valuesクラスには二つの変数があります。Object[]  テーブル、マスター、テーブルはデータを格納する配列です。テーブルの長さは2の倍数です。  markの値は  テーブル.length-1  この点はHashMapの内部記憶と似ています。  でも、テーブルの中の要素は全部チェーンではないです。
質が行く  Valuesでputを行う場合は、まずkey.hashCode&markを行い、table.lengthより小さい値を得て、indexといいます。その後、table[index]の値をチェックします。存在しない場合は、table[index]にkey,table[index]を入れます。既に存在していて、かつkey.equals(oldKey)が成立しない場合、すなわち衝突が発生した場合、index=index+2(ここは+2で、keyのため、value二つは隣に置いてあり、一つの要素は二つの穴を占めている)。次の場所を探してみて、もしまた衝突したら、挿入できるところを見つけて、table[index]=key、table[index+1]=valueを探します。 
二つの注意事項があります。
key.hashCode()は2の倍数でなければなりません。indexの値は奇数である可能性があります。  ThreadLocal.hashというメンバー変数が参照できます。
テーブル内部のデータは分散して保存されています。
2.連続配列記憶
これはAndroidに追加されたArayMapを例に分析しています。  ArayMapには2つの主要変数があります。int[]  mhashes,Object[]  mArays.
mhashesは主にkeyのhash値を保管しています。mAraysはデータを保存するために使われています。また、奇数の保存keyです。偶数はvalue、key、valueの順に並べられています。  mAraysの長さはmhashesの2倍です。何しろmAraysはkeyです。valueは全部預けます。
mhashesにkeyを格納するhash値は、小さい時から大きな順に並べられています。複数のkeyのhash値が同じであれば、その順に並べられます。
ArayMapにputを行うときは、まずsh=key.hashCodeをintして、mhashesでhashの位置を二分検索します。(中にあれば、戻ってきます。なしであれば、一番近い位置を見つけてから、逆を取って返します。)  indexは、index>0なら、mAraysの中の2*indexでkey値を取得し、2つのkeyがequals()であるかどうかを比較し、等しくない場合は、それぞれ上に、下に向かって、近くの同じhash値のkeyを調べ、equals()のkeyがあるかどうかを確認します。    index<0は、以前に同じhashのkeyが挿入されていないことを示しています。index=~index(もう一回反を取ると、正の数になります。挿入する位置を代行します。)をmhashesのindexにshを挿入し、mAraysの2*indexにkeyを挿入します。(2*index)+1にvalue.を挿入します。
注意:
mhashesとmAraysは新しいデータを挿入する時、挿入位置の後ろのデータを一つの単位に後ろに移動します。これは頻繁に挿入、削除する動作にとって消耗が大きいです。
keyのhashサイズは挿入の順番を決めています。
3.数字をkeyとする配列保存
このようなmapは特殊で、keyは数字のタイプです。  これはAndroidに追加されたSparseArayで分析される。SparseArayには2つの主要変数があります。int[]  mKeys  和  Object[]  mValues、mKeysはkeyを保存するので、秩序正しい配列で、小さいから大きいまで並べます。  mValuesはmKeysに対応するvalue値の集合です。   mKeysとmValuesの長さは同じです。
質が行く  SparseArayでput(key,value)をする時、まずmKeysの中でkeyの位置を二分で探します。見つかっていない場合は、挿入すべき位置を見つけて、逆を取って返します。index、index>0と記入したら、そのままmValues[index]でvalueを置換します。index<0ならindex=~index、つまり逆を取って、mKeysのindexのところにkeyを挿入して、mValues[index]のところにvalueを挿入して、前のデータはindexのところから一つの単位を移動します。
注意:
mKeysとmAraysのデータを挿入する時、データ移動を行います。頻繁に挿入、削除するmapにとって消耗が大きいです。
最後に、彼らの長所と短所を比較します。
HashMap:メモリの占有率はわりに大きくて、増加、削除の効率はわりに高くて、改正、調査の効率は普通です。
ThreadLocal.Values:  メモリの占有は普通で、データ量が比較的に小さい時、添削して調べる効率は高いです。データ量が大きい時、添削して調べる効率は普通です。
ArayMap:メモリの占有率はより小さくて、修正、検索の効率は高くて、増加、削除の効率はより低いです。
SparseAray:メモリの占有率が小さいので、修正、検索の効率が高く、増加、削除の効率が低いです。そして、メインキーは数字です。
締め括りをつける
私たちはどのような保存方法がいいかを判断しません。すべては実際の状況で分析し、最適な保存方法を見つけます。皆さんのためになりたいです。興味のある友達はJavabeanとmapの相互変換方法コード例を参照してください。  話し相手とMapは互いに転化します。  Struts 2 ONLを使用してMapメソッドを遍歴します。詳しくはなどです。みなさんの応援に感謝します。