Java中Map接口的解析

<div class="blog-content-box">
    <div class="article-header-box">
        <div class="article-header">
            <div class="article-title-box">
                <span class="article-type type-1 float-left">原创</span>                <h1 class="title-article">Java中Map接口的解析</h1>
            </div>
            <div class="article-info-box">
                <div class="article-bar-top" style="height: 24px;">
                                            <span class="c-gray">置顶</span>
                                                                                                                                                                <span class="time">2018-11-26 15:56:29</span>
                    <a class="follow-nickName" href="https://me.csdn.net/jiguquan3839" target="_blank" rel="noopener">IT刘华强</a>
                    <span class="read-count">阅读数 1594</span><span class="article_info_click" style="position: static;">更多</span>
                                                                                                                <div class="tags-box space">
                                <span class="label">分类专栏:</span>
                                                                                                            <a class="tag-link" target="_blank" rel="noopener" href="https://blog.csdn.net/jiguquan3839/article/category/8112688">
                                            Java                                        </a>
                                                                                                </div>
                                        </div>
                <div class="operating">
                                    </div>
            </div>
        </div>
    </div>
    <article class="baidu_pl">
                <div id="article_content" class="article_content clearfix">
                                                <div class="article-copyright">
                <span class="creativecommons">
                <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
                    </a>
            <span>
                版权声明:本文为博主原创文章,遵循<a href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="noopener"> CC 4.0 BY-SA </a>版权协议,转载请附上原文出处链接和本声明。            </span>
               <div class="article-source-link2222">
                    本文链接:<a href="https://blog.csdn.net/jiguquan3839/article/details/84546835">https://blog.csdn.net/jiguquan3839/article/details/84546835</a>
                </div>
            </span>
                    </div>
                                                    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
                                        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
                <div class="htmledit_views" id="content_views">
                                            <h1 style="margin-left:0cm;"><a name="t0"></a>Map详解:</h1>

<p style="text-indent:50px;">先看图,便于宏观了解Map的地位。</p>

<p style="text-indent:50px;"><img alt="" class="has" height="320" src="https://img-blog.csdnimg.cn/20181126154547546.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="701"></p>

<p style="text-indent:50px;">Map接口中键和值一一映射. 可以通过键来获取值。</p>

<ul><li>给定一个键和一个值,你可以将该值存储在一个Map对象. 之后,你可以通过键来访问对应的值。</li>
	<li>当访问的值不存在的时候,方法就会抛出一个NoSuchElementException异常.</li>
	<li>当对象的类型和Map里元素类型不兼容的时候,就会抛出一个 ClassCastException异常。</li>
	<li>当在不允许使用Null对象的Map中使用Null对象,会抛出一个NullPointerException 异常。</li>
	<li>当尝试修改一个只读的Map时,会抛出一个UnsupportedOperationException异常。</li>
</ul><h2><a name="t1"></a>Map基本操作:</h2>

<p style="text-indent:50px;"><strong>Map </strong><strong>初始化</strong></p>

<p style="text-indent:50px;">Map&lt;String, String&gt; map = new HashMap&lt;String, String&gt;();</p>

<p style="text-indent:50px;"><a name="paragraph_1_4"></a><strong>插入元素</strong></p>

<p style="text-indent:50px;">map.put("key1", "value1");</p>

<p style="text-indent:50px;"><a name="paragraph_1_5"></a><strong>获取元素</strong></p>

<p style="text-indent:50px;">map.get("key1")</p>

<p style="text-indent:50px;"><a name="paragraph_1_6"></a><strong>移除元素</strong></p>

<p style="text-indent:50px;">map.remove("key1");</p>

<p style="text-indent:50px;"><a name="paragraph_1_7"></a><strong>清空</strong><strong>map</strong></p>

<p style="text-indent:50px;">map.clear();</p>

<h1 style="margin-left:0cm;"><a name="t2"></a>hashMap原理:</h1>

<p style="text-indent:50px;">hashMap是由数组和链表这两个结构来存储数据。</p>

<p style="text-indent:50px;">数组:存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);寻址容易,插入和删除困难;</p>

