-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeed.xml
1828 lines (1718 loc) · 335 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xml" href="/feed.xslt.xml"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="http://jekyllrb.com" version="3.2.1">Jekyll</generator><link href="https://ckape.github.io/workhard/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ckape.github.io/workhard/" rel="alternate" type="text/html" /><updated>2016-09-22T22:57:56+08:00</updated><id>https://ckape.github.io/workhard/</id><title type="html">WorkHard-Website</title><subtitle>This is my own site.</subtitle><entry><title type="html">Java源码分析——TreeMap</title><link href="https://ckape.github.io/workhard/TreeMap/" rel="alternate" type="text/html" title="Java源码分析——TreeMap" /><published>2016-09-22T00:00:00+08:00</published><updated>2016-09-22T00:00:00+08:00</updated><id>https://ckape.github.io/workhard/TreeMap</id><content type="html" xml:base="https://ckape.github.io/workhard/TreeMap/"><h2 id="treemap">TreeMap</h2>
<blockquote>
<p>参考学习资料:
<a href="http://blog.csdn.net/eson_15/article/details/51217741">java集合框架10——TreeMap和源码分析(一)</a></p>
</blockquote>
<ol>
<li>
<p>简介
跟HashMap一样,TreeMap也是一个 <strong>非线程安全</strong> 的集合,不同的是,TreeMap是有序集合,内部是通过 <strong>红黑树</strong> 实现的。【可爱的传送门:<a href="http://blog.csdn.net/eson_15/article/details/51144079">红黑树介绍</a>】该映射根据其key的自然顺序进行排序,或者根据用户自定义的Comarotor进行排序。</p>
</li>
<li>
<p>源码分析(jdk1.7)</p>
</li>
</ol></content><category term="JavaBasic" /><summary type="html">TreeMap源码分析.</summary></entry><entry><title type="html">Project Test</title><link href="https://ckape.github.io/workhard/Project/" rel="alternate" type="text/html" title="Project Test" /><published>2016-09-21T00:00:00+08:00</published><updated>2016-09-21T00:00:00+08:00</updated><id>https://ckape.github.io/workhard/Project</id><content type="html" xml:base="https://ckape.github.io/workhard/Project/"><h1 id="project">Project</h1></content><category term="Project" /><summary type="html">Project Test.</summary></entry><entry><title type="html">Java源码分析——HashSet</title><link href="https://ckape.github.io/workhard/HashSet/" rel="alternate" type="text/html" title="Java源码分析——HashSet" /><published>2016-09-21T00:00:00+08:00</published><updated>2016-09-21T00:00:00+08:00</updated><id>https://ckape.github.io/workhard/HashSet</id><content type="html" xml:base="https://ckape.github.io/workhard/HashSet/"><h1 id="set">Set</h1>
<ol>
<li><strong>HashSet</strong>
<ul>
<li>Serializable</li>
<li>Cloneable</li>
<li>Iterable<E></E></li>
<li>Collection<E></E></li>
<li>Set<E></E></li>
</ul>
</li>
<li><strong>TreeSet</strong>
<ul>
<li>Serializable</li>
<li>Cloneable</li>
<li>Iterable<E></E></li>
<li>Collection<E></E></li>
<li>NavigableSet<E></E></li>
<li>Set<E></E></li>
<li>SortedSet<E></E></li>
</ul>
</li>
<li><strong>LinkedHashSet</strong></li>
<li><strong>CopyOnWriteArraySet</strong></li>
<li><strong>AbstractSet</strong></li>
<li><strong>ConcurrentSkipListSet</strong></li>
<li><strong>EnumSet</strong></li>
<li><strong>JobStateReasons</strong></li>
</ol>
<h2 id="hashsethashmap">HashSet(本质上是HashMap)</h2>
<p>所以先看HashMap的源码</p>
<p><strong>其实就是基于HashMap实现的,用key放置值,value则存放一个final,static的对象PRESENT</strong></p></content><category term="JavaBasic" /><summary type="html">HashSet源码分析.</summary></entry><entry><title type="html">Java源码分析——HashMap</title><link href="https://ckape.github.io/workhard/HashMap/" rel="alternate" type="text/html" title="Java源码分析——HashMap" /><published>2016-09-21T00:00:00+08:00</published><updated>2016-09-21T00:00:00+08:00</updated><id>https://ckape.github.io/workhard/HashMap</id><content type="html" xml:base="https://ckape.github.io/workhard/HashMap/"><h1 id="map">Map</h1>
<ol>
<li>HashMap(常用)</li>
<li>TreeMap(常用)</li>
<li>ConcurrentHashMap(并发)</li>
<li>EnumMap(枚举map)</li>
<li>Hashtable</li>
<li>LinkedHashMap</li>
</ol>
<h2 id="hashmap">HashMap</h2>
<ol>
<li>map
<ul>
<li>定义
<blockquote>
<p>一个把键映射到值的对象被称作一个映射表对象。映射表不能包含重复的键,每个键至多可以与一个值关联。Map接口提供了三个集合视图:键的集合视图、值的集合视图以及键值对的集合视图。一个映射表的顺序取决于它的集合视图的迭代器返回元素的顺序。一些Map接口的具体实现(比如TreeMap)保证元素有一定的顺序,其它一些实现(比如HashMap)则不保证元素在其内部有序。</p>
</blockquote>
</li>
</ul>
</li>
<li>HashMap
<ul>
<li>定义
<blockquote>
<p>HashMap&lt;K, V&gt;是基于哈希表这个数据结构的Map接口具体实现,允许null键和null值(最多只允许一个key为null,但允许多个value为null)。这个类与HashTable近似等价,区别在于HashMap不是线程安全的并且允许null键和null值。由于基于哈希表实现,所以HashMap内部的元素是无序的。HashMap对与get与put操作的时间复杂度是常数级别的(在散列均匀的前提下)。对HashMap的集合视图进行迭代所需时间与HashMap的capacity(bucket的数量)加上HashMap的尺寸(键值对的数量)成正比。因此,若迭代操作的性能很重要,不要把初始capacity设的过高(不要把load factor设的过低)。</p>
</blockquote>
</li>
</ul>
</li>
</ol>
<ul>
<li>影响性能的因素:
<ul>
<li>intial capacity(初始容量):HashMap对象刚创建时其内部的哈希表的“桶”的数量;</li>
<li>load factor(负载因子):maxSize / capacity,也就是HashMap所允许的最大键值对数与桶数的比值,当我们清楚自己将要大概存放多少数据时,也可以自定义load factor的大小;
<em>注意:增大load factor可以节省空间但查找一个元素的时间会增加,减小load factor会占用更多的存储空间,但是get与put的操作会更快。当HashMap中的键值对数量超过了maxSize(即load factor与capacity的乘积),它会再散列,再散列会重建内部数据结构,桶数(capacity)大约会增加到原来的两倍。</em></li>
</ul>
</li>
</ul>
<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">//默认初始容量是16,必须是2的幂 </span>
<span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">DEFAULT_INITIAL_CAPACITY</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="o">;</span> <span class="c1">// aka 16 </span>
<span class="c1">//最大容量(必须是2的幂且小于2的30次方,传入容量过大会被这个值替换) </span>
<span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">MAXIMUM_CAPACITY</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="o">;</span>
<span class="c1">//默认加载因子,所谓加载因子是指哈希表在其容量自动增加之前可以达到多满的一种尺度 </span>
<span class="kd">static</span> <span class="kd">final</span> <span class="kt">float</span> <span class="n">DEFAULT_LOAD_FACTOR</span> <span class="o">=</span> <span class="mf">0.75f</span><span class="o">;</span>
<span class="c1">//存储Entry的默认空数组 </span>
<span class="kd">static</span> <span class="kd">final</span> <span class="n">Entry</span><span class="o">&lt;?,?&gt;[]</span> <span class="n">EMPTY_TABLE</span> <span class="o">=</span> <span class="o">{};</span>
<span class="c1">//存储Entry的数组,长度为2的幂。HashMap采用拉链法实现的,每个Entry的本质是个单向链表 </span>
<span class="kd">transient</span> <span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;[]</span> <span class="n">table</span> <span class="o">=</span> <span class="o">(</span><span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;[])</span> <span class="n">EMPTY_TABLE</span><span class="o">;</span>
<span class="c1">//HashMap的大小,即HashMap存储的键值对数量 </span>
<span class="kd">transient</span> <span class="kt">int</span> <span class="n">size</span><span class="o">;</span>
<span class="c1">//HashMap的阈值,用于判断是否需要调整HashMap的容量 </span>
<span class="kt">int</span> <span class="n">threshold</span><span class="o">;</span>
<span class="c1">//加载因子实际大小 </span>
<span class="kd">final</span> <span class="kt">float</span> <span class="n">loadFactor</span><span class="o">;</span>
<span class="c1">//HashMap被修改的次数,用于fail-fast机制 </span>
<span class="kd">transient</span> <span class="kt">int</span> <span class="n">modCount</span><span class="o">;</span>
</code></pre>
</div>
<ul>
<li>
<p>HashMap构造函数</p>
<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="cm">/**
* Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/</span>
<span class="kd">public</span> <span class="nf">HashMap</span><span class="o">(</span><span class="kt">int</span> <span class="n">initialCapacity</span><span class="o">,</span> <span class="kt">float</span> <span class="n">loadFactor</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">initialCapacity</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="o">)</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"Illegal initial capacity: "</span> <span class="o">+</span>
<span class="n">initialCapacity</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">initialCapacity</span> <span class="o">&gt;</span> <span class="n">MAXIMUM_CAPACITY</span><span class="o">)</span>
<span class="n">initialCapacity</span> <span class="o">=</span> <span class="n">MAXIMUM_CAPACITY</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">loadFactor</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">Float</span><span class="o">.</span><span class="na">isNaN</span><span class="o">(</span><span class="n">loadFactor</span><span class="o">))</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"Illegal load factor: "</span> <span class="o">+</span>
<span class="n">loadFactor</span><span class="o">);</span>
<span class="k">this</span><span class="o">.</span><span class="na">loadFactor</span> <span class="o">=</span> <span class="n">loadFactor</span><span class="o">;</span>
<span class="n">threshold</span> <span class="o">=</span> <span class="n">initialCapacity</span><span class="o">;</span>
<span class="n">init</span><span class="o">();</span>
<span class="o">}</span>
</code></pre>
</div>
<p><code class="highlighter-rouge">threshold</code>即为上文提到的maxSize。</p>
</li>
<li>
<p>基本实现原理
HashMap是基于拉链法处理碰撞的散列表的实现,一个存储整型元素的HashMap的内部存储结构如下图所示:</p>
</li>
</ul>
<figure>
<img src="http://upload-images.jianshu.io/upload_images/2397836-3be8c0d8ef3f12bf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" />
</figure>
<p>我们可以看到,HashMap是采用<code class="highlighter-rouge">数组+链表</code>实现的,<strong>在JDK 1.8中,对HashMap做了进一步优化,引入了红黑树。当链表的长度大于8时,就会使用红黑树来代替链表</strong>。</p>
<ul>
<li>源码分析
<ul>
<li>jdk1.7
<ul>
<li><code class="highlighter-rouge">table</code>字段是一个Entry&lt;K, V&gt;数组.</li>
<li>HashMap的底层是通过链表来解决<code class="highlighter-rouge">hash冲突</code>的,即<code class="highlighter-rouge">碰撞</code>.</li>
</ul>
<div class="language-java highlighter-rouge"><pre class="highlight"><code> <span class="cm">/**
* An empty table instance to share when the table is not inflated.
*/</span>
<span class="kd">static</span> <span class="kd">final</span> <span class="n">Entry</span><span class="o">&lt;?,?&gt;[]</span> <span class="n">EMPTY_TABLE</span> <span class="o">=</span> <span class="o">{};</span>
<span class="cm">/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/</span>
<span class="kd">transient</span> <span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;[]</span> <span class="n">table</span> <span class="o">=</span> <span class="o">(</span><span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;[])</span> <span class="n">EMPTY_TABLE</span><span class="o">;</span>
<span class="cm">/**
* Entry&lt;K,V&gt;是存储对应键值对的节点,里面还定义了next指向了下一个节点
* 所以是一个单向链表,是HashMap链式存储对应的链表
*
*/</span>
<span class="kd">static</span> <span class="kd">class</span> <span class="nc">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="kd">implements</span> <span class="n">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">K</span> <span class="n">key</span><span class="o">;</span>
<span class="n">V</span> <span class="n">value</span><span class="o">;</span>
<span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">next</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">hash</span><span class="o">;</span>
<span class="cm">/**
* Creates new entry.
*/</span>
<span class="n">Entry</span><span class="o">(</span><span class="kt">int</span> <span class="n">h</span><span class="o">,</span> <span class="n">K</span> <span class="n">k</span><span class="o">,</span> <span class="n">V</span> <span class="n">v</span><span class="o">,</span> <span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">n</span><span class="o">)</span> <span class="o">{</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">v</span><span class="o">;</span>
<span class="n">next</span> <span class="o">=</span> <span class="n">n</span><span class="o">;</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">k</span><span class="o">;</span>
<span class="n">hash</span> <span class="o">=</span> <span class="n">h</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">K</span> <span class="nf">getKey</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">key</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">V</span> <span class="nf">getValue</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">value</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">V</span> <span class="nf">setValue</span><span class="o">(</span><span class="n">V</span> <span class="n">newValue</span><span class="o">)</span> <span class="o">{</span>
<span class="n">V</span> <span class="n">oldValue</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">newValue</span><span class="o">;</span>
<span class="k">return</span> <span class="n">oldValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//重写了equals方法,用于遍历链表取值</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="nf">equals</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">o</span> <span class="k">instanceof</span> <span class="n">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">))</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">Map</span><span class="o">.</span><span class="na">Entry</span> <span class="n">e</span> <span class="o">=</span> <span class="o">(</span><span class="n">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">)</span><span class="n">o</span><span class="o">;</span>
<span class="n">Object</span> <span class="n">k1</span> <span class="o">=</span> <span class="n">getKey</span><span class="o">();</span>
<span class="n">Object</span> <span class="n">k2</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">getKey</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">k1</span> <span class="o">==</span> <span class="n">k2</span> <span class="o">||</span> <span class="o">(</span><span class="n">k1</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">k1</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">k2</span><span class="o">)))</span> <span class="o">{</span>
<span class="n">Object</span> <span class="n">v1</span> <span class="o">=</span> <span class="n">getValue</span><span class="o">();</span>
<span class="n">Object</span> <span class="n">v2</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">getValue</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">v1</span> <span class="o">==</span> <span class="n">v2</span> <span class="o">||</span> <span class="o">(</span><span class="n">v1</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">v1</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">v2</span><span class="o">)))</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kt">int</span> <span class="nf">hashCode</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">Objects</span><span class="o">.</span><span class="na">hashCode</span><span class="o">(</span><span class="n">getKey</span><span class="o">())</span> <span class="o">^</span> <span class="n">Objects</span><span class="o">.</span><span class="na">hashCode</span><span class="o">(</span><span class="n">getValue</span><span class="o">());</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">getKey</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">getValue</span><span class="o">();</span>
<span class="o">}</span>
<span class="cm">/**
* 当向HashMap中添加元素时,即调用put(k,v)时,
* 对已经在HashMap中k位置进行v的覆盖时,会调用此方法
* 这里没做任何处理
*/</span>
<span class="kt">void</span> <span class="nf">recordAccess</span><span class="o">(</span><span class="n">HashMap</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">m</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="cm">/**
* 当从HashMap中删除了一个Entry时,会调用该函数
* 这里没做任何处理
*/</span>
<span class="kt">void</span> <span class="nf">recordRemoval</span><span class="o">(</span><span class="n">HashMap</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">m</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with &lt;tt&gt;key&lt;/tt&gt;, or
* &lt;tt&gt;null&lt;/tt&gt; if there was no mapping for &lt;tt&gt;key&lt;/tt&gt;.
* (A &lt;tt&gt;null&lt;/tt&gt; return can also indicate that the map
* previously associated &lt;tt&gt;null&lt;/tt&gt; with &lt;tt&gt;key&lt;/tt&gt;.)
*/</span>
<span class="kd">public</span> <span class="n">V</span> <span class="nf">put</span><span class="o">(</span><span class="n">K</span> <span class="n">key</span><span class="o">,</span> <span class="n">V</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//如果哈希表没有初始化(table为空) </span>
<span class="c1">//用构造时的阈值(其实就是初始容量)扩展table </span>
<span class="k">if</span> <span class="o">(</span><span class="n">table</span> <span class="o">==</span> <span class="n">EMPTY_TABLE</span><span class="o">)</span> <span class="o">{</span>
<span class="n">inflateTable</span><span class="o">(</span><span class="n">threshold</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">key</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="c1">//如果key==null,就将value加到table[0]的位置 </span>
<span class="c1">//该位置永远只有一个value,新传进来的value会覆盖旧的value </span>
<span class="k">return</span> <span class="nf">putForNullKey</span><span class="o">(</span><span class="n">value</span><span class="o">);</span>
<span class="c1">//计算hash值,并且计算出值的索引</span>
<span class="kt">int</span> <span class="n">hash</span> <span class="o">=</span> <span class="n">hash</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">indexFor</span><span class="o">(</span><span class="n">hash</span><span class="o">,</span> <span class="n">table</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">table</span><span class="o">[</span><span class="n">i</span><span class="o">];</span> <span class="n">e</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Object</span> <span class="n">k</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span><span class="o">.</span><span class="na">hash</span> <span class="o">==</span> <span class="n">hash</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">k</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">key</span><span class="o">)</span> <span class="o">==</span> <span class="n">key</span> <span class="o">||</span> <span class="n">key</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">k</span><span class="o">)))</span> <span class="o">{</span>
<span class="n">V</span> <span class="n">oldValue</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">value</span><span class="o">;</span>
<span class="n">e</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="n">e</span><span class="o">.</span><span class="na">recordAccess</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="k">return</span> <span class="n">oldValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">modCount</span><span class="o">++;</span>
<span class="c1">//如果在table[i]中没找到对应的key,那么就直接在该位置的链表中添加此Entry</span>
<span class="n">addEntry</span><span class="o">(</span><span class="n">hash</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="n">i</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Offloaded version of put for null keys
*/</span>
<span class="kd">private</span> <span class="n">V</span> <span class="nf">putForNullKey</span><span class="o">(</span><span class="n">V</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">table</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span> <span class="n">e</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span><span class="o">.</span><span class="na">key</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">V</span> <span class="n">oldValue</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">value</span><span class="o">;</span>
<span class="n">e</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="n">e</span><span class="o">.</span><span class="na">recordAccess</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="k">return</span> <span class="n">oldValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">modCount</span><span class="o">++;</span>
<span class="n">addEntry</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/</span>
<span class="kt">void</span> <span class="nf">addEntry</span><span class="o">(</span><span class="kt">int</span> <span class="n">hash</span><span class="o">,</span> <span class="n">K</span> <span class="n">key</span><span class="o">,</span> <span class="n">V</span> <span class="n">value</span><span class="o">,</span> <span class="kt">int</span> <span class="n">bucketIndex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">((</span><span class="n">size</span> <span class="o">&gt;=</span> <span class="n">threshold</span><span class="o">)</span> <span class="o">&amp;&amp;</span> <span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">table</span><span class="o">[</span><span class="n">bucketIndex</span><span class="o">]))</span> <span class="o">{</span>
<span class="n">resize</span><span class="o">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">table</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
<span class="n">hash</span> <span class="o">=</span> <span class="o">(</span><span class="kc">null</span> <span class="o">!=</span> <span class="n">key</span><span class="o">)</span> <span class="o">?</span> <span class="n">hash</span><span class="o">(</span><span class="n">key</span><span class="o">)</span> <span class="o">:</span> <span class="mi">0</span><span class="o">;</span>
<span class="n">bucketIndex</span> <span class="o">=</span> <span class="n">indexFor</span><span class="o">(</span><span class="n">hash</span><span class="o">,</span> <span class="n">table</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">createEntry</span><span class="o">(</span><span class="n">hash</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="n">bucketIndex</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**
* Retrieve object hash code and applies a supplemental hash function to the
* result hash, which defends against poor quality hash functions. This is
* critical because HashMap uses power-of-two length hash tables, that
* otherwise encounter collisions for hashCodes that do not differ
* in lower bits. Note: Null keys always map to hash 0, thus index 0.
*/</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="nf">hash</span><span class="o">(</span><span class="n">Object</span> <span class="n">k</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">h</span> <span class="o">=</span> <span class="n">hashSeed</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="mi">0</span> <span class="o">!=</span> <span class="n">h</span> <span class="o">&amp;&amp;</span> <span class="n">k</span> <span class="k">instanceof</span> <span class="n">String</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">sun</span><span class="o">.</span><span class="na">misc</span><span class="o">.</span><span class="na">Hashing</span><span class="o">.</span><span class="na">stringHash32</span><span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">k</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">h</span> <span class="o">^=</span> <span class="n">k</span><span class="o">.</span><span class="na">hashCode</span><span class="o">();</span>
<span class="c1">// This function ensures that hashCodes that differ only by</span>
<span class="c1">// constant multiples at each bit position have a bounded</span>
<span class="c1">// number of collisions (approximately 8 at default load factor).</span>
<span class="n">h</span> <span class="o">^=</span> <span class="o">(</span><span class="n">h</span> <span class="o">&gt;&gt;&gt;</span> <span class="mi">20</span><span class="o">)</span> <span class="o">^</span> <span class="o">(</span><span class="n">h</span> <span class="o">&gt;&gt;&gt;</span> <span class="mi">12</span><span class="o">);</span>
<span class="k">return</span> <span class="n">h</span> <span class="o">^</span> <span class="o">(</span><span class="n">h</span> <span class="o">&gt;&gt;&gt;</span> <span class="mi">7</span><span class="o">)</span> <span class="o">^</span> <span class="o">(</span><span class="n">h</span> <span class="o">&gt;&gt;&gt;</span> <span class="mi">4</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**
* Like addEntry except that this version is used when creating entries
* as part of Map construction or "pseudo-construction" (cloning,
* deserialization). This version needn't worry about resizing the table.
*
* Subclass overrides this to alter the behavior of HashMap(Map),
* clone, and readObject.
*/</span>
<span class="kt">void</span> <span class="nf">createEntry</span><span class="o">(</span><span class="kt">int</span> <span class="n">hash</span><span class="o">,</span> <span class="n">K</span> <span class="n">key</span><span class="o">,</span> <span class="n">V</span> <span class="n">value</span><span class="o">,</span> <span class="kt">int</span> <span class="n">bucketIndex</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Entry</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span><span class="n">V</span><span class="o">&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">table</span><span class="o">[</span><span class="n">bucketIndex</span><span class="o">];</span>
<span class="n">table</span><span class="o">[</span><span class="n">bucketIndex</span><span class="o">]</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entry</span><span class="o">&lt;&gt;(</span><span class="n">hash</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="n">e</span><span class="o">);</span>
<span class="n">size</span><span class="o">++;</span>
<span class="o">}</span>
</code></pre>
</div>
</li>
</ul>
</li>
<li>jdk 1.8</li>
</ul>
<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kd">final</span> <span class="n">V</span> <span class="nf">putVal</span><span class="o">(</span><span class="kt">int</span> <span class="n">hash</span><span class="o">,</span> <span class="n">K</span> <span class="n">key</span><span class="o">,</span> <span class="n">V</span> <span class="n">value</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">onlyIfAbsent</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">evict</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span> <span class="n">V</span><span class="o">&gt;[]</span> <span class="n">tab</span><span class="o">;</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span> <span class="n">V</span><span class="o">&gt;</span> <span class="n">p</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">n</span><span class="o">,</span> <span class="n">i</span><span class="o">;</span>
<span class="c1">// 若table为空或table的length为0则需要通过resize方法扩容</span>
<span class="k">if</span> <span class="o">((</span><span class="n">tab</span> <span class="o">=</span> <span class="n">table</span><span class="o">)</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="o">(</span><span class="n">n</span> <span class="o">=</span> <span class="n">tab</span><span class="o">.</span><span class="na">length</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span>
<span class="n">n</span> <span class="o">=</span> <span class="o">(</span><span class="n">tab</span> <span class="o">=</span> <span class="n">resize</span><span class="o">()).</span><span class="na">length</span><span class="o">;</span>
<span class="c1">// 让传入的hash与n-1做与运算从而得到目标Node的索引</span>
<span class="c1">// 若该索引处为null,则直接插入包含了key-value pair的new Node</span>
<span class="k">if</span> <span class="o">((</span><span class="n">p</span> <span class="o">=</span> <span class="n">tab</span><span class="o">[</span><span class="n">i</span> <span class="o">=</span> <span class="o">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="o">&amp;</span> <span class="n">hash</span><span class="o">])</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">tab</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">(</span><span class="n">hash</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="k">else</span> <span class="o">{</span>
<span class="c1">// 若索引处不为null,则判断key是否存在</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span> <span class="n">V</span><span class="o">&gt;</span> <span class="n">e</span><span class="o">;</span>
<span class="n">K</span> <span class="n">k</span><span class="o">;</span>
<span class="c1">// 若key存在,则直接覆盖value</span>
<span class="k">if</span> <span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">hash</span> <span class="o">==</span> <span class="n">hash</span>
<span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">k</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">key</span><span class="o">)</span> <span class="o">==</span> <span class="n">key</span> <span class="o">||</span> <span class="o">(</span><span class="n">key</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">key</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">k</span><span class="o">))))</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">p</span><span class="o">;</span>
<span class="c1">// 若key不存在,则判断table[i]是否为TreeNode</span>
<span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">p</span> <span class="k">instanceof</span> <span class="n">TreeNode</span><span class="o">)</span>
<span class="c1">// 若是的话,说明此处为红黑树,直接插入key-value pair</span>
<span class="n">e</span> <span class="o">=</span> <span class="o">((</span><span class="n">TreeNode</span><span class="o">&lt;</span><span class="n">K</span><span class="o">,</span> <span class="n">V</span><span class="o">&gt;)</span> <span class="n">p</span><span class="o">).</span><span class="na">putTreeVal</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">tab</span><span class="o">,</span> <span class="n">hash</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">// 否则遍历链表</span>
<span class="k">else</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">binCount</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;;</span> <span class="o">++</span><span class="n">binCount</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">((</span><span class="n">e</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">p</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">(</span><span class="n">hash</span><span class="o">,</span> <span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="c1">// 链表长度大于8则转为红黑树</span>
<span class="k">if</span> <span class="o">(</span><span class="n">binCount</span> <span class="o">&gt;=</span> <span class="n">TREEIFY_THRESHOLD</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="c1">// -1 for 1st</span>
<span class="n">treeifyBin</span><span class="o">(</span><span class="n">tab</span><span class="o">,</span> <span class="n">hash</span><span class="o">);</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// 若key已经存在则直接覆盖value</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span><span class="o">.</span><span class="na">hash</span> <span class="o">==</span> <span class="n">hash</span>
<span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">k</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">key</span><span class="o">)</span> <span class="o">==</span> <span class="n">key</span> <span class="o">||</span> <span class="o">(</span><span class="n">key</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">key</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">k</span><span class="o">))))</span>
<span class="k">break</span><span class="o">;</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">e</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// existing mapping for key</span>
<span class="n">V</span> <span class="n">oldValue</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="na">value</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">onlyIfAbsent</span> <span class="o">||</span> <span class="n">oldValue</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">e</span><span class="o">.</span><span class="na">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="n">afterNodeAccess</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="k">return</span> <span class="n">oldValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="c1">// 若超过maxSize,则扩容</span>
<span class="k">if</span> <span class="o">(++</span><span class="n">size</span> <span class="o">&gt;</span> <span class="n">threshold</span><span class="o">)</span>
<span class="n">resize</span><span class="o">();</span>
<span class="n">afterNodeInsertion</span><span class="o">(</span><span class="n">evict</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
</code></pre>
</div>
<p>以上代码的工作过程可以总结为下图:</p>
<figure>
<img src="http://upload-images.jianshu.io/upload_images/2397836-6450610b8603539c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" />
</figure>
<blockquote>
<p><a href="http://www.jianshu.com/p/f174d49b391c?hmsr=toutiao.io&amp;utm_medium=toutiao.io&amp;utm_source=toutiao.io">从源码角度认识ArrayList,LinkedList与HashMap</a>
<a href="https://zhuanlan.zhihu.com/p/21673805">Java 8系列之重新认识HashMap</a></p>
</blockquote>
<h1 id="section">拓展</h1>
<h1 id="hashmaphttpwwwimportnewcom7099html"><a href="http://www.importnew.com/7099.html">HashMap的工作原理</a></h1>
<h2 id="qhashmap-hashmap">Q:“你用过HashMap吗?” “什么是HashMap?你为什么用到它?”</h2>
<h2 id="qhashmap-hashmapget">Q:“你知道HashMap的工作原理吗?” “你知道HashMap的get()方法的工作原理吗?”</h2>
<h2 id="qhashmapcollision-detectionhashcode">Q:关于HashMap中的碰撞探测(collision detection)以及碰撞的解决方法?“当两个对象的hashcode相同会发生什么?”</h2>
<h2 id="qhashcode">Q:“如果两个键的hashcode相同,你如何获取值对象?”</h2>
<h2 id="qhashmapload-factorhashmap075map75bucketarraylisthashmapbucketmapbucketrehashinghashbucket">Q:“如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?”除非你真正知道HashMap的工作原理,否则你将回答不出这道题。默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。</h2>
<h2 id="qhashmap">Q:“你了解重新调整HashMap大小存在什么问题吗?”</h2>
<h2 id="qstring-intergerwrapper-">Q:为什么String, Interger这样的wrapper类适合作为键? 我们可以使用自定义的对象作为键吗?</h2>
<h2 id="qcocurrenthashmaphashtable">Q:我们可以使用CocurrentHashMap来代替Hashtable吗?</h2>
<p>查看<a href="http://javarevisited.blogspot.com/2011/04/difference-between-concurrenthashmap.html/">Hashtable和ConcurrentHashMap的区别</a>。</p>
<p>我个人很喜欢这个问题,因为这个问题的深度和广度,也不直接的涉及到不同的概念。让我们再来看看这些问题设计哪些知识点:</p>
<ul>
<li>hashing的概念</li>
<li>HashMap中解决碰撞的方法</li>
<li>equals()和hashCode()的应用,以及它们在HashMap中的重要性</li>
<li>不可变对象的好处</li>
<li>HashMap多线程的条件竞争</li>
<li>重新调整HashMap的大小</li>
</ul>
<p>因为HashMap的好处非常多,我曾经在电子商务的应用中使用HashMap作为缓存。因为金融领域非常多的运用Java,也出于性能的考虑,我们会经常用到HashMap和ConcurrentHashMap。你可以查看更多的关于HashMap的文章:</p>
<p><a href="http://www.importnew.com/7010.html/">HashMap和Hashtable的区别</a>
<a href="http://www.importnew.com/6931.html/">HashMap和HashSet的区别</a></p></content><category term="JavaBasic" /><summary type="html">HashMap源码分析.</summary></entry><entry><title type="html">Java源码分析——LinkedList</title><link href="https://ckape.github.io/workhard/LinkedList/" rel="alternate" type="text/html" title="Java源码分析——LinkedList" /><published>2016-09-20T00:00:00+08:00</published><updated>2016-09-20T00:00:00+08:00</updated><id>https://ckape.github.io/workhard/LinkedList</id><content type="html" xml:base="https://ckape.github.io/workhard/LinkedList/"><h2 id="linkedlist">LinkedList</h2>
<blockquote>
<p>参考学习资料:</p>
<blockquote>
<p>JDK1.7之前的【Java集合源码剖析】LinkedList源码剖析</p>
</blockquote>
</blockquote>
<ol>
<li>LinkedList的要点
<ul>
<li><strong>双向链表</strong>:LinkedList基于双向链表实现的(Entry有next,previous指针),因此可以把它当栈,队列和双端队列使用;
在JDK1.7之前LinkedList之前是循环链表的方式实现两端插入的,包含一个无值的头结点,JDK1.7及以上是包含两个指针分别指向头结点和尾结点;</li>
<li><strong>线程不安全</strong>:LinkedList通过维护modCount修改计数,每个迭代器保存各自的修改计数与modCount对比检验的方式防止并发修改;</li>
<li><strong>性能特点</strong>:由于是链表实现,不支持快速随机存取,因此get(index)效率不高,在循环时一定注意不能误用;支持高效的结构性修改(只需要移动指针指向);因此LinkedList定义了内部类实现ListIterator,避免使用效率低下的get()(AbstractList的迭代器是基于get()的),iterator()返回也是这个内部类实例;</li>
<li><strong>克隆和序列化</strong>:实现了Serializable和Cloneable接口,支持序列化和克隆,其中序列化使用writeObject和readObject不采用默认的序列化机制,只保存size和元素对象,一方面是隐藏内部表示信息,一方面节省了开销;</li>
<li><strong>置空操作</strong>:强调一点,对应容器,删除结点时x = null;是很有必要的,让容器,容器中的结点在清除后不要互相引用的保存在堆中,影响垃圾回收,因为JVM一般是进行可达性分析的;</li>
</ul>
</li>
<li>基本结构
<ul>
<li>结点类
<ul>
<li>双向链表,链表包含2个指针:头结点指针,尾结点指针;</li>
<li>结点(Node),包含2个指针,指向前驱结点和后序结点;</li>
</ul>
</li>
</ul>
</li>
</ol>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">transient</span> <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">//不变式:(first == null &amp;&amp; last == null) || (first.prev == null &amp;&amp; first.item != null)</span>
<span class="kd">transient</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">first</span><span class="o">;</span>
<span class="c1">//不变式:(first == null &amp;&amp; last == null) || (last.next == null &amp;&amp; last.item != null)</span>
<span class="kd">transient</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">last</span><span class="o">;</span>
<span class="c1">//结点</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="n">E</span> <span class="n">item</span><span class="o">;</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">next</span><span class="o">;</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">prev</span><span class="o">;</span>
<span class="n">Node</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">prev</span><span class="o">,</span> <span class="n">E</span> <span class="n">element</span><span class="o">,</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">next</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="n">element</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="n">prev</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<ul>
<li>列表迭代器ListIterator非静态内部类实现
<ul>
<li>每个迭代器对象独立维护一个expectedModCount进行修改计数检查,每次进行修改操作之前(包括set方法)检查计数,防止并发修改(抛出ConcurrentModificationException异常);</li>
<li>lastReturned这个变量很关键,结构性修改一次之后(add和remove)这个变量被置空,因此对于迭代器调用一次add或remove之后调用next才可以在此remove和set;</li>
<li>ListIterator支持两个方向的迭代遍历;
<div class="language-java highlighter-rouge"><pre class="highlight"><code> <span class="kd">private</span> <span class="kd">class</span> <span class="nc">ListItr</span> <span class="kd">implements</span> <span class="n">ListIterator</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="c1">//lastReturned保存最后返回的结点引用,当add,remove结构性修改后将这个值置空用于标识结构结构已修改</span>
<span class="kd">private</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">lastReturned</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">next</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">nextIndex</span><span class="o">;</span>
<span class="c1">//每个迭代器保存创建时modCount,维护自己的modCount防止因为并发修改造成的不一致</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">expectedModCount</span> <span class="o">=</span> <span class="n">modCount</span><span class="o">;</span>
<span class="n">ListItr</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="n">next</span> <span class="o">=</span> <span class="o">(</span><span class="n">index</span> <span class="o">==</span> <span class="n">size</span><span class="o">)</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="n">node</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="n">nextIndex</span> <span class="o">=</span> <span class="n">index</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">add</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//每次结构性修改之前必须先检查modCount是否同步,保证同时只有一个ListIterator可以修改链表</span>
<span class="n">checkForComodification</span><span class="o">();</span>
<span class="c1">//lastReturned置空,防止删除之前的结点</span>
<span class="n">lastReturned</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">linkLast</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="k">else</span>
<span class="nf">linkBefore</span><span class="o">(</span><span class="n">e</span><span class="o">,</span> <span class="n">next</span><span class="o">);</span>
<span class="n">nextIndex</span><span class="o">++;</span>
<span class="n">expectedModCount</span><span class="o">++;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">hasNext</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">nextIndex</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">E</span> <span class="nf">next</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">//检查修改计数</span>
<span class="n">checkForComodification</span><span class="o">();</span>
<span class="k">if</span><span class="o">(!</span><span class="n">hasNext</span><span class="o">())</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">NoSuchElementException</span><span class="o">();</span>
<span class="n">lastReturned</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span>
<span class="n">next</span> <span class="o">=</span> <span class="n">next</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
<span class="n">nextIndex</span><span class="o">++;</span>
<span class="k">return</span> <span class="n">lastReturned</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">hasPrevious</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">//nextIndex时显然不能有prev</span>
<span class="k">return</span> <span class="n">nextIndex</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//前一个结点,此时next和lastReturned值一致</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">E</span> <span class="nf">previous</span><span class="o">()</span> <span class="o">{</span>
<span class="n">checkForComodification</span><span class="o">();</span>
<span class="k">if</span><span class="o">(!</span><span class="n">hasPrevious</span><span class="o">())</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">NoSuchElementException</span><span class="o">();</span>
<span class="n">nextIndex</span><span class="o">--;</span>
<span class="n">lastReturned</span> <span class="o">=</span> <span class="n">next</span> <span class="o">=</span> <span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">?</span> <span class="n">last</span> <span class="o">:</span> <span class="n">next</span><span class="o">.</span><span class="na">prev</span><span class="o">;</span>
<span class="k">return</span> <span class="n">lastReturned</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">nextIndex</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">nextIndex</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">previousIndex</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">nextIndex</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//删除最后返回的结点</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">remove</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">//检查修改计数</span>
<span class="n">checkForComodification</span><span class="o">();</span>
<span class="k">if</span><span class="o">(</span><span class="n">lastReturned</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalStateException</span><span class="o">();</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">lastNext</span> <span class="o">=</span> <span class="n">lastReturned</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
<span class="n">unlink</span><span class="o">(</span><span class="n">lastReturned</span><span class="o">);</span>
<span class="c1">//如果next和lastReturned(这种情况在previous执行后出现),要修改next值</span>
<span class="k">if</span><span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="n">lastReturned</span><span class="o">)</span>
<span class="n">next</span> <span class="o">=</span> <span class="n">lastNext</span><span class="o">;</span> <span class="c1">//虽然删除了一个结点,但是next向后移动了一位,因此nextIndex值不需要修改</span>
<span class="k">else</span>
<span class="n">nextIndex</span><span class="o">--;</span>
<span class="n">lastReturned</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">expectedModCount</span><span class="o">++;</span>
<span class="o">}</span>
<span class="c1">//修改最后返回结点的值</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">lastReturned</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalStateException</span><span class="o">();</span>
<span class="n">checkForComodification</span><span class="o">();</span>
<span class="n">lastReturned</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="n">e</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//检查是否并发修改</span>
<span class="kd">final</span> <span class="kt">void</span> <span class="nf">checkForComodification</span><span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">modCount</span> <span class="o">!=</span> <span class="n">expectedModCount</span><span class="o">)</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConcurrentModificationException</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>
<ol>
<li>操作:LinkedList继承自AbstractSequentialList,实现了List,Deque,Serializable和Cloneable;因此可以按此顺序进行解释,首先分析LinkedList自身最很核心的方法。</li>
</ol>
</li>
<li>3-1 核心操作:包括linkFirst,linkLast,linkBefore,unlink,unlinkFirst,unlinkLast,node;这7个方法实现了双向链表最核心的功能,其他接口实现大部分是基于这7个方法的。
<ul>
<li>3-1-1. 这些方法有几个重要的细节:
<ul>
<li>i. 删除结点的时候置空操作;</li>
<li>ii. modCount的修改;</li>
<li>iii. node方法查找某个位置的结点根据index和size/2的关系进行优化处理;
<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">//在头端插入</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">linkFirst</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">f</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">newNode</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="o">&lt;&gt;(</span><span class="n">e</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">f</span><span class="o">);</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">f</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//原链表为空时last指针也要指向新结点</span>
<span class="n">last</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">f</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">++</span><span class="n">size</span><span class="o">;</span>
<span class="c1">//增加修改次数</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//在尾端插入</span>
<span class="kt">void</span> <span class="nf">linkLast</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">l</span> <span class="o">=</span> <span class="n">last</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">newNode</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="o">&lt;&gt;(</span><span class="n">e</span><span class="o">,</span> <span class="n">l</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="n">last</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">l</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//原链表为空时first指针也要执行新结点</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">l</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">++</span><span class="n">size</span><span class="o">;</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//在指定结点前插入</span>
<span class="kt">void</span> <span class="nf">linkBefore</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">,</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">succ</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">pred</span> <span class="o">=</span> <span class="n">succ</span><span class="o">.</span><span class="na">prev</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">newNode</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="o">&lt;&gt;(</span><span class="n">e</span><span class="o">,</span> <span class="n">succ</span><span class="o">.</span><span class="na">prev</span><span class="o">,</span> <span class="n">succ</span><span class="o">);</span>
<span class="n">succ</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">pred</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">pred</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">++</span><span class="n">size</span><span class="o">;</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//删除第一个结点,由调用者判断是否有头结点</span>
<span class="kd">private</span> <span class="n">E</span> <span class="nf">unlinkFirst</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">f</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">E</span> <span class="n">element</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">next</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
<span class="n">f</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">//删除之后置为null,不影响被引用对象的垃圾回收</span>
<span class="n">f</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span> <span class="c1">//first指针指向next</span>
<span class="k">if</span><span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">last</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">else</span>
<span class="n">next</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">--</span><span class="n">size</span><span class="o">;</span> <span class="c1">//数量减少</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span> <span class="c1">//修改计数增加</span>
<span class="k">return</span> <span class="n">element</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//删除最后一个结点</span>
<span class="kd">private</span> <span class="n">E</span> <span class="nf">unlinkLast</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">l</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">E</span> <span class="n">element</span> <span class="o">=</span> <span class="n">l</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">prev</span> <span class="o">=</span> <span class="n">l</span><span class="o">.</span><span class="na">prev</span><span class="o">;</span>
<span class="n">l</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">//置空不影响原被引用对象的垃圾回收</span>
<span class="n">l</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">last</span> <span class="o">=</span> <span class="n">prev</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">prev</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">first</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">else</span>
<span class="n">prev</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">--</span><span class="n">size</span><span class="o">;</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="k">return</span> <span class="n">element</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//删除链表中某个结点</span>
<span class="n">E</span> <span class="nf">unlink</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">E</span> <span class="n">element</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">prev</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">prev</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">next</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
<span class="n">x</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">//置空,不影响垃圾回收</span>
<span class="k">if</span><span class="o">(</span><span class="n">prev</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span>
<span class="k">else</span> <span class="o">{</span>
<span class="n">prev</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span>
<span class="n">x</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span><span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">last</span> <span class="o">=</span> <span class="n">prev</span><span class="o">;</span>
<span class="k">else</span> <span class="o">{</span>
<span class="n">next</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="n">prev</span><span class="o">;</span>
<span class="n">x</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">--</span><span class="n">size</span><span class="o">;</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="k">return</span> <span class="n">element</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//获取指定位置的结点,通过index是否小于size/2进行优化</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="nf">node</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//如果小于size / 2从头开始搜索,否则从尾开始搜索</span>
<span class="k">if</span><span class="o">(</span><span class="n">index</span> <span class="o">&lt;</span> <span class="o">(</span><span class="n">size</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="o">))</span> <span class="o">{</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span>
<span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">index</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
<span class="k">return</span> <span class="n">x</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">last</span><span class="o">;</span>
<span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="o">;</span> <span class="o">--</span><span class="n">i</span><span class="o">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">prev</span><span class="o">;</span>
<span class="k">return</span> <span class="n">x</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>3-2 私有辅助方法:包括检查查找索引,插入位置是否合法;
<div class="language-java highlighter-rouge"><pre class="highlight"><code> <span class="c1">//检查索引是否合法</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">isElementIndex</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">index</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//检查索引是否合法,不合法抛出异常</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">checkElementIndex</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">isElementIndex</span><span class="o">(</span><span class="n">index</span><span class="o">))</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IndexOutOfBoundsException</span><span class="o">(</span><span class="n">outOfBoundsMsg</span><span class="o">(</span><span class="n">index</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">outOfBoundsMsg</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Index: "</span><span class="o">+</span><span class="n">index</span><span class="o">+</span><span class="s">", Size: "</span><span class="o">+</span><span class="n">size</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//检查待插入位置的索引值是否合法</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">isPositionIndex</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">index</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">index</span> <span class="o">&lt;=</span> <span class="n">size</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//检查待插入位置的索引值是否合法,不合法抛出异常</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">checkPositionIndex</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">isPositionIndex</span><span class="o">(</span><span class="n">index</span><span class="o">))</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IndexOutOfBoundsException</span><span class="o">(</span><span class="n">outOfBoundsMsg</span><span class="o">(</span><span class="n">index</span><span class="o">));</span>
<span class="o">}</span>
</code></pre>
</div>
</li>
<li>3-3 List接口实现
<ul>
<li>3-3-1 基于Node内部表示,因此List的关键方法也要依赖与内部表示;</li>
<li>3-3-2 注意,LinkedList的subList实现没有覆盖AbstractList的实现;
<div class="language-java highlighter-rouge"><pre class="highlight"><code> <span class="c1">//添加结点,在表尾</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">add</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">linkLast</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//在指定位置添加结点</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">add</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">,</span> <span class="n">E</span> <span class="n">element</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//检查插入位置是否合法</span>
<span class="n">checkPositionIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="k">if</span><span class="o">(</span><span class="n">index</span> <span class="o">==</span> <span class="n">size</span><span class="o">)</span> <span class="c1">//排除为空的可能</span>
<span class="n">linkLast</span><span class="o">(</span><span class="n">element</span><span class="o">);</span>
<span class="k">else</span> <span class="o">{</span> <span class="c1">//index &lt; size时</span>
<span class="n">linkBefore</span><span class="o">(</span><span class="n">element</span><span class="o">,</span> <span class="n">node</span><span class="o">(</span><span class="n">index</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">//将一个集合中元素添加在指定位置之后,注意双向链表中指针值的设置</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">addAll</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">,</span> <span class="n">Collection</span><span class="o">&lt;?</span> <span class="kd">extends</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">c</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//检验插入位置是否合法</span>
<span class="n">checkPositionIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="c1">//将这个集合中的保存到新数组中,再进行操作,这是一种“安全”的做法</span>
<span class="c1">//使用toArray的目的是为了调用者可以自由的操作这个数组,而不会影响原来的集合</span>
<span class="c1">//返回的是对象数组,因为将集合类本身并不知道具体是什么类型,因此无法以最具体的类型声明数组</span>
<span class="c1">//调用此方法也意味着我们要进行强制类型转换,不过可以像addAll这样通过参数的类型参数来限制保证正确的类型</span>
<span class="n">Object</span><span class="o">[]</span> <span class="n">a</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">toArray</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">numNew</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="c1">//arraylength指令(乱入一记字节码指令)</span>
<span class="k">if</span><span class="o">(</span><span class="n">numNew</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="c1">//声明两个变量(指针)用来辅助设置插入过程中前后结点的指针值</span>
<span class="c1">//保存succ最后修改这个结点的prev指针(如果不为空的话)</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">pred</span><span class="o">,</span> <span class="n">succ</span><span class="o">;</span>
<span class="c1">//插入位置正好是末尾,无法通过node()查找定位到</span>
<span class="c1">//否则找到index位置的结点,并确定pred的值</span>
<span class="k">if</span><span class="o">(</span><span class="n">index</span> <span class="o">==</span> <span class="n">size</span><span class="o">)</span> <span class="o">{</span>
<span class="n">pred</span> <span class="o">=</span> <span class="n">last</span><span class="o">;</span>
<span class="n">succ</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">succ</span> <span class="o">=</span> <span class="n">node</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="n">pred</span> <span class="o">=</span> <span class="n">succ</span><span class="o">.</span><span class="na">prev</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">for</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span> <span class="o">:</span> <span class="n">a</span><span class="o">)</span> <span class="o">{</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span> <span class="n">E</span> <span class="n">element</span> <span class="o">=</span> <span class="o">(</span><span class="n">E</span><span class="o">)</span><span class="n">o</span><span class="o">;</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">newNode</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Node</span><span class="o">&lt;&gt;(</span><span class="n">element</span><span class="o">,</span> <span class="n">pred</span><span class="o">,</span> <span class="n">succ</span><span class="o">);</span>
<span class="k">if</span><span class="o">(</span><span class="n">pred</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="c1">//在表头插入,设置frist值</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="k">else</span>
<span class="n">pred</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="n">pred</span> <span class="o">=</span> <span class="n">newNode</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//设置后续结点的prev</span>
<span class="k">if</span><span class="o">(</span><span class="n">succ</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="c1">//在末尾插入修改last的指向</span>
<span class="n">last</span> <span class="o">=</span> <span class="n">pred</span><span class="o">;</span>
<span class="k">else</span> <span class="o">{</span>
<span class="n">pred</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">succ</span><span class="o">;</span>
<span class="n">succ</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="n">pred</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">size</span> <span class="o">+=</span> <span class="n">numNew</span><span class="o">;</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">addAll</span><span class="o">(</span><span class="n">Collection</span><span class="o">&lt;?</span> <span class="kd">extends</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">c</span><span class="o">)</span> <span class="o">{</span>
<span class="n">addAll</span><span class="o">(</span><span class="n">size</span><span class="o">,</span> <span class="n">c</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">E</span> <span class="nf">get</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//检验索引值是否合法,不合法抛出异常</span>
<span class="n">checkElementIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="k">return</span> <span class="nf">node</span><span class="o">(</span><span class="n">index</span><span class="o">).</span><span class="na">item</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//设置并返回旧值</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">E</span> <span class="nf">set</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">,</span> <span class="n">E</span> <span class="n">element</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//检验索引值是否合法,不合法抛出异常</span>
<span class="n">checkElementIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">node</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="n">E</span> <span class="n">oldVal</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="n">x</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="n">element</span><span class="o">;</span>
<span class="k">return</span> <span class="n">oldVal</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">E</span> <span class="nf">remove</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="n">checkElementIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="k">return</span> <span class="nf">unlink</span><span class="o">(</span><span class="n">node</span><span class="o">(</span><span class="n">index</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">remove</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">o</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="na">item</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">unlink</span><span class="o">(</span><span class="n">x</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">o</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">))</span> <span class="o">{</span>
<span class="n">unlink</span><span class="o">(</span><span class="n">x</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//清空链表,尤其注意置空,让结点之间,结点和元素之间不在互相引用的存在堆中,让它们“独立”的接受垃圾回收</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">clear</span><span class="o">()</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;)</span> <span class="o">{</span>
<span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">next</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
<span class="c1">//置空,不要影响原来被引用对象的垃圾回收</span>
<span class="n">x</span><span class="o">.</span><span class="na">item</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">x</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">x</span><span class="o">.</span><span class="na">prev</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">next</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">last</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">size</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">++</span><span class="n">modCount</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//查找指定对象第一次出现的位置</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">indexOf</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">o</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="na">item</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="k">return</span> <span class="n">index</span><span class="o">;</span>
<span class="n">index</span><span class="o">++;</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">o</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">))</span>
<span class="k">return</span> <span class="n">index</span><span class="o">;</span>
<span class="n">index</span><span class="o">++;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//查找指定对象最后一次出现的位置</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">lastIndexOf</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">if</span><span class="o">(</span><span class="n">o</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">last</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">prev</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="na">item</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="k">return</span> <span class="n">index</span><span class="o">;</span>
<span class="n">index</span><span class="o">++;</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">last</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">prev</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">o</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">))</span>
<span class="k">return</span> <span class="n">index</span><span class="o">;</span>
<span class="n">index</span><span class="o">++;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">size</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">size</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//注意contains,indexOf,lastIndexOf方法接受的都是Object</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">contains</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">indexOf</span><span class="o">(</span><span class="n">o</span><span class="o">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//列表迭代器</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">ListIterator</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="nf">listIterator</span><span class="o">(</span><span class="kt">int</span> <span class="n">index</span><span class="o">)</span> <span class="o">{</span>
<span class="n">checkPositionIndex</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ListItr</span><span class="o">(</span><span class="n">index</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//保存为数组,这里只能返回Object,因为不能通过泛型参数创建对象/数组对象</span>
<span class="c1">//通过toArray方法可以自由操作该集合内元素而不影响该集合</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Object</span><span class="o">[]</span> <span class="nf">toArray</span><span class="o">()</span> <span class="o">{</span>
<span class="n">Object</span><span class="o">[]</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Object</span><span class="o">[</span><span class="n">size</span><span class="o">];</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="n">result</span><span class="o">[</span><span class="n">i</span><span class="o">++]</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//toArray的泛型方法版本,相对于toArray()来说可以进行必要的类型检查,但是创建数组的责任交给了调用者</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span><span class="o">[]</span> <span class="nf">toArray</span><span class="o">(</span><span class="n">T</span><span class="o">[]</span> <span class="n">a</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//检查长度是否能够存放所有元素</span>
<span class="k">if</span><span class="o">(</span><span class="n">a</span><span class="o">.</span><span class="na">length</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">)</span> <span class="c1">//小于size重新通过反射创建</span>
<span class="n">a</span> <span class="o">=</span> <span class="o">(</span><span class="n">T</span><span class="o">[])</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">reflect</span><span class="o">.</span><span class="na">Array</span><span class="o">.</span><span class="na">newInstance</span><span class="o">(</span>
<span class="n">a</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getComponentType</span><span class="o">(),</span> <span class="n">size</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">//通过Object数组引用,可以避开泛型参数的限制,数组对象本身可以检查存入的类型是否正确,不正确保存ArrayStoreException</span>
<span class="n">Object</span><span class="o">[]</span> <span class="n">result</span> <span class="o">=</span> <span class="n">a</span><span class="o">;</span>
<span class="k">for</span><span class="o">(</span><span class="n">Node</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">first</span><span class="o">;</span> <span class="n">x</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
<span class="n">result</span><span class="o">[</span><span class="n">i</span><span class="o">++]</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="na">item</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//如果数组长度大于集合长度,size位置置空</span>
<span class="k">if</span><span class="o">(</span><span class="n">a</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;</span> <span class="n">size</span><span class="o">)</span> <span class="o">{</span>
<span class="n">a</span><span class="o">[</span><span class="n">size</span><span class="o">]</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span>
</code></pre>
</div>
</li>
</ul>
</li>
<li>3-4 Deque双端队列的实现
<ul>
<li>3-4-1 与其他队列实现一样:offer(入队),poll(出队),peek(队首元素)不抛出异常,remove~(不同位置的删除方法),element(队首元素)为空是抛出异常;</li>
<li>3-4-2 现pop和push,栈操作,以链表头作为栈顶;
<div class="language-java highlighter-rouge"><pre class="highlight"><code> <span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">addFirst</span><span class="o">(</span><span class="n">E</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">linkFirst</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>