Javaにおけるmap内部記憶方式の解析
Map、つまりマッピングして、キーパッドのペアとも称して、1つのKeyがあって、1つのValue。
例えばGrouvy言語では、 def map=''name'''liudehua'、'age':50'ではmap['name'] の値は'liudehua'です。
では、Mapの内部メモリはどうやって実現されますか? これからゆっくり説明します
一、ファスナー式で保管する
これはJavaの中のHashMapを例にとって説明します。 HashMapの内部には配列Entry[]があります。 テーブル、この配列はデータを保存するものです。
Entry類の定義は大体次の通りです。
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メソッドを遍歴します。詳しくはなどです。みなさんの応援に感謝します。
例えば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メソッドを遍歴します。詳しくはなどです。みなさんの応援に感謝します。