<p style="text-indent:50px;">链表:存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N);寻址困难,插入和删除容易。</p>

<p style="text-indent:50px;">hashMap则结合了两者的优点,既满足了寻址,又满足了操作,为什么呢?关键在于它的存储结构。</p>

<p style="text-indent:50px;">它底层是一个数组,数组元素就是一个链表形式,见下图:</p>

<p style="text-indent:50px;"><img alt="" class="has" height="362" src="https://img-blog.csdnimg.cn/20181126155122922.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="354"></p>

<p style="text-indent:50px;">Entry: 存储键值对。</p>

<p style="text-indent:50px;">Map类在设计时提供了一个静态修饰接口Entry。Entry将键值对的对应关系封装成了键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对对象中获取相应的键与值。之所以被修饰成静态是为了可以用类名直接调用。</p>

<p style="text-indent:50px;"><img alt="" class="has" height="152" src="https://img-blog.csdnimg.cn/20181126155143913.png" width="451"></p>

<p style="text-indent:50px;"><span style="color:#000000;">每次初始化</span><span style="color:#000000;">HashMap</span><span style="color:#000000;">都会构造一个</span><span style="color:#000000;">table</span><span style="color:#000000;">数组,而</span><span style="color:#000000;">table</span><span style="color:#000000;">数组的元素为</span><span style="color:#000000;">Entry</span><span style="color:#000000;">节点</span>,它里面包含了键<span style="color:#000000;">key</span><span style="color:#000000;">,值</span><span style="color:#000000;">value</span><span style="color:#000000;">,下一个节点</span><span style="color:#000000;">next</span><span style="color:#000000;">,以及</span><span style="color:#000000;">hash</span><span style="color:#000000;">值</span>。</p>

<pre class="has" name="code"><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Entry</span>&lt;<span class="hljs-title">K</span>,<span class="hljs-title">V</span>&gt; <span class="hljs-keyword">implements</span> <span class="hljs-title">Map</span>.<span class="hljs-title">Entry</span>&lt;<span class="hljs-title">K</span>,<span class="hljs-title">V</span>&gt; </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-keyword">final</span> K key;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        V value;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        Entry&lt;K,V&gt; next;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-keyword">int</span> hash;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="复制" onclick="hljs.copyCode(event)"></div></pre>

<p style="margin-left:0cm;">查看hashMap的API发现,它有4个构造函数:</p>

<p style="text-indent:50px;"><img alt="" class="has" height="206" src="https://img-blog.csdnimg.cn/20181126155232915.png" width="542"></p>

<p style="text-indent:50px;">1、构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。</p>

<p style="text-indent:50px;">2、指定初始容量和默认加载因子 (0.75) 的空 HashMap。</p>

<p style="text-indent:50px;">3、指定初始容量和默认加载因子的空HashMap。</p>

<p style="text-indent:50px;">4、构造一个映射关系与指定Map相同的新HashMap。</p>

<p style="text-indent:50px;">注意:<span style="color:#333333;">HashMap</span><span style="color:#333333;">使用的是懒加载,构造完</span><span style="color:#333333;">HashMap</span><span style="color:#333333;">对象后,只要不进行</span><span style="color:#333333;">put</span><span style="color:#333333;">方法插入元素之前,</span><span style="color:#333333;">HashMap</span><span style="color:#333333;">并不会去初始化或者扩容</span><span style="color:#333333;">table</span><span style="color:#333333;">。</span></p>

<h2 style="margin-left:0cm;"><a name="t3"></a>Put方法:</h2>

<p style="text-indent:50px;">首先判断是否是空数组(table == EMPTY_TABLE),如果是,开始初始化HashMap的table数据结构,然后执行扩容函数,如果未指定容量,默认是大小为16的表,然后根据加载因子计算临界值。什么是加载因子呢?hashMap的大小是一定的,如果不够存储了肯定要扩容,那么扩容的依据是什么呢,什么时候确定要扩容了呢?这个时候就需要引入加载因子这个概念,我们假使依旧使用默认大小16,加载因子0.75,那么当hashMap的size大于12(16*0.75=12)的时候,那么就会进行扩容。</p>

