前回のLZでは、HashMap、Hashtable、TreeMapの実装方法をデータ構造、実装原理、ソース解析の3つの側面から詳しく説明しました。
: 推奨読書: java改善の章(23) - hashmap
javaの増加の章(25) - -Hashtable
Java改善の章(26)-----hashCode
Java改善の章(27)--TreeMap
1. マップの概要
まず Map の構造図を見てください
Map:
「キーと値」マッピングの抽象インターフェイス。マップには重複キーは含まれておらず、1 つのキーが 1 つの値に対応します。 SortedMap:
Map インターフェースを継承する、順序付けされたキーと値のペアのインターフェース。 NavigableMap:
SortedMap を継承し、指定された検索ターゲットに最も近い一致のナビゲーション メソッドを返すインターフェイスを持ちます。 AbstractMap:
は、Map の関数インターフェイスのほとんどを実装します。 「Map実装クラス」の繰り返しコーディングを軽減します。 Dictionary:
キーを対応する値にマップするクラスの抽象親クラス。現在は Map インターフェイスに置き換えられています。 TreeMap:
順序付けされたハッシュ テーブルは、SortedMap インターフェイスを実装し、最下層は赤黒ツリーを通じて実装されます。 HashMap:
は、「ジッパーメソッド」に基づくハッシュテーブルです。最下層は「配列+リンクリスト」を使って実装されています。 WeakHashMap:
「ジッパーメソッド」に基づくハッシュテーブル。 HashTable:
「ジッパーメソッド」に基づくハッシュテーブル。 要約は次のとおりです:
それらの違い:
2. 内部ハッシュ: ハッシュ マッピング テクノロジー
ほぼすべての一般的なマップはハッシュ マッピング テクノロジーを使用します。私たちプログラマーはそれを理解する必要があります。
ハッシュ マッピング テクノロジーは、要素を配列にマッピングする非常にシンプルなテクノロジーです。ハッシュ マップは配列の結果を使用するため、任意のキーによる配列へのアクセスを決定するためのインデックス付けメカニズムが必要です。このメカニズムをハッシュ関数と呼びます。 Java では、そのような整数を見つけることについて心配する必要はありません。すべてのオブジェクトには整数値を返す hashCode メソッドが必要であり、必要なのはそれを整数に変換し、その値を配列で除算することだけです。サイズから余りを取り出します。以下の通り:
int hashValue = Maths.abs(obj.hashCode()) % size;
以下は HashMap と HashTable です:
----------HashMap------------ //计算hash值 static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } //计算key的索引位置 static int indexFor(int h, int length) { return h & (length-1); } -----HashTable-------------- int index = (hash & 0x7FFFFFFF) % tab.length; //确认该key的索引位置
位置のインデックスは、配列内のノードの位置を表します。次の図は、ハッシュ マップの基本原理図です:
この図では、ステップ 1 ~ 4 は配列内の要素の位置を見つけること、ステップ 5 ~ 8 は配列内の要素の位置を見つけることです。要素を配列に追加します。挿入プロセス中に少しイライラすることがあります。同じハッシュ値を持つ複数の要素が存在する可能性があるため、それらは同じインデックス位置を取得します。これは、複数の要素が同じ位置にマッピングされることを意味します。このプロセスは「競合」と呼ばれます。競合を解決する方法は、インデックス位置にリンク リストを挿入し、このリンク リストに要素を追加するだけです。もちろん単純な挿入ではなく、インデックス位置のリンクリストを取得し、そうでない場合はその要素を直接挿入します。キーと同じである場合は、元のキーの値を上書きして古い値を返します。それ以外の場合、要素はチェーンの先頭に保存されます (最初に保存された要素はチェーンの最後に配置されます)。 。以下は HashMap の put メソッドで、インデックス位置を計算し、要素を適切な位置に挿入するプロセス全体を詳細に示しています:
public V put(K key, V value) { //当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因 if (key == null) return putForNullKey(value); //计算key的hash值 int hash = hash(key.hashCode()); //计算key hash 值在 table 数组中的位置 int i = indexFor(hash, table.length); //从i出开始迭代 e,判断是否存在相同的key for (Entry<K, V> e = table[i]; e != null; e = e.next) { Object k; //判断该条链上是否有hash值相同的(key相同) //若存在相同,则直接覆盖value,返回旧value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; //旧值 = 新值 e.value = value; e.recordAccess(this); return oldValue; //返回旧值 } } //修改次数增加1 modCount++; //将key、value添加至i位置处 addEntry(hash, key, value, i); return null; }
HashMap の put メソッドは、次の基本的な考え方を示しています。実際、他のマップを見ると、原則が似ていることがわかります。
3. マップの最適化
まず第一に、ハッシュマップの内部配列のサイズは 1 のみであり、すべての要素がこの位置 (0) にマッピングされると仮定します。より長いリンクリストを形成します。更新時やアクセス時にはこのリンクリストに対して線形探索を行う必要があるため、必然的に効率が悪くなってしまいます。非常に大きな配列があり、リンクされたリストの各位置に要素が 1 つしかない場合、アクセス時にインデックス値を計算してオブジェクトが取得されると想定します。これにより検索の効率は向上しますが、無駄が生じます。コントロール。確かに、これら 2 つの方法は極端ではありますが、最適化のアイデアを提供します。 要素が均等に分散されるように、より大きな配列を使用します。 Map には効率に影響する 2 つの要素があります。1 つはコンテナーの初期サイズで、もう 1 つは負荷率です。 3.1は、実装サイズを調整します。マップのサイズを調整できるようになります。マップ内の要素が一定量に達すると、コンテナ自体のサイズが変更されることはわかっていますが、このサイズ変更プロセスは非常にコストがかかります。サイズを変更するには、元の要素をすべて新しい配列に挿入する必要があります。インデックス = ハッシュ(キー) % の長さはわかっています。これにより、元の競合しているキーが競合しなくなり、競合していないキーが競合するようになる可能性があります。再計算、調整、挿入のプロセスは非常にコストがかかり、非効率的です。したがって、マップの予想されるサイズ値を把握し始めて、マップのサイズを十分に大きくすると、サイズ変更の必要性を大幅に削減、または排除することができ、速度が向上する可能性が高くなります。
以下は、HashMap がコンテナー サイズを調整するプロセスです。次のコードを通して、その拡張プロセスの複雑さを確認できます。void resize(int newCapacity) { Entry[] oldTable = table; //原始容器 int oldCapacity = oldTable.length; //原始容器大小 if (oldCapacity == MAXIMUM_CAPACITY) { //是否超过最大值:1073741824 threshold = Integer.MAX_VALUE; return; } //新的数组:大小为 oldCapacity * 2 Entry[] newTable = new Entry[newCapacity]; transfer(newTable, initHashSeedAsNeeded(newCapacity)); table = newTable; /* * 重新计算阀值 = newCapacity * loadFactor > MAXIMUM_CAPACITY + 1 ? * newCapacity * loadFactor :MAXIMUM_CAPACITY + 1 */ threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); } //将元素插入到新数组中 void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }
3.2、负载因子
为了确认何时需要调整Map容器,Map使用了一个额外的参数并且粗略计算存储容器的密度。在Map调整大小之前,使用”负载因子”来指示Map将会承担的“负载量”,也就是它的负载程度,当容器中元素的数量达到了这个“负载量”,则Map将会进行扩容操作。负载因子、容量、Map大小之间的关系如下:负载因子 * 容量 > map大小 ----->调整Map大小。
例如:如果负载因子大小为0.75(HashMap的默认值),默认容量为11,则 11 * 0.75 = 8.25 = 8,所以当我们容器中插入第八个元素的时候,Map就会调整大小。
负载因子本身就是在控件和时间之间的折衷。当我使用较小的负载因子时,虽然降低了冲突的可能性,使得单个链表的长度减小了,加快了访问和更新的速度,但是它占用了更多的控件,使得数组中的大部分控件没有得到利用,元素分布比较稀疏,同时由于Map频繁的调整大小,可能会降低性能。但是如果负载因子过大,会使得元素分布比较紧凑,导致产生冲突的可能性加大,从而访问、更新速度较慢。所以我们一般推荐不更改负载因子的值,采用默认值0.75.
最后
推荐阅读:
java提高篇(二三)—–HashMap
java提高篇(二五)—–HashTable
Java提高篇(二六)-----hashCode
Java提高篇(二七)—–TreeMap
以上就是Java提高篇(三三)-----Map总结的内容,更多相关内容请关注PHP中文网(www.php.cn)!

javaachievesplatformentenceTheTheTheJavavirtualMachine(JVM)、CodetorunondifferentoperatingSystemswithOutModification.thejvmcompilesjavacodeplatform-IndopentedbyTecodeを承認することを許可します

javaispowerfulfulduetoitsplatformindepentence、object-orientednature、richstandardlibrary、performancecapability、andstrongsecurityfeatures.1)platformendependenceallowseplicationStorunonaydevicesupportingjava.2)オブジェクト指向のプログラマン型