<p style="text-indent:50px;">回来说put方法,如果key是null,调用putForNullKey方法,保存null与key,这是HashMap允许为null的原因。然后计算hash值和用indexFor计算数据存在的位置,然后从i出开始迭代e,找到 key 保存的位置。</p>

<p style="text-indent:50px;"><img alt="" class="has" height="400" src="https://img-blog.csdnimg.cn/20181126155309461.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="482"></p>

<p style="text-indent:50px;"><img alt="" class="has" height="156" src="https://img-blog.csdnimg.cn/20181126155315154.png" width="554"></p>

<p style="text-indent:50px;">上面说到如果数组扩容,那么每次要怎么扩容呢?</p>

<p style="text-indent:50px;"><img alt="" class="has" height="215" src="https://img-blog.csdnimg.cn/20181126155330129.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="554"></p>

<p style="text-indent:50px;"><img alt="" class="has" height="244" src="https://img-blog.csdnimg.cn/20181126155334432.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="554"></p>

<p style="text-indent:50px;">当size大于等于某一个阈值thresholdde时候且该table并不是一个空table,因为size 已经大于等于阈值了,说明Entry数量较多,哈希冲突严重,那么若该Entry对应的桶不是一个空桶,这个Entry的加入必然会把原来的链表拉得更长,因此需要扩容;若对应的桶是一个空桶,那么此时没有必要扩容。如果扩容,table会扩容为原来的两倍,直到达到数组的最大长度1&lt;&lt;30(2的30次方),如果size大于这个值,那么就直接修改为Integer.MAX_VALUE。扩容后的元素hash值对应的新的桶位置,然后在指定的桶位置上,创建一个新的Entry。</p>

<p style="text-indent:50px;">这里需要说明的是,hashmap是可以存放key和value均为null的,存放在table[0]的位置,此时使用put方法在添加元素的时候,如果在table[0]中已经存入key为null的元素则给null赋上新的value值并返回后面的值,否则则初始化null的元素,存入put里面存放的值。</p>

<pre class="has" name="code"><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        HashMap hashMap = <span class="hljs-keyword">new</span> HashMap();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        hashMap.put(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        System.out.println(hashMap.get(<span class="hljs-keyword">null</span>));</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        Integer a = (Integer) hashMap.put(<span class="hljs-keyword">null</span>, <span class="hljs-number">1</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        System.out.println(a);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        System.out.println(hashMap.get(<span class="hljs-keyword">null</span>));</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"><span class="hljs-comment">/*</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">输出为:</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">null</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">null</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">1</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">*/</span></div></div></li></ol></code><div class="hljs-button {2}" data-title="复制" onclick="hljs.copyCode(event)"></div></pre>

<h2 style="margin-left:0cm;"><a name="t4"></a>Get方法:</h2>

<p style="text-indent:50px;"><img alt="" class="has" height="191" src="https://img-blog.csdnimg.cn/20181126155359166.png" width="538"></p>

<p style="margin-left:0cm;">Get比较好理解,判断key是不是null,如果是,返回getForNullKey的函数返回值,如果不是,则在table中去找。</p>

<p style="margin-left:0cm;">Remove方法:</p>

<p style="margin-left:0cm;">判断,如果hashMap的size是0,返回null;找到需要移除的元素的前一个节点,然后把前驱节点的next指向删除节点的next节点,此时当前节点没有任何引用指向,它在程序结束之后就会被gc回收。</p>

<pre class="has" name="code"><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">final</span> Entry&lt;K,V&gt; <span class="hljs-title">removeEntryForKey</span><span class="hljs-params">(Object key)</span> </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    		<span class="hljs-keyword">if</span> (size == <span class="hljs-number">0</span>) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    		    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    		}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">   		 <span class="hljs-keyword">int</span> hash = (key == <span class="hljs-keyword">null</span>) ? <span class="hljs-number">0</span> : hash(key);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">   		 <span class="hljs-keyword">int</span> i = indexFor(hash, table.length);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    		Entry&lt;K,V&gt; prev = table[i];</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    		Entry&lt;K,V&gt; e = prev;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">		 <span class="hljs-keyword">while</span> (e != <span class="hljs-keyword">null</span>) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        		Entry&lt;K,V&gt; next = e.next;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">       		 Object k;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">       		 <span class="hljs-keyword">if</span> (e.hash == hash &amp;&amp;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        		    ((k = e.key) == key || (key != <span class="hljs-keyword">null</span> &amp;&amp; key.equals(k)))) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        		    modCount++;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">         		   size--;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">         		   <span class="hljs-keyword">if</span> (prev == e)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">          		      table[i] = next;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">         		   <span class="hljs-keyword">else</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">          		      prev.next = next;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">          		  e.recordRemoval(<span class="hljs-keyword">this</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">         		   <span class="hljs-keyword">return</span> e;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        		}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="23"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        		prev = e;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="24"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        		e = next;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="25"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">   		 }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="26"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">		 <span class="hljs-keyword">return</span> e;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="27"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">	}</div></div></li></ol></code><div class="hljs-button {2}" data-title="复制" onclick="hljs.copyCode(event)"></div></pre>

<h2 style="margin-left:0cm;"><a name="t5"></a>Map的遍历:</h2>

<p style="text-indent:50px;">map这里可以用增强for和迭代器两种方式遍历:</p>

<pre class="has" name="code"><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span> java.util.HashMap;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span> java.util.Iterator;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span> java.util.Map;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MapDemo</span> </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        HashMap&lt;String, String&gt; sets = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        sets.put(<span class="hljs-string">"username"</span>, <span class="hljs-string">"value1"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        sets.put(<span class="hljs-string">"password"</span>, <span class="hljs-string">"value2"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        sets.put(<span class="hljs-string">"key3"</span>, <span class="hljs-string">"value3"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        sets.put(<span class="hljs-string">"key4"</span>, <span class="hljs-string">"value4"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        sets.put(<span class="hljs-keyword">null</span>,<span class="hljs-keyword">null</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-comment">// 增强for循环 =========== keySet ===================</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-keyword">for</span> (String s : sets.keySet()) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">            System.out.println(s + <span class="hljs-string">".."</span> + sets.get(s));</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-comment">//================== entrySet ======================</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-keyword">for</span> (Map.Entry&lt;String, String&gt; m : sets.entrySet()) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">            System.out.println(m.getKey() + <span class="hljs-string">".."</span> + m.getValue());</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-comment">// 迭代器 ================ keySet ===================</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        Iterator it = sets.keySet().iterator();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="23"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-keyword">while</span> (it.hasNext()) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="24"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">            String key = (String) it.next();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="25"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">            System.out.println(key + <span class="hljs-string">".."</span> + sets.get(key));</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="26"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="27"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-comment">//================== entrySet ======================</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="28"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        Iterator&lt;Map.Entry&lt;String, String&gt;&gt; iterator = sets.entrySet().iterator();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="29"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        <span class="hljs-keyword">while</span> (iterator.hasNext()) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="30"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">            Map.Entry&lt;String, String&gt; m = iterator.next();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="31"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">            System.out.println(m.getKey() + <span class="hljs-string">".."</span> + m.getValue());</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="32"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">        }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="33"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">    }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="34"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="复制" onclick="hljs.copyCode(event)"></div></pre>

<p style="margin-left:0cm;">TreeMap</p>

<p style="text-indent:50px;">这里简要介绍下:TreeMap 是一个有序的key-value集合,继承于AbstractMap,它是通过<a href="http://www.cnblogs.com/skywang12345/p/3245399.html" rel="nofollow" data-token="190f5ee81d395e91a03926ee83cbe310">红黑树</a>实现的。TreeMap 实现了NavigableMap接口,实现了Cloneable接口,实现了java.io.Serializable接口。</p>

<p style="text-indent:50px;">TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。</p>

<p style="text-indent:50px;">红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它有五个特点如下:</p>

<p style="text-indent:50px;">性质1:节点是红色或黑色。</p>

<p style="text-indent:50px;">性质2:根节点是黑色。</p>

<p style="text-indent:50px;">性质3:每个叶节点(NIL节点,空节点)是黑色的。</p>

<p style="text-indent:50px;">性质4:每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)。</p>

<p style="text-indent:50px;">性质5:从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。</p>

<p style="text-indent:50px;">详细了解<a href="https://blog.csdn.net/yangyutong0506/article/details/78204953" rel="nofollow" data-token="2ad55bc2bf71f76ec3758e7988550665">请点击</a>。</p>

<h1 style="margin-left:0cm;"><a name="t6"></a>LinkedHashMap:</h1>

<p style="text-indent:50px;">HashMap是无序的,只要不涉及线程安全问题,Map基本都可以使用HashMap。如果我们期待一个有序的Map,这个时候,LinkedHashMap就派上用场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序,该迭代顺序可以是插入顺序或者是访问顺序。那么是如何维护的呢,首先参考HashMap的存储结构,将其中的Entry元素增加一个pre指针和一个next指针,这样,根据插入元素的顺序将各个元素依次连接起来,这样LinkedHashMap就保证了元素的顺序。</p>

<p style="text-indent:50px;"><img alt="" class="has" height="345" src="https://img-blog.csdnimg.cn/20181126155525355.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="530"></p>

<p style="text-indent:50px;">继承自HashMap,实现了Map接口,LinkedHashMap重写了父类HashMap的get方法,实际在调用父类getEntry()方法取得查找的元素后,再判断当排序模式accessOrder为true时(即按访问顺序排序),先将当前节点从链表中移除,然后再将当前节点插入到链表尾部。</p>

<p style="text-indent:50px;">实现LRU缓存:</p>

<p style="text-indent:50px;">LinkedHashMap和HashMap+LinkedList的操作都是类似的,LRU缓存是我最近看到一个很巧妙的东西,所以推荐大家看一下<a href="https://www.cnblogs.com/LZYY/p/3447785.html" rel="nofollow" data-token="afa3842cfe293cf1a5d82e1a7fdf5e59">这篇文章</a>。</p>

<h2><a name="t7"></a>对比下Hashmap、Hashtable和ConcurrentHashmap:</h2>

<p style="text-indent:50px;">第一、Hashmap是线程不安全的,Hashtable和ConcurrentHashMap是线程安全的,在Hashtable中使用了关键字synchronized修饰,加上了同步锁;ConcurrentHashMap在JDK1.7中采用了锁分离的技术,每一个Segment都独立上锁,保证了并发的安全性;每一个Segment元素存储的是HashEntry数组+ 链表,Segment的大小是一开始就确定的,后期不能再进行扩容,但是单个Segment里面的数组是可以扩容的。</p>

<p style="text-indent:50px;"><img alt="" class="has" height="253" src="https://img-blog.csdnimg.cn/20190421141741875.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="459"></p>

<p style="text-indent:50px;">但是在JDK1.8上则摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,如下图所示,并发控制使用Synchronized和CAS来操作,每一个Node节点都是用volatile修饰的,整个看起来就像是优化过且线程安全的HashMap。</p>

<p style="text-indent:50px;"><img alt="" class="has" height="180" src="https://img-blog.csdnimg.cn/20190421141954720.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppZ3VxdWFuMzgzOQ==,size_16,color_FFFFFF,t_70" width="530"></p>

<p style="text-indent:50px;">第二、Hashmap是可以存放key和value均为null的,存放在table[0]的位置,此时使用put方法在添加元素的时候,如果在table[0]中已经存入key为null的元素则给null赋上新的value值并返回后面的值,否则则初始化null的元素,存入put里面存放的值。Hashtable和ConcurrentHashMap是不可以存放null的key或者value的,原因和并发状态下的操作有关,当在并发状态下执行无法分辨是key没找到的null还是有key值为null,这在多线程里面是模糊不清的,所以不允许put、get为null的元素,如果强行操作就会报空指针异常。</p>
                                    </div>
                    </div>
    </article>
    <div class="postTime"> 
        <div class="article-bar-bottom">
            <span class="time">
                文章最后发布于: 2018-11-26 15:56:29            </span>
        </div>
    </div>
</div>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值