上位のJava関数には、次のものが含まれます。1)オブジェクト指向プログラミング、サポートポリ型、コードの柔軟性と保守性の向上。 2)例外処理メカニズム、トライキャッチ式ブロックによるコードの堅牢性の向上。 3)ゴミ収集、メモリ管理の簡素化。 4)ジェネリック、タイプの安全性の向上。 5)コードをより簡潔で表現力豊かにするためのAMBDAの表現と機能的なプログラミング。 6)最適化されたデータ構造とアルゴリズムを提供するリッチ標準ライブラリ。

javaisnotentirelylylyplatformedent dueTojvmvariations andNativeCodeIntegration、ButlargelyHoldSitsworapromise.1)JavacompilestobyteCoderunbythejvm、Cross-Platformexecution.2を許可します

thejavavirtualmachine(jvm)isanabstractcomputingmachineculucialforjavaexecutionsiTrunsjavabytecode、「writeonce、runaynay "capability

JavaremainsagoodlanguagedueToitscontinuousevolution androbustecosystem.1)lambdaexpressionsenhancecodereadability andenableFunctionalprogramming.2)streamsalowsolowsolfisitydataprocessing、特に特にlagedatasets.3)硬化系系統系系統系系統系系統

Javaisgreatduetoitsplatformindependence、robustoopsupport、extensiveLibraries、andstrongCommunity.1)PlatformentepenteviajvMallowsCodeTorunonVariousPlatforms.2)oopeatureSlikeEncapsulation、遺伝、およびポリモ系系統型皮下皮質皮下Rich

Javaの5つの主要な特徴は、多型、Lambda Expressions、StreamSapi、ジェネリック、例外処理です。 1。多型により、さまざまなクラスのオブジェクトを一般的なベースクラスのオブジェクトとして使用できます。 2。Lambda式は、コードをより簡潔にし、特にコレクションやストリームの処理に適しています。 3.ストリームサピは、大規模なデータセットを効率的に処理し、宣言操作をサポートします。 4.ジェネリックは、タイプの安全性と再利用性を提供し、型刻印中にタイプエラーがキャッチされます。 5.例外処理は、エラーをエレガントに処理し、信頼できるソフトウェアを作成するのに役立ちます。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

メモ帳++7.3.1
使いやすく無料のコードエディター

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。
