-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
1494 lines (1311 loc) · 399 KB
/
atom.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"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>akathink's blog</title>
<subtitle>AkaThink</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://akathink.com/"/>
<updated>2016-10-12T14:19:47.000Z</updated>
<id>http://akathink.com/</id>
<author>
<name>LiuQingJie</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Android开发规范</title>
<link href="http://akathink.com/2016/10/12/Android%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83/"/>
<id>http://akathink.com/2016/10/12/Android开发规范/</id>
<published>2016-10-12T14:16:53.000Z</published>
<updated>2016-10-12T14:19:47.000Z</updated>
<content type="html"><![CDATA[<h1 id="Android编码规范"><a href="#Android编码规范" class="headerlink" title="Android编码规范"></a>Android编码规范</h1><blockquote>
<p>因为要进行混合开发,RN所需环境是JDK1.8以上,所以统一使用JDK1.8以上。<br>IDE统一采用AndroidStudio最新版</p>
</blockquote>
<h2 id="1-源文件基础"><a href="#1-源文件基础" class="headerlink" title="1 源文件基础"></a>1 源文件基础</h2><h5 id="1-1-文件名"><a href="#1-1-文件名" class="headerlink" title="1.1 文件名"></a>1.1 文件名</h5><p>源文件以功能模块名称来命名,大小写敏感。</p>
<h5 id="1-2-文件编码:UTF-8"><a href="#1-2-文件编码:UTF-8" class="headerlink" title="1.2 文件编码:UTF-8"></a>1.2 文件编码:UTF-8</h5><p>源文件编码格式为UTF-8。</p>
<p>特殊字符:统一采用符号表来获取。</p>
<h2 id="2-命名规范"><a href="#2-命名规范" class="headerlink" title="2 命名规范"></a>2 命名规范</h2><p>注意:</p>
<ul>
<li>使用完整的英文描述命名</li>
<li>避免命名超长</li>
<li>避免相似的命名</li>
<li>慎用缩写,如果用到缩写,参考下一跳</li>
<li>按照缩写规则使用缩写</li>
</ul>
<h5 id="2-1-包命名规范"><a href="#2-1-包命名规范" class="headerlink" title="2.1 包命名规范"></a>2.1 包命名规范</h5><p> 采用反域名命名规则,包名全部小写,连续的单词只是简单地连接起来,不使用下划线,一级包名为com,二级包名为xxx(可以是公司域名或者个人命名),三级包名根据应用进行命名,四级包名为模块名或层级名。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">com.akathink.yinhua</div><div class="line">com.akathink.yinhua.ui</div></pre></td></tr></table></figure>
<h5 id="2-2-类命名规范"><a href="#2-2-类命名规范" class="headerlink" title="2.2 类命名规范"></a>2.2 类命名规范</h5><p>采用<strong>大驼峰式命名法</strong>,尽量避免缩写,除非该缩写是众所周知的,比如HTML,URL;如果类名称包含单词缩写,则单词缩写的每个字母均应大写。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">BaseActivity</span> | <span class="title">class</span> <span class="title">BaseListAdapter</span> | <span class="title">class</span> <span class="title">HomeLogic</span></span></div></pre></td></tr></table></figure>
<h5 id="2-3-接口命名规范"><a href="#2-3-接口命名规范" class="headerlink" title="2.3 接口命名规范"></a>2.3 接口命名规范</h5><p> 采用<strong>大驼峰命名法</strong>,多以<code>able</code>或<code>ible</code>结尾。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Runnabe</span> | <span class="title">interface</span> <span class="title">Accessible</span></span></div></pre></td></tr></table></figure>
<h5 id="2-4-变量命名"><a href="#2-4-变量命名" class="headerlink" title="2.4 变量命名"></a>2.4 变量命名</h5><p> 非静态成员变量Google的m命名法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> String mUserName;</div></pre></td></tr></table></figure>
<p> 静态成员变量Google的s命名法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> String sUserName;</div></pre></td></tr></table></figure>
<p> 临时变量、参数均以Java命名方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> String userName;</div></pre></td></tr></table></figure>
<h5 id="2-5-常量命名"><a href="#2-5-常量命名" class="headerlink" title="2.5 常量命名"></a>2.5 常量命名</h5><p>常量使用全大写字母加下划线的方式命名,避免代码中出现魔法数字和硬编码。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">"tag"</span>;</div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MOUDLE_TREAT = <span class="number">0</span>;</div></pre></td></tr></table></figure>
<h5 id="2-6-控件命名"><a href="#2-6-控件命名" class="headerlink" title="2.6 控件命名"></a>2.6 控件命名</h5><p>类中控件名称必须与xml布局文件中id保持一致。</p>
<p>在布局文件中Button的id为<code>android:id = "@+id/pay_btn"</code></p>
<p>类中的控件命名为<code>private Button mPayBtn</code></p>
<h5 id="2-7方法命名"><a href="#2-7方法命名" class="headerlink" title="2.7方法命名"></a>2.7方法命名</h5><p>采用<strong>小驼峰命名法</strong>,动词或名词。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">run();| onCrete()</div></pre></td></tr></table></figure>
<h5 id="2-8-layout命名"><a href="#2-8-layout命名" class="headerlink" title="2.8 layout命名"></a>2.8 layout命名</h5><p>全部小写,采用下划线命名法,使用模块名_功能名。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">login_activity.xml |</div></pre></td></tr></table></figure>
<h5 id="2-9-id命名"><a href="#2-9-id命名" class="headerlink" title="2.9 id命名"></a>2.9 id命名</h5><p>全部小写,采用下划线命名法,能通过id名直接理解当前组件要实现的功能。</p>
<p>命名模式:模块名称<em>view缩写 </em>逻辑名称</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@+id/login_name_edit 登录界面用户名输入框</div></pre></td></tr></table></figure>
<h5 id="2-10-资源命名"><a href="#2-10-资源命名" class="headerlink" title="2.10 资源命名"></a>2.10 资源命名</h5><p>全部小写,采用下划线命名法,使用模块名_用途来命名。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">login_btn_normal.9.png</div></pre></td></tr></table></figure>
<h5 id="2-11-动画文件命名"><a href="#2-11-动画文件命名" class="headerlink" title="2.11 动画文件命名"></a>2.11 动画文件命名</h5><p>全部小写,采用下划线命名法,加前缀区分。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">fade_in <span class="comment">//淡入</span></div><div class="line">fade_out<span class="comment">//淡出</span></div></pre></td></tr></table></figure>
<h2 id="3-类声明"><a href="#3-类声明" class="headerlink" title="3 类声明"></a>3 类声明</h2><h5 id="3-1-类成员顺序"><a href="#3-1-类成员顺序" class="headerlink" title="3.1 类成员顺序"></a>3.1 类成员顺序</h5><p>类成员顺序对易学性有很大的影响,不用的类对成员的排序可能是不同的。</p>
<p>但每个类应该以某种逻辑去排序。</p>
<p>类成员排列常用规则:</p>
<ul>
<li>按照发生的先后</li>
<li>常量按照使用先后</li>
<li>UI控件成员变量按照layout文件中的先后</li>
<li>普通成员变量按使用先后</li>
<li>方法基本按调用的先后在各自区块中排列</li>
<li>相关功能模块作为小区块放在一起</li>
</ul>
<h5 id="3-2-区块划分"><a href="#3-2-区块划分" class="headerlink" title="3.2 区块划分"></a>3.2 区块划分</h5><p>建议使用注释将文件分为明显的区块,划分如下</p>
<ul>
<li>常量声明区</li>
<li>UI控件成员变量声明区</li>
<li>普通成员变量声明区</li>
<li>内部接口声明区</li>
<li>初始化相关方法区</li>
<li>事件响应方法区</li>
<li>普通逻辑方法区</li>
<li>重载的逻辑方法区</li>
<li>发起异步任务方法区</li>
<li>异步任务回掉方法区</li>
<li>声明周期回掉方法区(除去onCreate()方法)</li>
<li>内部类声明区</li>
</ul>
<h5 id="3-3-重载:永不分离"><a href="#3-3-重载:永不分离" class="headerlink" title="3.3 重载:永不分离"></a>3.3 重载:永不分离</h5><p>当一个类有多个构造函数,或是多个同名方法,这些函数/方法应该按顺序出现。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PeoPle</span> </span>{</div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">PeoPle</span><span class="params">(String name)</span> </span>{</div><div class="line"> System.out.print(<span class="string">"name is "</span> + name);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">PeoPle</span><span class="params">(String name, <span class="keyword">int</span> age)</span> </span>{</div><div class="line"> System.out.print(<span class="string">"name is "</span> + name + <span class="string">"; age is "</span> + age);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>##</p>
<h2 id="4-注释"><a href="#4-注释" class="headerlink" title="4 注释"></a>4 注释</h2><h5 id="4-1-文件头注释-使用-注释"><a href="#4-1-文件头注释-使用-注释" class="headerlink" title="4.1 文件头注释 使用/* /注释"></a>4.1 文件头注释 使用/<em>* </em>/注释</h5><p>每个文件头都应注释,包含创建时间,作者,主要功能等。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/** *</span></div><div class="line">* Created by akathink on 2016/10/12.</div><div class="line">* 登陆界面</div><div class="line">*/</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span> </span>{</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</div><div class="line"> setContentView(R.layout.login_activity);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<h5 id="4-2-方法头注释-使用-注释"><a href="#4-2-方法头注释-使用-注释" class="headerlink" title="4.2 方法头注释 使用/* /注释"></a>4.2 方法头注释 使用/<em>* </em>/注释</h5><p>每一个成员(包含自定义成员方法,覆盖方法,属性方法)的方法头都必须做方法头注释。应该包含实现功能(用途),参数,返回值和抛出异常的列表等。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"> <span class="comment">/**</span></div><div class="line"> * 登陆接口</div><div class="line"> * <span class="doctag">@param</span> context context</div><div class="line"> * <span class="doctag">@param</span> request 回调</div><div class="line"> * <span class="doctag">@param</span> loginName 用户名</div><div class="line"> * <span class="doctag">@param</span> passWord 密码</div><div class="line"> * return null</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Login</span><span class="params">(Context context, JsonRequest request, String loginName, String passWord)</span> </span>{</div><div class="line"> request.addParams(<span class="string">"loginName"</span>, loginName);</div><div class="line"> request.addParams(<span class="string">"passWord"</span>, passWord);</div><div class="line"> BaseNetApi.baseRequest(context, <span class="string">"RMIS.API/api/MCommon/Login"</span>, request);</div><div class="line">}</div></pre></td></tr></table></figure>
<h5 id="4-3-块注释-使用-注释"><a href="#4-3-块注释-使用-注释" class="headerlink" title="4.3 块注释 使用//注释"></a>4.3 块注释 使用//注释</h5><p>在实现一段阶段性功能代码前做快注释。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 获取历史用户列表</span></div><div class="line">userList = AppContext.getInstance().getUserList();</div><div class="line"><span class="keyword">if</span>(userList != <span class="keyword">null</span> && userList.userInfoList != <span class="keyword">null</span> && userList.userInfoList.size() != <span class="number">0</span>) {</div><div class="line"> currentUserConfig = userList.userInfoList.get(<span class="number">0</span>);</div><div class="line">} <span class="keyword">else</span> {</div><div class="line"> currentUserConfig = <span class="keyword">new</span> MLoginHistory();</div><div class="line">}</div></pre></td></tr></table></figure>
<h5 id="4-4-变量注释-使用-注释"><a href="#4-4-变量注释-使用-注释" class="headerlink" title="4.4 变量注释 使用//注释"></a>4.4 变量注释 使用//注释</h5><p>所有成员变量和大多数局部变量在声明是做功能注释。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> String userName; <span class="comment">// 用户名</span></div><div class="line"><span class="keyword">public</span> String userPwd; <span class="comment">// 密码</span></div></pre></td></tr></table></figure>
<h5 id="4-5-语句注释-使用-注释"><a href="#4-5-语句注释-使用-注释" class="headerlink" title="4.5 语句注释 使用//注释"></a>4.5 语句注释 使用//注释</h5><p>在关键语句的右侧做单条语句注释。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">initView();<span class="comment">//初始化控件</span></div><div class="line">login();<span class="comment">//登录操作</span></div></pre></td></tr></table></figure>
<p>一个项目的注释风格要统一,并且要多使用注释。</p>
<h2 id="5-异常"><a href="#5-异常" class="headerlink" title="5 异常"></a>5 异常</h2><h5 id="5-1-不要忽略异常"><a href="#5-1-不要忽略异常" class="headerlink" title="5.1 不要忽略异常"></a>5.1 不要忽略异常</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">setServerPort</span><span class="params">(Strng value)</span></span>{</div><div class="line"> <span class="keyword">try</span>{</div><div class="line"> serverPort = Integer.parseInt(value);</div><div class="line"> }<span class="keyword">catch</span>(NumberFormatException e){}</div><div class="line">}</div></pre></td></tr></table></figure>
<p>有时代码永远不会碰到这种出错情况,或者处理异常并不重要,但必须在代码中以某种规矩来处理所有的异常。根据情况不同,处理方式不同。</p>
<p>可接受的替代方案包括:</p>
<ul>
<li>向方法的调用者抛出异常。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">setServerPort</span><span class="params">(String value)</span> <span class="keyword">throws</span> NumberFormatException</span>{</div><div class="line"> serverPort = Integer.parseInt(value);</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>根据抽象级别抛出新的异常。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">setServerPort</span><span class="params">(Strng value)</span> <span class="keyword">throws</span> ConfigurationException</span>{</div><div class="line"> <span class="keyword">try</span>{</div><div class="line"> serverPort = Integer.parseInt(value);</div><div class="line"> }<span class="keyword">catch</span>(NumberFormatException e){</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ConfigurationException(<span class="string">"port"</span> + value + <span class="string">"is not valid."</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>默默的处理错误并在catch{}语句块中替换为合适的值。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">setServerPort</span><span class="params">(Strng value)</span> <span class="keyword">throws</span> ConfigurationException</span>{</div><div class="line"> <span class="keyword">try</span>{</div><div class="line"> serverPort = Integer.parseInt(value);</div><div class="line"> }<span class="keyword">catch</span>(NumberFormatException e){</div><div class="line"> serverPort = <span class="number">80</span>;<span class="comment">// default port for server</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>捕获异常并抛出一个新的RuntimeException。这种做法比较危险:只有确信发生该错误时最合适的做法就是崩溃,才会这么做。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">setServerPort</span><span class="params">(Strng value)</span> <span class="keyword">throws</span> ConfigurationException</span>{</div><div class="line"> <span class="keyword">try</span>{</div><div class="line"> serverPort = Integer.parseInt(value);</div><div class="line"> }<span class="keyword">catch</span>(NumberFormatException e){</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"port "</span> + value <span class="string">" is invalid, "</span>, e); </div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li>如果确信忽略异常比较合适,就忽略,但必须把忽略的原因写出来。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">setServerPort</span><span class="params">(Strng value)</span> <span class="keyword">throws</span> ConfigurationException</span>{</div><div class="line"> <span class="keyword">try</span>{</div><div class="line"> serverPort = Integer.parseInt(value);</div><div class="line"> }<span class="keyword">catch</span>(NumberFormatException e){</div><div class="line"> <span class="comment">// Method is documented to just ignore invalid user input. </span></div><div class="line"> <span class="comment">// serverPort will just be unchanged. </span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<h5 id="5-2-不要捕获顶级的exception"><a href="#5-2-不要捕获顶级的exception" class="headerlink" title="5.2 不要捕获顶级的exception"></a>5.2 不要捕获顶级的exception</h5><p>绝大部分情况下,捕获顶级的Exception或Throwable都是不合适的,Throwable更不合适,因为它还包含了Error异常。这种捕获非常危险。这意味着本来不必考虑的Exception(包括类似ClassCastException的RuntimeException)被卷入到应用程序级的错误处理中来。这会让代码运行的错误变得模糊不清。例:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">try</span>{</div><div class="line"> someComplicatedIOFunction(); <span class="comment">// may throw IOException </span></div><div class="line"> someComplicatedParsingFunction(); <span class="comment">// may throw ParsingException </span></div><div class="line"> someComplicatedSecurityFunction(); <span class="comment">// may throw SecurityException </span></div><div class="line">}<span class="keyword">catch</span>(Exception e){</div><div class="line"> handleError();</div><div class="line">}</div></pre></td></tr></table></figure>
<p>比捕获顶级Exception更好的方案:</p>
<ul>
<li>分开捕获每一种异常,一条try语句后面跟随多个catch语句</li>
<li>使用多个try块。</li>
<li>再次抛出异常。</li>
</ul>
<h5 id="5-3-import"><a href="#5-3-import" class="headerlink" title="5.3 import"></a>5.3 import</h5><p>使用完全限定的import,尽量不使用顶级导包、不适用通配符。</p>
<p>import语句不换行。</p>
<p>例:当需要使用foo包红的bar类时,存在两种可能:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> foo.*;<span class="comment">//可能会减少import语句,不建议使用</span></div></pre></td></tr></table></figure>
<p>或者:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> foo.bar;<span class="comment">//代码的可读性更好,便于维护</span></div></pre></td></tr></table></figure>
<h2 id="6-Log"><a href="#6-Log" class="headerlink" title="6 Log"></a>6 Log</h2><p>记录日志会对性能产生显著的负面影响。如果日志不厚简练的话,很快会丧失可用性。日志包含5中不同的级别。</p>
<p>使用通用的LogUtil类取代原生Log类。</p>
<h5 id="6-1-ERROR"><a href="#6-1-ERROR" class="headerlink" title="6.1 ERROR"></a>6.1 ERROR</h5><p>该级别日志应在致命错误发生时使用。也就是说,错误的后果能被用户看到,但是不明确删除部分数据、卸装程序、清除数据区或重新刷机(或更糟糕)就无法恢复。该级别总是记录日志。需要记录ERROR级别日志的事件一般都应该向统计信息收集(statistics-gathering )服务器报告。 </p>
<h5 id="6-2-WARNING"><a href="#6-2-WARNING" class="headerlink" title="6.2 WARNING"></a>6.2 WARNING</h5><p>该级别日志应该用于哪些重大的、意外的事件。也就是说,错误的后果能被用户看到,但是不采取明确的动作可能就无法无损恢复,从等待或重启应用开始,直至重新下载新版程序或重启设备。该级别总是记录日志。需记录WARNING级别日志的事件也可以考虑向统计信息收集服务器报告。 </p>
<h5 id="6-3-INFORMATIVE"><a href="#6-3-INFORMATIVE" class="headerlink" title="6.3 INFORMATIVE"></a>6.3 INFORMATIVE</h5><p>该级别日志应该用于记录大部分人都会感兴趣的事件。也就是说,如果检测到事件的影响面可能很广,但不一定是错误。应该只有那些拥有本区域内最高级别身份认证的模块才能记录这些日志(为了避免级别不足的模块重复记录日志)。该级别总是记录日志。 </p>
<h5 id="6-4-DEBUG"><a href="#6-4-DEBUG" class="headerlink" title="6.4 DEBUG"></a>6.4 DEBUG</h5><p>该级别日志应该用于进一步记录有关调查、调试意外现象的设备事件。应该只记录那些有关控件运行所必需的信息。如果debug日志占用了太多的日志空间,那就应该使用详细级别日志(verbose)才更为合适。 </p>
<h5 id="6-5-VERBOSE"><a href="#6-5-VERBOSE" class="headerlink" title="6.5 VERBOSE"></a>6.5 VERBOSE</h5><p>该级别日志应用于所有其余的事件。</p>
<h2 id="7-代码规约"><a href="#7-代码规约" class="headerlink" title="7 代码规约"></a>7 代码规约</h2><h5 id="7-1-方法"><a href="#7-1-方法" class="headerlink" title="7.1 方法"></a>7.1 方法</h5><p>一个方法尽量不要超过50行。如果方法太长,需要进行方法拆分。</p>
<p>保证每个方法只做一件事,不要使用try catch处理业务逻辑。</p>
<h5 id="7-2-参数和返回值"><a href="#7-2-参数和返回值" class="headerlink" title="7.2 参数和返回值"></a>7.2 参数和返回值</h5><p>一个方法的参数尽可能不超过4个;</p>
<p>如果方法返回一个错误码,请使用异常;</p>
<p>尽可能不要使用null,替代为异常,或者使用空变量。</p>
<h5 id="7-3-数字"><a href="#7-3-数字" class="headerlink" title="7.3 数字"></a>7.3 数字</h5><p>代码中不允许出现单独的数字、字符,如果需要使用,将他们按照含义封装成静态变量。</p>
<h5 id="7-4-控制语句"><a href="#7-4-控制语句" class="headerlink" title="7.4 控制语句"></a>7.4 控制语句</h5><p>判断中如有常量,则应该将常量置于判断式的右侧。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span>( isAdmin() == <span class="keyword">true</span>)...</div></pre></td></tr></table></figure>
<h5 id="7-5-变量赋值"><a href="#7-5-变量赋值" class="headerlink" title="7.5 变量赋值"></a>7.5 变量赋值</h5><p>避免在一个语句中给多个变量赋相同的值。</p>
<p>不要将赋值运算符用爱容易于相等关系运算符混肴的地方。</p>
<p>不要使用内嵌赋值运算符视图提高运行时的效率。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//错误</span></div><div class="line">d = (a = b + c) + r;</div><div class="line"><span class="comment">//应该写成</span></div><div class="line">a = b + c;</div><div class="line">d = a + r;</div></pre></td></tr></table></figure>
<h5 id="7-6-大括号"><a href="#7-6-大括号" class="headerlink" title="7.6 大括号"></a>7.6 大括号</h5><p>大括号与if,else,for,do,while语句一起使用,即使只有一条语句或者空,都应把大括号加上。</p>
<p>对于非空快和块状结构,大括号遵循Kernighan和Ritchie风格Egyptian brackets:</p>
<ul>
<li>左大括号前不换行</li>
<li>左大括号后换行</li>
<li>右大括号前换行</li>
<li>如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行。例如,如果右大括号后面是else或逗号,则不换行。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">loginOnClickListener</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span> </span>{ </div><div class="line"> <span class="meta">@Override</span> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>{ </div><div class="line"> <span class="keyword">if</span>((<span class="keyword">int</span>) view.getTag() == currentPos){ </div><div class="line"> <span class="keyword">return</span>; </div><div class="line"> } </div><div class="line"> login(); </div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>一个空的块状结构离什么都不包含,大括号可以简洁写出{},不需要换行。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">doNothing</span><span class="params">()</span></span>{};</div></pre></td></tr></table></figure>
<h5 id="7-7-块缩进:2个空格"><a href="#7-7-块缩进:2个空格" class="headerlink" title="7.7 块缩进:2个空格"></a>7.7 块缩进:2个空格</h5><p>开始一个新的块,缩进增加两个空格,块结束时,缩进返回先前的缩进级别。</p>
<h5 id="7-8-枚举类"><a href="#7-8-枚举类" class="headerlink" title="7.8 枚举类"></a>7.8 枚举类</h5><p>枚举常量间用逗号隔开,所有适用于其他类的格式也适用于枚举类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="keyword">enum</span> Suit{ </div><div class="line"> CLUBS,</div><div class="line"> HEARTS,</div><div class="line"> SPADES,</div><div class="line"> DIAMONDS</div><div class="line">}</div></pre></td></tr></table></figure>
<h5 id="7-9-变量声明"><a href="#7-9-变量声明" class="headerlink" title="7.9 变量声明"></a>7.9 变量声明</h5><p>每次只声明一个变量,不要使用组合声明。</p>
<p>需要时才声明,并尽快进行初始化。</p>
<p>限制变量的作用范围。</p>
<h5 id="7-10-switch语句"><a href="#7-10-switch语句" class="headerlink" title="7.10 switch语句"></a>7.10 switch语句</h5><p>switch块中的内容缩进为2个空格,每个switch标签后新起一行。</p>
<p>在switch块内,每个语句组通过break,continue,return或抛出异常来终止。</p>
<p>default的情况要写出来,即使什么代码也不包含。</p>
<h5 id="7-11-其他要求"><a href="#7-11-其他要求" class="headerlink" title="7.11 其他要求"></a>7.11 其他要求</h5><ul>
<li>代码中尽量不要出现中文。注释除外。代码中通过string.xml引用来来显示中文。</li>
<li>控件声明放在activity级别。</li>
<li>在一个View.OnClickListener中处理所有的点击事件逻辑,</li>
<li>界面之间传值尽量使用intent方式,少用全局变量。</li>
<li>不建议在布局文件中添加点击事件。</li>
<li>数据类型转换一定要检验。</li>
<li>使用常量代替枚举。</li>
<li>实体不要在不同模块间共享,但可以在统一模块下的不同页面共享。</li>
</ul>
<h2 id="8-封装"><a href="#8-封装" class="headerlink" title="8 封装"></a>8 封装</h2><ol>
<li><p>自定义UI组件替代原生组件</p>
<p><strong>原因:</strong>有的时候,我们可能更换字体或者Image的加载方式,若是使用自定义组件的话,则需要将用到这些组件的地方都得做相应的处理,若是采用自定义组件的话,则只需更改一处,易于维护。</p>
<p>若是自定义UI组件,则需要以UI开头,例如UITextView,目的是为了避免在引包的时候,不会引成谷歌官方的包。</p>
</li>
<li><p>凡是使用的第三方组件均需做一定的封装,不要直接使用第三方组件。</p>
</li>
</ol>
<h3 id="缩写规则"><a href="#缩写规则" class="headerlink" title="缩写规则"></a>缩写规则</h3><ul>
<li>view缩写</li>
</ul>
<table>
<thead>
<tr>
<th>控件</th>
<th>布局文件中缩写</th>
<th>代码中缩写</th>
</tr>
</thead>
<tbody>
<tr>
<td>LinearLayout</td>
<td>xxx_layout</td>
<td>xxxLLayout</td>
</tr>
<tr>
<td>RelativeLayout</td>
<td>xxx_layout</td>
<td>xxxRLayout</td>
</tr>
<tr>
<td>TextView</td>
<td>xxx_tv</td>
<td>xxxTv</td>
</tr>
<tr>
<td>EditText</td>
<td>xxx_edt</td>
<td>xxxEdt</td>
</tr>
<tr>
<td>Button</td>
<td>xxx_btn</td>
<td>xxxBtn</td>
</tr>
<tr>
<td>ImageView</td>
<td>xxx_iv</td>
<td>xxxIv</td>
</tr>
<tr>
<td>RadioButton</td>
<td>xxx_rbtn</td>
<td>xxxRbtn</td>
</tr>
<tr>
<td>ListView</td>
<td>xxx_lv</td>
<td>xxxLv</td>
</tr>
<tr>
<td>ProgressBar</td>
<td>xxx_pbar</td>
<td>xxxPbar</td>
</tr>
</tbody>
</table>
<ul>
<li>包包含</li>
</ul>
<table>
<thead>
<tr>
<th>包名</th>
<th>此包中包含</th>
</tr>
</thead>
<tbody>
<tr>
<td>com.xx.yinhua.activity</td>
<td>页面用到的Activity类 (activities层级名用户界面层)</td>
</tr>
<tr>
<td>com.xx.yinhua.base</td>
<td>页面中每个Activity类共享的可以写成一个BaseActivity类 (所有Activity类均需继承自该类)</td>
</tr>
<tr>
<td>com.xx.yinhua.adapter</td>
<td>页面用到的Adapter类 (适配器的类)</td>
</tr>
<tr>
<td>com.xx.yinhua.tools</td>
<td>公共工具方法类(tools模块名)</td>
</tr>
<tr>
<td>com.xx.yinhua.bean//或者.unity</td>
<td>元素类</td>
</tr>
<tr>
<td>com.xx.yinhua.db</td>
<td>数据库操作类</td>
</tr>
<tr>
<td>com.xx.yinhua.view//或者.ui</td>
<td>自定义的View类等</td>
</tr>
<tr>
<td>com.xx.yinhua.service</td>
<td>Service服务</td>
</tr>
<tr>
<td>com.xx.yinhua.broadcast</td>
<td>Broadcast服务</td>
</tr>
</tbody>
</table>
<ul>
<li>类缩写描述</li>
</ul>
<table>
<thead>
<tr>
<th>类</th>
<th>描述</th>
<th>例如</th>
</tr>
</thead>
<tbody>
<tr>
<td>activity 类</td>
<td>Activity为后缀标识</td>
<td>登录页面LoginActivity</td>
</tr>
<tr>
<td>Adapter类</td>
<td>Adapter为后缀标识</td>
<td>Adapte 为后缀标识</td>
</tr>
<tr>
<td>解析类</td>
<td>Hlr为后缀标识</td>
<td>首页解析类HomePosterHlr</td>
</tr>
<tr>
<td>公共方法类</td>
<td>Tools或Manager为后缀标识</td>
<td>日志工具类LogTools</td>
</tr>
<tr>
<td>数据库类</td>
<td>以DBHelper后缀标识</td>
<td>用户数据库UserDBHelper</td>
</tr>
<tr>
<td>Service类</td>
<td>以Service为后缀标识</td>
<td>时间服务TimeService</td>
</tr>
<tr>
<td>Broadcast类</td>
<td>Broadcast类</td>
<td>时间通知TimeBroadcast</td>
</tr>
<tr>
<td>ContentProvider</td>
<td>以Provider为后缀标识</td>
<td></td>
</tr>
<tr>
<td>直接写的共享基础类</td>
<td>以Base开头</td>
<td>BaseActivity,BaseFragment</td>
</tr>
</tbody>
</table>
]]></content>
<summary type="html">
<h1 id="Android编码规范"><a href="#Android编码规范" class="headerlink" title="Android编码规范"></a>Android编码规范</h1><blockquote>
<p>因为要进行混合开发,RN所需环境是JDK1
</summary>
<category term="Android" scheme="http://akathink.com/categories/Android/"/>
<category term="开发规范" scheme="http://akathink.com/categories/Android/%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83/"/>
<category term="Android" scheme="http://akathink.com/tags/Android/"/>
<category term="开发规范" scheme="http://akathink.com/tags/%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83/"/>
</entry>
<entry>
<title>招式:轻松实现HomeLayout</title>
<link href="http://akathink.com/2016/09/03/%E6%8B%9B%E5%BC%8F%EF%BC%9A%E8%BD%BB%E6%9D%BE%E5%AE%9E%E7%8E%B0HomeLayout/"/>
<id>http://akathink.com/2016/09/03/招式:轻松实现HomeLayout/</id>
<published>2016-09-03T04:26:53.000Z</published>
<updated>2016-09-03T04:28:37.000Z</updated>
<summary type="html">
</summary>
<category term="招式" scheme="http://akathink.com/categories/%E6%8B%9B%E5%BC%8F/"/>
<category term="Android" scheme="http://akathink.com/categories/%E6%8B%9B%E5%BC%8F/Android/"/>
<category term="自定义View" scheme="http://akathink.com/categories/%E6%8B%9B%E5%BC%8F/Android/%E8%87%AA%E5%AE%9A%E4%B9%89View/"/>
<category term="HomeLayout" scheme="http://akathink.com/categories/%E6%8B%9B%E5%BC%8F/Android/%E8%87%AA%E5%AE%9A%E4%B9%89View/HomeLayout/"/>
<category term="Android" scheme="http://akathink.com/tags/Android/"/>
<category term="招式" scheme="http://akathink.com/tags/%E6%8B%9B%E5%BC%8F/"/>
<category term="自定义View" scheme="http://akathink.com/tags/%E8%87%AA%E5%AE%9A%E4%B9%89View/"/>
<category term="HomeLayout" scheme="http://akathink.com/tags/HomeLayout/"/>
</entry>
<entry>
<title>全面了解Android ANR</title>
<link href="http://akathink.com/2016/08/13/%E5%85%A8%E9%9D%A2%E4%BA%86%E8%A7%A3Android-ANR/"/>
<id>http://akathink.com/2016/08/13/全面了解Android-ANR/</id>
<published>2016-08-13T09:24:30.000Z</published>
<updated>2016-08-13T10:06:29.000Z</updated>
<content type="html"><![CDATA[<h1 id="什么是ANR?"><a href="#什么是ANR?" class="headerlink" title="什么是ANR?"></a>什么是ANR?</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">ANR:Application Not Responding,即应用无响应</div></pre></td></tr></table></figure>
<h1 id="ANR的类型"><a href="#ANR的类型" class="headerlink" title="ANR的类型"></a>ANR的类型</h1><p>ANR一般有三种类型:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">1. KeyDispatchTimeout(5 seconds) --主要类型按键或触摸事件在特定时间内无响应</div><div class="line"></div><div class="line">2. BroadcastTimeout(10 seconds) --BroadcastReceiver在特定时间内无法处理完成</div><div class="line"></div><div class="line">3. ServiceTimeout(20 seconds) --小概率类型 Service在特定的时间内无法处理完成</div></pre></td></tr></table></figure></p>
<h1 id="KeyDispatchTimeout"><a href="#KeyDispatchTimeout" class="headerlink" title="KeyDispatchTimeout"></a>KeyDispatchTimeout</h1><p>A key or touch event was not dispatched within the specified time(按键或触摸事件在特定时间内无响应)<br>具体的超时时间的定义在framework下的ActivityManagerService.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// How long we wait until we timeout on key dispatching.</span></div><div class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> KEY_DISPATCHING_TIMEOUT = <span class="number">5</span>*<span class="number">1000</span>;</div></pre></td></tr></table></figure>
<h1 id="为什么会超时呢?"><a href="#为什么会超时呢?" class="headerlink" title="为什么会超时呢?"></a>为什么会超时呢?</h1><p>超时时间的计数一般是从按键分发给app开始。超时的原因一般有两种:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">1. 当前的事件没有机会得到处理(即UI线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)</div><div class="line"></div><div class="line">2. 当前的事件正在处理,但没有及时完成</div></pre></td></tr></table></figure>
<h1 id="如何避免KeyDispatchTimeout"><a href="#如何避免KeyDispatchTimeout" class="headerlink" title="如何避免KeyDispatchTimeout"></a>如何避免KeyDispatchTimeout</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">1. UI线程尽量只做跟UI相关的工作</div><div class="line"></div><div class="line">2. 耗时的工作(比如数据库操作,I/O,连接网络或者别的有可能阻碍UI线程的操作)把它放入单独的线程处理</div><div class="line"></div><div class="line">3. 尽量用Handler来处理UIthread和别的thread之间的交互</div></pre></td></tr></table></figure>
<h1 id="UI线程"><a href="#UI线程" class="headerlink" title="UI线程"></a>UI线程</h1><p>说了那么多的UI线程,那么哪些属于UI线程呢?</p>
<p>UI线程主要包括如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">1. Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc</div><div class="line"></div><div class="line">2. AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc</div><div class="line"></div><div class="line">3. Mainthread handler: handleMessage(), post*(runnable r), etc</div><div class="line"></div><div class="line">4. other</div></pre></td></tr></table></figure>
<h1 id="如何去分析ANR"><a href="#如何去分析ANR" class="headerlink" title="如何去分析ANR"></a>如何去分析ANR</h1><p>先看个LOG:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line">04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}.</div><div class="line">5009.8ms since event, 5009.5ms since waitstarted</div><div class="line">04-0113:12:11.572 I/WindowManager( 220): Input event</div><div class="line">dispatching timedout sending</div><div class="line">tocom.android.email/com.android.email.activity.SplitScreenActivity</div><div class="line">04-01 13:12:14.123 I/Process( 220): Sending signal. PID: 21404 SIG: 3---发生ANR的时间和生成trace.txt的时间</div><div class="line">04-01 13:12:14.123 I/dalvikvm(21404):threadid=4: reacting to</div><div class="line">signal 3</div><div class="line">……</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): ANR in</div><div class="line">com.android.email(com.android.email/.activity.SplitScreenActivity)</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220):</div><div class="line">Reason:keyDispatchingTimedOut</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): Load: 8.68 / 8.37 / 8.53</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 4361ms to 699ms ago ----CPU在ANR发生前的使用情况</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 5.5%21404/com.android.email: 1.3% user + 4.1% kernel / faults:</div><div class="line">10 minor</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 4.3%220/system_server: 2.7% user + 1.5% kernel / faults: 11</div><div class="line">minor 2 major</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 0.9%52/spi_qsd.0: 0% user + 0.9% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 0.5%65/irq/170-cyttsp-: 0% user + 0.5% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 0.5%296/com.android.systemui: 0.5% user + 0% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 3697ms to 4223ms later:-- ANR后CPU的使用量</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 25%21404/com.android.email: 25% user + 0% kernel / faults: 191 minor</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 16% 21603/__eas(par.hakan: 16% user + 0% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 7.2% 21406/GC: 7.2% user + 0% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 1.8% 21409/Compiler: 1.8% user + 0% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 5.5%220/system_server: 0% user + 5.5% kernel / faults: 1 minor</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 5.5% 263/InputDispatcher: 0% user + 5.5% kernel</div><div class="line">04-0113:12:15.872 E/ActivityManager( 220): 32%TOTAL: 28% user + 3.7% kernel</div></pre></td></tr></table></figure>
<p>从LOG可以看出ANR的类型,CPU的使用情况,如果CPU使用量接近100%,说明当前设备很忙,有可能是CPU饥饿导致了ANR</p>
<p>如果CPU使用量很少,说明主线程被BLOCK了</p>
<p>如果IOwait很高,说明ANR有可能是主线程在进行I/O操作造成的</p>
<p>除了看LOG,解决ANR还得需要trace.txt文件,</p>
<p>如何获取呢?可以用如下命令获取</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">$chmod 777 /data/anr</div><div class="line"></div><div class="line">$rm /data/anr/traces.txt</div><div class="line"></div><div class="line">$ps</div><div class="line"></div><div class="line">$kill -3 PID</div></pre></td></tr></table></figure>
<p>adbpull data/anr/traces.txt ./mytraces.txt</p>
<p>从trace.txt文件,看到最多的是如下的信息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">-----pid 21404 at 2011-04-01 13:12:14 -----</div><div class="line">Cmdline: com.android.email</div><div class="line"></div><div class="line">DALVIK THREADS:</div><div class="line">(mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)</div><div class="line">"main" prio=5 tid=1NATIVE</div><div class="line">| group="main" sCount=1 dsCount=0obj=0x2aad2248 self=0xcf70</div><div class="line">| sysTid=21404 nice=0 sched=0/0cgrp=[fopen-error:2]</div><div class="line">handle=1876218976</div><div class="line">atandroid.os.MessageQueue.nativePollOnce(Native Method)</div><div class="line">atandroid.os.MessageQueue.next(MessageQueue.java:119)</div><div class="line">atandroid.os.Looper.loop(Looper.java:110)</div><div class="line">at android.app.ActivityThread.main(ActivityThread.java:3688)</div><div class="line">at java.lang.reflect.Method.invokeNative(Native Method)</div><div class="line">atjava.lang.reflect.Method.invoke(Method.java:507)</div><div class="line"></div><div class="line">atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)</div><div class="line">at</div><div class="line">com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)</div><div class="line">at dalvik.system.NativeStart.main(Native Method)</div></pre></td></tr></table></figure>
<p>说明主线程在等待下条消息进入消息队列</p>
<h1 id="Thread状态"><a href="#Thread状态" class="headerlink" title="Thread状态"></a>Thread状态</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">ThreadState (defined at “dalvik/vm/thread.h “)</div><div class="line"></div><div class="line">THREAD_UNDEFINED = -1, /* makes enum compatible with int32_t */</div><div class="line"></div><div class="line">THREAD_ZOMBIE = 0, /* TERMINATED */</div><div class="line"></div><div class="line">THREAD_RUNNING = 1, /* RUNNABLE or running now */</div><div class="line"></div><div class="line">THREAD_TIMED_WAIT = 2, /* TIMED_WAITING in Object.wait() */</div><div class="line"></div><div class="line">THREAD_MONITOR = 3, /* BLOCKED on a monitor */</div><div class="line"></div><div class="line">THREAD_WAIT = 4, /* WAITING in Object.wait() */</div><div class="line"></div><div class="line">THREAD_INITIALIZING= 5, /* allocated, not yet running */</div><div class="line"></div><div class="line">THREAD_STARTING = 6, /* started, not yet on thread list */</div><div class="line"></div><div class="line">THREAD_NATIVE = 7, /* off in a JNI native method */</div><div class="line"></div><div class="line">THREAD_VMWAIT = 8, /* waiting on a VM resource */</div><div class="line"></div><div class="line">THREAD_SUSPENDED = 9, /* suspended, usually by GC or debugger */</div></pre></td></tr></table></figure>
<h1 id="如何调查并解决ANR"><a href="#如何调查并解决ANR" class="headerlink" title="如何调查并解决ANR"></a>如何调查并解决ANR</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">1. 首先分析log</div><div class="line"></div><div class="line">2. 从trace.txt文件查看调用stack.</div><div class="line"></div><div class="line">3. 看代码</div><div class="line"></div><div class="line">4. 仔细查看ANR的成因(iowait?block?memoryleak?)</div></pre></td></tr></table></figure>
<h1 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h1><ul>
<li>案例1:关键词:ContentResolver in AsyncTask onPostExecute, high iowait</li>
</ul>
<p>原因:IOWait很高,说明当前系统在忙于I/O,因此数据库操作被阻塞</p>
<p>原来:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> Message message=Message.restoreMessageWithId(mProviderContext,messageId);</div><div class="line"> <span class="keyword">if</span>(message==<span class="keyword">null</span>){</div><div class="line"> <span class="keyword">return</span>;</div><div class="line">}</div><div class="line">Account account=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);</div><div class="line"><span class="keyword">if</span>(account==<span class="keyword">null</span>){</div><div class="line"> <span class="keyword">return</span>;<span class="comment">//isMessagingController returns false for null, but let's make itclear.</span></div><div class="line">}</div><div class="line"><span class="keyword">if</span>(isMessagingController(account)){</div><div class="line"> <span class="keyword">new</span> Thread(){</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>{</div><div class="line"> mLegacyController.processPendingActions(message.mAccountKey);</div><div class="line"> }}.start();</div><div class="line">}</div></pre></td></tr></table></figure>
<p>解决后:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">newThread() {</div><div class="line"> finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);</div><div class="line"> <span class="keyword">if</span>(message==<span class="keyword">null</span>){</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);</div><div class="line"> <span class="keyword">if</span>(account==<span class="keyword">null</span>){</div><div class="line"> <span class="keyword">return</span>;<span class="comment">//isMessagingController returns false for null, but let's make itclear.</span></div><div class="line"> }</div><div class="line"> <span class="keyword">if</span>(isMessagingController(account)) {</div><div class="line"> mLegacyController.processPendingActions(message.mAccountKey);</div><div class="line"> }</div><div class="line">}.start();</div></pre></td></tr></table></figure>
<p>关于AsyncTask:<a href="http://developer.android.com/reference/android/os/AsyncTask.html" target="_blank" rel="external">http://developer.android.com/reference/android/os/AsyncTask.html</a></p>
<ul>
<li>案例2:关键词:在UI线程进行网络数据的读写</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line">ANRin process: com.android.mediascape:PhotoViewer (last incom.android.mediascape:PhotoViewer)</div><div class="line"> Annotation:keyDispatchingTimedOut</div><div class="line"> CPU usage:</div><div class="line"> Load: <span class="number">6.74</span> / <span class="number">6.89</span> / <span class="number">6.12</span></div><div class="line"> CPUusage from <span class="number">8254</span>ms to <span class="number">3224</span>ms ago:</div><div class="line"> ovider.webmedia: <span class="number">4</span>% = <span class="number">4</span>% user +<span class="number">0</span>% kernel / faults: <span class="number">68</span> minor</div><div class="line"> system_server: <span class="number">2</span>% = <span class="number">1</span>% user + <span class="number">0</span>%kernel / faults: <span class="number">18</span> minor</div><div class="line"> re-initialized>: <span class="number">0</span>% = <span class="number">0</span>% user + <span class="number">0</span>%kernel / faults: <span class="number">50</span> minor</div><div class="line"> events/<span class="number">0</span>: <span class="number">0</span>% = <span class="number">0</span>% user + <span class="number">0</span>%kernel</div><div class="line"> TOTAL:<span class="number">7</span>% = <span class="number">6</span>% user + <span class="number">1</span>% kernel</div><div class="line"></div><div class="line"> DALVIKTHREADS:</div><div class="line"> <span class="string">""</span>main<span class="string">""</span> prio=<span class="number">5</span> tid=<span class="number">3</span> NATIVE</div><div class="line"> |group=<span class="string">""</span>main<span class="string">""</span> sCount=<span class="number">1</span> dsCount=<span class="number">0</span> s=Yobj=<span class="number">0x4001b240</span> self=<span class="number">0xbda8</span></div><div class="line"> | sysTid=<span class="number">2579</span> nice=<span class="number">0</span> sched=<span class="number">0</span>/<span class="number">0</span>cgrp=unknown handle=-<span class="number">1343993184</span></div><div class="line"> atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStreamImpl(NativeMethod)</div><div class="line"> atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStream(OSNetworkSystem.java:<span class="number">478</span>)</div><div class="line"> atorg.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:<span class="number">565</span>)</div><div class="line"> atorg.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:<span class="number">87</span>)</div><div class="line"> atorg.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection$LimitedInputStream.read(HttpURLConnection.java:<span class="number">303</span>)</div><div class="line"> atjava.io.InputStream.read(InputStream.java:<span class="number">133</span>)</div><div class="line"> atjava.io.BufferedInputStream.fillbuf(BufferedInputStream.java:<span class="number">157</span>)</div><div class="line"> atjava.io.BufferedInputStream.read(BufferedInputStream.java:<span class="number">346</span>)</div><div class="line"> atandroid.graphics.BitmapFactory.nativeDecodeStream(Native Method)</div><div class="line"> atandroid.graphics.BitmapFactory.decodeStream(BitmapFactory.java:<span class="number">459</span>)</div><div class="line"> atcom.android.mediascape.activity.PhotoViewerActivity.getPreviewImage(PhotoViewerActivity.java:<span class="number">4465</span>)</div><div class="line"> atcom.android.mediascape.activity.PhotoViewerActivity.dispPreview(PhotoViewerActivity.java:<span class="number">4406</span>)</div><div class="line"> atcom.android.mediascape.activity.PhotoViewerActivity.access$<span class="number">6500</span>(PhotoViewerActivity.java:<span class="number">125</span>)</div><div class="line"> atcom.android.mediascape.activity.PhotoViewerActivity$<span class="number">33</span>$<span class="number">1</span>.run(PhotoViewerActivity.java:<span class="number">4558</span>)</div><div class="line"> atandroid.os.Handler.handleCallback(Handler.java:<span class="number">587</span>)</div><div class="line"> atandroid.os.Handler.dispatchMessage(Handler.java:<span class="number">92</span>)</div><div class="line"> atandroid.os.Looper.loop(Looper.java:<span class="number">123</span>)</div><div class="line"> atandroid.app.ActivityThread.main(ActivityThread.java:<span class="number">4370</span>)</div><div class="line"> atjava.lang.reflect.Method.invokeNative(Native Method)</div><div class="line"> atjava.lang.reflect.Method.invoke(Method.java:<span class="number">521</span>)</div><div class="line"> atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:<span class="number">868</span>)</div><div class="line"> atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:<span class="number">626</span>)</div><div class="line"> atdalvik.system.NativeStart.main(Native Method)</div></pre></td></tr></table></figure>
<p>关于网络连接,在设计的时候可以设置个timeout的时间或者放入独立的线程来处理。</p>
<p>关于Handler的问题,可以参考:<a href="http://developer.android.com/reference/android/os/Handler.html" target="_blank" rel="external">http://developer.android.com/reference/android/os/Handler.html</a></p>
<ul>
<li>案例3:关键词:Memoryleak/Thread leak</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div></pre></td><td class="code"><pre><div class="line"><span class="number">11</span>-<span class="number">1621</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager( <span class="number">1190</span>): ANR in process:android.process.acore (last in android.process.acore)</div><div class="line"> <span class="number">11</span>-<span class="number">1621</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager( <span class="number">1190</span>): Annotation:keyDispatchingTimedOut</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager(<span class="number">1190</span>): CPU usage:</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager( <span class="number">1190</span>):Load: <span class="number">11.5</span> / <span class="number">11.1</span> / <span class="number">11.09</span></div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager(<span class="number">1190</span>): CPU usage from <span class="number">9046</span>ms to <span class="number">4018</span>ms ago:</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span>I/ActivityManager( <span class="number">1190</span>): d.process.acore:<span class="number">98</span>%= <span class="number">97</span>% user + <span class="number">0</span>% kernel / faults: <span class="number">1134</span> minor</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span>I/ActivityManager( <span class="number">1190</span>): system_server: <span class="number">0</span>% = <span class="number">0</span>% user + <span class="number">0</span>% kernel /faults: <span class="number">1</span> minor</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager( <span class="number">1190</span>): adbd:<span class="number">0</span>% = <span class="number">0</span>% user + <span class="number">0</span>% kernel</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span> I/ActivityManager(<span class="number">1190</span>): logcat: <span class="number">0</span>% = <span class="number">0</span>% user + <span class="number">0</span>% kernel</div><div class="line"> <span class="number">11</span>-<span class="number">16</span> <span class="number">21</span>:<span class="number">41</span>:<span class="number">42.560</span>I/ActivityManager( <span class="number">1190</span>): TOTAL:<span class="number">100</span>% = <span class="number">98</span>% user + <span class="number">1</span>% kernel</div><div class="line"></div><div class="line"> Cmdline: android.process.acore</div><div class="line"></div><div class="line"> DALVIK THREADS:</div><div class="line"> <span class="string">"main"</span>prio=<span class="number">5</span> tid=<span class="number">3</span> VMWAIT</div><div class="line"> |group=<span class="string">"main"</span> sCount=<span class="number">1</span> dsCount=<span class="number">0</span> s=N obj=<span class="number">0x40026240</span>self=<span class="number">0xbda8</span></div><div class="line"> | sysTid=<span class="number">1815</span> nice=<span class="number">0</span> sched=<span class="number">0</span>/<span class="number">0</span> cgrp=unknownhandle=-<span class="number">1344001376</span></div><div class="line"> atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)</div><div class="line"> atandroid.graphics.Bitmap.nativeCreate(Native Method)</div><div class="line"> atandroid.graphics.Bitmap.createBitmap(Bitmap.java:<span class="number">468</span>)</div><div class="line"> atandroid.view.View.buildDrawingCache(View.java:<span class="number">6324</span>)</div><div class="line"> atandroid.view.View.getDrawingCache(View.java:<span class="number">6178</span>)</div><div class="line"> atandroid.view.ViewGroup.drawChild(ViewGroup.java:<span class="number">1541</span>)</div><div class="line"> ……</div><div class="line"> atcom.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:<span class="number">1830</span>)</div><div class="line"> atandroid.view.ViewRoot.draw(ViewRoot.java:<span class="number">1349</span>)</div><div class="line"> atandroid.view.ViewRoot.performTraversals(ViewRoot.java:<span class="number">1114</span>)</div><div class="line"> atandroid.view.ViewRoot.handleMessage(ViewRoot.java:<span class="number">1633</span>)</div><div class="line"> atandroid.os.Handler.dispatchMessage(Handler.java:<span class="number">99</span>)</div><div class="line"> atandroid.os.Looper.loop(Looper.java:<span class="number">123</span>)</div><div class="line"> atandroid.app.ActivityThread.main(ActivityThread.java:<span class="number">4370</span>)</div><div class="line"> atjava.lang.reflect.Method.invokeNative(Native Method)</div><div class="line"> atjava.lang.reflect.Method.invoke(Method.java:<span class="number">521</span>)</div><div class="line"> atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:<span class="number">868</span>)</div><div class="line"> atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:<span class="number">626</span>)</div><div class="line"> atdalvik.system.NativeStart.main(Native Method)</div><div class="line"></div><div class="line"> <span class="string">"Thread-408"</span>prio=<span class="number">5</span> tid=<span class="number">329</span> WAIT</div><div class="line"> |group=<span class="string">"main"</span> sCount=<span class="number">1</span> dsCount=<span class="number">0</span> s=N obj=<span class="number">0x46910d40</span>self=<span class="number">0xcd0548</span></div><div class="line"> | sysTid=<span class="number">10602</span> nice=<span class="number">0</span> sched=<span class="number">0</span>/<span class="number">0</span> cgrp=unknownhandle=<span class="number">15470792</span></div><div class="line"> at java.lang.Object.wait(Native Method)</div><div class="line"> -waiting on <<span class="number">0x468cd420</span>> (a java.lang.Object)</div><div class="line"> atjava.lang.Object.wait(Object.java:<span class="number">288</span>)</div><div class="line"> atcom.android.dialer.CallLogContentHelper$UiUpdaterExecutor$<span class="number">1</span>.run(CallLogContentHelper.java:<span class="number">289</span>)</div><div class="line"> atjava.lang.Thread.run(Thread.java:<span class="number">1096</span>)</div></pre></td></tr></table></figure>
<p>分析:</p>
<p>atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)内存不足导致block在创建bitmap上</p>
<p>MEMINFO in pid 1360 [android.process.acore]</p>
<p>native dalvik other total</p>
<p>size: 17036 23111 N/A 40147</p>
<p>allocated: 16484 20675 N/A 37159</p>
<p>free: 296 2436 N/A 2732</p>
<p>解决:如果机器的内存族,可以修改虚拟机的内存为36M或更大,不过最好是复查代码,查看哪些内存没有释放</p>
<h1 id="感谢"><a href="#感谢" class="headerlink" title="感谢"></a>感谢</h1><p>本篇博客转自于下<a href="http://www.cnblogs.com/purediy/p/3225060.html" target="_blank" rel="external">http://www.cnblogs.com/purediy/p/3225060.html</a></p>
<p>感谢作者的总结和分享!</p>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><a href="http://www.cnblogs.com/purediy/p/3225060.html" target="_blank" rel="external">http://www.cnblogs.com/purediy/p/3225060.html</a></p>
]]></content>
<summary type="html">
<h1 id="什么是ANR?"><a href="#什么是ANR?" class="headerlink" title="什么是ANR?"></a>什么是ANR?</h1><figure class="highlight plain"><table><tr><td class=
</summary>
<category term="内功修养" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Android" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Android/"/>
<category term="ANR" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Android/ANR/"/>
<category term="Android" scheme="http://akathink.com/tags/Android/"/>
<category term="内功修养" scheme="http://akathink.com/tags/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="ANR" scheme="http://akathink.com/tags/ANR/"/>
</entry>
<entry>
<title>轻松了解Java各类引用</title>
<link href="http://akathink.com/2016/08/13/%E8%BD%BB%E6%9D%BE%E4%BA%86%E8%A7%A3Java%E5%90%84%E7%B1%BB%E5%BC%95%E7%94%A8/"/>
<id>http://akathink.com/2016/08/13/轻松了解Java各类引用/</id>
<published>2016-08-13T00:24:35.000Z</published>
<updated>2016-08-13T03:51:27.000Z</updated>
<content type="html"><![CDATA[<h1 id="强引用"><a href="#强引用" class="headerlink" title="强引用"></a>强引用</h1><p>强引用是使用最为普遍的引用,如果一个对象具有强引用,那么垃圾回收器绝不会回收它。如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Object object = <span class="keyword">new</span> Object();<span class="comment">// 强引用</span></div></pre></td></tr></table></figure>
<p>当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。如果不使用时,通过如下方式来弱化引用,如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">object = <span class="keyword">null</span>;<span class="comment">//帮助垃圾收集器回收此对象</span></div></pre></td></tr></table></figure>
<p>显示地设置object为null,或超出对象的生命周期范围,则GC认为该对象不存在引用,这时就可以回收这个对象,具体什么时候回收主要取决于GC的算法实现机制。</p>
<p>举例:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">printBookInfo</span><span class="params">()</span></span>{</div><div class="line"> AkaThinkBook akaThinkBook = <span class="keyword">new</span> AkaThinkBook();</div><div class="line"> akaThinkBook.getBookInfo();</div><div class="line">}</div></pre></td></tr></table></figure>
<p>该方法内部拥有一个强引用akaThinkBook,这个引用将会保存在栈中,而真正的引用对象(new AkaThinkBook())则保存在堆中。当这个方法运行完之后,就会退出方法栈,则引用对象的引用不再存在,这个对象就会被回收。</p>
<p>但如果这个akaThinkBook是全局变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。</p>
<p>强引用在实际开发中占有非常重要的席位,通过ArrayList的实现源代码来了解一下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line">* The array buffer into which the elements of the ArrayList are stored.</div><div class="line">* The capacity of the ArrayList is the length of this array buffer. Any</div><div class="line">* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA</div><div class="line">* will be expanded to DEFAULT_CAPACITY when the first element is added.</div><div class="line">*/</div><div class="line"><span class="keyword">transient</span> Object[] elementData; <span class="comment">// non-private to simplify nested class access</span></div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Removes all of the elements from this list. The list will</div><div class="line"> * be empty after this call returns.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</div><div class="line"> modCount++;</div><div class="line"> <span class="comment">// clear to let GC do its work</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < size; i++)</div><div class="line"> elementData[i] = <span class="keyword">null</span>;</div><div class="line"> size = <span class="number">0</span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>在ArrayList类中定义了一个变量elementData数组,在调用clear方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。</p>
<h1 id="软引用"><a href="#软引用" class="headerlink" title="软引用"></a>软引用</h1><p> 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//强引用</span></div><div class="line">AkaThinkBook akaThinkBook = <span class="keyword">new</span> AkaThinkBook();</div><div class="line"><span class="comment">//软引用</span></div><div class="line">SoftReference<AkaThinkBook> softReference = <span class="keyword">new</span> SoftReference<AkaThinkBook>(akaThinkBook);</div></pre></td></tr></table></figure>
<p>当内存不足时,等价于:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span>(JVM.内存不足()){</div><div class="line"></div><div class="line"> akaThinkBook = <span class="keyword">null</span>;<span class="comment">//转换为软引用</span></div><div class="line"> System.gc();<span class="comment">// 进行垃圾回收</span></div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>虚引用在实际中有重要的应用,例如浏览器的后退按钮。按后退时,这个后退时显示的网页内容是重新进行请求还是从缓存中取出呢?这就要看具体的实现策略了。</p>
<ol>
<li>如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建</li>
<li>如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出</li>
</ol>
<p>这时候就可以使用软引用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">Browser browser = <span class="keyword">new</span> Browser();<span class="comment">//获取页面进行浏览</span></div><div class="line">SoftReference softBrowser = <span class="keyword">new</span> SoftReference<Browser>(browser);<span class="comment">//浏览完毕之后设置为软引用</span></div><div class="line"><span class="keyword">if</span>(softBrowser != <span class="keyword">null</span>){</div><div class="line"> browser = (Browser) softBrowser.get();<span class="comment">//如果没有被GC回收,直接获取</span></div><div class="line">}<span class="keyword">else</span>{</div><div class="line"> browser = <span class="keyword">new</span> Browser();<span class="comment">//由于内存不足,导致软引用被GC回收,若是现在再使用的话,则直接创建</span></div><div class="line"> softBrowser = <span class="keyword">new</span> SoftReference<Browser>(browser);<span class="comment">//重新设置为软引用</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>这样就很好的解决了实际的问题。</p>
<p>软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。</p>
<h1 id="弱引用"><a href="#弱引用" class="headerlink" title="弱引用"></a>弱引用</h1><p>弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//强引用</span></div><div class="line">AkaThinkBook akaThinkBook = <span class="keyword">new</span> AkaThinkBook();</div><div class="line"><span class="comment">//弱引用</span></div><div class="line">WeakReference<AkaThinkBook> weakReference = <span class="keyword">new</span> WeakReference<AkaThinkBook>(akaThinkBook);</div><div class="line">akaThinkBook = <span class="keyword">null</span>;</div></pre></td></tr></table></figure>
<p>当垃圾回收器进行扫描回收时等价于:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">akaThinkBook = <span class="keyword">null</span>;</div><div class="line">System.gc();</div></pre></td></tr></table></figure>
<p>如果这个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来记住此对象。 </p>
<p>下面的代码会让akaThinkBook变为一个强引用:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">AkaThinkBook book = weakReference.get();</div></pre></td></tr></table></figure>
<p>弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。<br>当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。</p>
<p>这个引用不会在对象的垃圾回收判断中产生任何附加的影响。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.reference;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.ref.Reference;</div><div class="line"><span class="keyword">import</span> java.lang.ref.ReferenceQueue;</div><div class="line"><span class="keyword">import</span> java.lang.ref.WeakReference;</div><div class="line"><span class="keyword">import</span> java.util.LinkedList;</div><div class="line"></div><div class="line"><span class="keyword">import</span> javax.security.auth.Refreshable;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReferenceDemo</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> ReferenceQueue<BigFile> referenceQueue = <span class="keyword">new</span> ReferenceQueue<>();</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">checkQueue</span><span class="params">()</span> </span>{</div><div class="line"> Reference<? extends BigFile> reference = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">while</span> ((reference = referenceQueue.poll()) != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (reference != <span class="keyword">null</span>) {</div><div class="line"> System.out.println(<span class="string">"In queue: "</span> + ((BigFileWeakReference) (reference)).getVideo());</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</div><div class="line"> <span class="keyword">int</span> size = <span class="number">3</span>;</div><div class="line"> LinkedList<WeakReference<BigFile>> weakList = <span class="keyword">new</span> LinkedList<WeakReference<BigFile>>();</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < size; i++) {</div><div class="line"> weakList.add(<span class="keyword">new</span> BigFileWeakReference(<span class="keyword">new</span> BigFile(<span class="string">"-----Weak Video-----"</span> + i), referenceQueue));</div><div class="line"> System.out.println(<span class="string">"Just created weak: "</span> + weakList.getLast());</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> System.gc();</div><div class="line"> <span class="keyword">try</span> { <span class="comment">// 下面休息8秒钟,让上面的垃圾回收线程运行完成</span></div><div class="line"> Thread.currentThread().sleep(<span class="number">8000</span>);</div><div class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> checkQueue();</div><div class="line"> }</div><div class="line"></div><div class="line">}</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">BigFile</span> </span>{</div><div class="line"> <span class="keyword">private</span> String video;</div><div class="line"></div><div class="line"> <span class="comment">// 占用空间,让线程进行回收</span></div><div class="line"> <span class="keyword">byte</span>[] b = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">2</span> * <span class="number">1024</span>];</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BigFile</span><span class="params">(String video)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.video = video;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getVideo</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> video;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable </span>{</div><div class="line"> System.out.println(<span class="string">"Finalizing BigFile"</span> + video);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">BigFileWeakReference</span> <span class="keyword">extends</span> <span class="title">WeakReference</span><<span class="title">BigFile</span>> </span>{</div><div class="line"> <span class="keyword">private</span> String video;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BigFileWeakReference</span><span class="params">(BigFile bigFile, ReferenceQueue<BigFile> referenceQueue)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(bigFile, referenceQueue);</div><div class="line"> <span class="keyword">this</span>.video = bigFile.getVideo();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getVideo</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> video;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable </span>{</div><div class="line"> System.out.println(<span class="string">"Finalizing BigFileWeakReference"</span> + video);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>运行结果</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">Just created weak: com.akathink.reference.BigFileWeakReference@15db9742</div><div class="line">Just created weak: com.akathink.reference.BigFileWeakReference@6d06d69c</div><div class="line">Just created weak: com.akathink.reference.BigFileWeakReference@7852e922</div><div class="line">Finalizing BigFile-----Weak Video-----2</div><div class="line">Finalizing BigFile-----Weak Video-----1</div><div class="line">Finalizing BigFile-----Weak Video-----0</div><div class="line">In queue: -----Weak Video-----2</div><div class="line">In queue: -----Weak Video-----1</div><div class="line">In queue: -----Weak Video-----0</div></pre></td></tr></table></figure>
<h1 id="虚引用"><a href="#虚引用" class="headerlink" title="虚引用"></a>虚引用</h1><p>“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。</p>
<p>虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>Java这四种引用的级别由高到低依次为:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">强引用 > 软引用 > 弱引用 > 虚引用</div></pre></td></tr></table></figure>
<p>通过图来看一下他们之间在垃圾回收时的区别:</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/Java%E5%90%84%E7%B1%BB%E5%BC%95%E7%94%A8%E6%80%BB%E7%BB%93.jpg" alt="Java四类引用总结"></p>
<p>当垃圾回收器回收时,某些对象会被回收,某些不会被回收。垃圾回收器会从根对象Object来标记存活的对象,然后将某些不可达的对象和一些引用的对象进行回收。</p>
<p>通过表格来说明一下,如下:</p>
<table>
<thead>
<tr>
<th>引用类型</th>
<th style="text-align:center">被垃圾回收时间</th>
<th>用途</th>
<th style="text-align:right">生存时间</th>
</tr>
</thead>
<tbody>
<tr>
<td>强引用</td>
<td style="text-align:center">从来不会</td>
<td>对象的一般状态</td>
<td style="text-align:right">JVM停止运行时终止</td>
</tr>
<tr>
<td><font color="#ff008f" size="4">软引用</font></td>
<td style="text-align:center">内存不足时</td>
<td>对象缓存</td>
<td style="text-align:right">内存不足时终止</td>
</tr>
<tr>
<td><font color="#ff008f" size="4">弱引用</font></td>
<td style="text-align:center">垃圾回收时</td>
<td>对象缓存</td>
<td style="text-align:right">GC运行后终止</td>
</tr>
<tr>
<td><font color="#ff008f" size="4">虚引用</font></td>
<td style="text-align:center">Unknown</td>
<td>Unknown</td>
<td style="text-align:right">Unknown</td>
</tr>
</tbody>
</table>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><a href="http://my.oschina.net/ydsakyclguozi/blog/404389" target="_blank" rel="external">http://my.oschina.net/ydsakyclguozi/blog/404389</a></p>
]]></content>
<summary type="html">
<h1 id="强引用"><a href="#强引用" class="headerlink" title="强引用"></a>强引用</h1><p>强引用是使用最为普遍的引用,如果一个对象具有强引用,那么垃圾回收器绝不会回收它。如下:</p>
<figure class="hig
</summary>
<category term="内功修养" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Java" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/"/>
<category term="引用" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/%E5%BC%95%E7%94%A8/"/>
<category term="公共基础知识" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/%E5%BC%95%E7%94%A8/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="内功修养" scheme="http://akathink.com/tags/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Java" scheme="http://akathink.com/tags/Java/"/>
<category term="公共基础知识" scheme="http://akathink.com/tags/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="强引用" scheme="http://akathink.com/tags/%E5%BC%BA%E5%BC%95%E7%94%A8/"/>
<category term="弱引用" scheme="http://akathink.com/tags/%E5%BC%B1%E5%BC%95%E7%94%A8/"/>
<category term="软引用" scheme="http://akathink.com/tags/%E8%BD%AF%E5%BC%95%E7%94%A8/"/>
<category term="虚引用" scheme="http://akathink.com/tags/%E8%99%9A%E5%BC%95%E7%94%A8/"/>
</entry>
<entry>
<title>彻底搞懂Java反射Reflect</title>
<link href="http://akathink.com/2016/08/12/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%87%82Java%E5%8F%8D%E5%B0%84Reflect/"/>
<id>http://akathink.com/2016/08/12/彻底搞懂Java反射Reflect/</id>
<published>2016-08-12T01:31:26.000Z</published>
<updated>2016-08-12T08:31:55.000Z</updated>
<content type="html"><![CDATA[<h1 id="背景知识"><a href="#背景知识" class="headerlink" title="背景知识"></a>背景知识</h1><p>在了解反射之前,我们首先了解一下Class和Object:</p>
<ul>
<li>Class: 所有类的根源,是整个Java反射机制的源头。</li>
<li>Object:所有对象的根源。</li>
</ul>
<h1 id="Class类"><a href="#Class类" class="headerlink" title="Class类"></a>Class类</h1><h2 id="Class类的作用"><a href="#Class类的作用" class="headerlink" title="Class类的作用"></a>Class类的作用</h2><ul>
<li>在运行时判断任意一个对象所属的类</li>
<li>在运行时构造任意一个类的对象</li>
<li>在运行时判断任意一个类所具有的成员变量和方法</li>
<li>在运行时调用任意一个对象的方法</li>
<li>生成动态代理</li>
</ul>
<h2 id="Class类的使用"><a href="#Class类的使用" class="headerlink" title="Class类的使用"></a>Class类的使用</h2><p>本次通过代码+注释来驱动讲解Java的反射知识,这样比纯文字描述了解的要快而且记得牢的多:</p>
<p>首先,创建一个类AkaThinkBook.java 供验证反射机制使用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.reflect;</div><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 本类提供了两个字段、两个构造方法、五个普通方法,供验证反射机制使用</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AkaThinkBook</span> </span>{</div><div class="line"> <span class="keyword">private</span> String bookName;</div><div class="line"> <span class="keyword">private</span> String bookAuthor;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">AkaThinkBook</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">AkaThinkBook</span><span class="params">(String bookName, String bookAuthor)</span> </span>{</div><div class="line"> <span class="keyword">super</span>();</div><div class="line"> <span class="keyword">this</span>.bookName = bookName;</div><div class="line"> <span class="keyword">this</span>.bookAuthor = bookAuthor;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getBookName</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> bookName;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setBookName</span><span class="params">(String bookName)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.bookName = bookName;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getBookAuthor</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> bookAuthor;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setBookAuthor</span><span class="params">(String bookAuthor)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.bookAuthor = bookAuthor;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getBookInfo</span><span class="params">()</span></span>{</div><div class="line"> System.out.println(<span class="string">"AkaThink即将出版的《音画》APP为您提供优质的音画作品,带给您美的享受!"</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>其次,定义一个ClassUtil.java 来帮助我们打印一些日志信息</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.reflect;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</div><div class="line"><span class="keyword">import</span> java.lang.reflect.Field;</div><div class="line"><span class="keyword">import</span> java.lang.reflect.Method;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassUtil</span> </span>{</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 打印对象的字段信息</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> object</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printFieldMsg</span><span class="params">(Object object)</span> </span>{</div><div class="line"></div><div class="line"> System.out.println(<span class="string">"\n\n下面打印的是对象的 字段 信息:\n"</span>);</div><div class="line"></div><div class="line"> Class clazz = object.getClass();</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 成员变量也是对象</div><div class="line"> *</div><div class="line"> * java.lang.reflect.Field</div><div class="line"> *</div><div class="line"> * Field类封装了关于成员变量的操作</div><div class="line"> *</div><div class="line"> * getFields()获取的是所有的Public的成员变量的信息</div><div class="line"> *</div><div class="line"> * getDeclaredFields()获取的是该类自己声明的变量的信息</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="comment">// Field[] fields = clazz.getFields();</span></div><div class="line"> Field[] fields = clazz.getDeclaredFields();</div><div class="line"> <span class="keyword">for</span> (Field field : fields) {</div><div class="line"> <span class="comment">// 得到成员变量的类型的类类型</span></div><div class="line"> Class fieldType = field.getType();</div><div class="line"> String typeName = fieldType.getName();</div><div class="line"> <span class="comment">// 得到成员变量的名称</span></div><div class="line"> String fieldName = field.getName();</div><div class="line"> System.out.println(typeName + <span class="string">" "</span> + fieldName);</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 打印对象的构造函数的信息</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> object</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printConstructorMsg</span><span class="params">(Object object)</span> </span>{</div><div class="line"></div><div class="line"> System.out.println(<span class="string">"\n下面打印的是对象的 构造方法 信息:\n"</span>);</div><div class="line"></div><div class="line"> Class clazz = object.getClass();</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 构造函数也是对象</div><div class="line"> *</div><div class="line"> * java.lang.reflect.Constructor</div><div class="line"> *</div><div class="line"> * getConstructors()获取的是该类的所有public方法</div><div class="line"> *</div><div class="line"> * getDeclaredConstructors()获取的是该对象自己声明的构造方法</div><div class="line"> */</div><div class="line"> <span class="comment">// Constructor[] constructors = clazz.getConstructors();</span></div><div class="line"> Constructor[] constructors = clazz.getDeclaredConstructors();</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (Constructor constructor : constructors) {</div><div class="line"> System.out.print(constructor.getName() + <span class="string">"("</span>);</div><div class="line"></div><div class="line"> Class[] paramTypes = constructor.getParameterTypes();</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (Class paramClazz : paramTypes) {</div><div class="line"> System.out.print(paramClazz.getName()+ <span class="string">" , "</span> );</div><div class="line"> }</div><div class="line"> System.out.println(<span class="string">")"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 打印对象的方法信息</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> object</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printMethodMsg</span><span class="params">(Object object)</span> </span>{</div><div class="line"></div><div class="line"> System.out.println(<span class="string">"\n下面打印的是对象的 方法 信息:\n"</span>);</div><div class="line"></div><div class="line"> <span class="comment">// 获取该对象的类类型</span></div><div class="line"> Class clazz = object.getClass();</div><div class="line"> System.out.println(<span class="string">"类的名称是:"</span> + clazz.getName());</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Method类,方法对象</div><div class="line"> *</div><div class="line"> * java.lang.reflect.Method</div><div class="line"> *</div><div class="line"> * 一个成员方法就是一个Method对象</div><div class="line"> *</div><div class="line"> * getMethods()方法获取的就是该class or interface 的所有的public的方法,包括父类继承的方法。</div><div class="line"> *</div><div class="line"> * getDeclaredMethods()获取的是该class or interface 自己声明的方法,不问访问权限。</div><div class="line"> */</div><div class="line"><span class="comment">// Method[] methods = clazz.getMethods();</span></div><div class="line"> Method[] methods = clazz.getDeclaredMethods();</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (Method method : methods) {</div><div class="line"> <span class="comment">// 得到方法的返回值类型的类类型</span></div><div class="line"> Class returnType = method.getReturnType();</div><div class="line"> System.out.print(returnType.getName() + <span class="string">" "</span>);</div><div class="line"> <span class="comment">// 得到方法的名称</span></div><div class="line"> System.out.print(method.getName() + <span class="string">"("</span>);</div><div class="line"> <span class="comment">// 获取参数类型--> 得到的是参数列表的类类型</span></div><div class="line"> Class[] paramTypes = method.getParameterTypes();</div><div class="line"> <span class="keyword">for</span> (Class paramClazz : paramTypes) {</div><div class="line"> System.out.print(paramClazz.getName() + <span class="string">" , "</span>);</div><div class="line"> }</div><div class="line"> System.out.println(<span class="string">")"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>最后,定义一个:ClassDemo.java 来帮助我们了解Class类的使用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.reflect;</div><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> *Class类的使用</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassDemo</span> </span>{</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * AkaThinkBook也是一个实例对象</div><div class="line"> * 任何一个类都是Class的实例对象,这个实例对象有三种表示方式</div><div class="line"> *</div><div class="line"> */</div><div class="line"> AkaThinkBook akaThinkBook = <span class="keyword">new</span> AkaThinkBook();</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 第一种表示方式-->实际在告诉我们任何一个类都有一个隐含的静态成员变量class</div><div class="line"> */</div><div class="line"> Class clazz1 = AkaThinkBook.class;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 第二种表示方式-->已经知道该类的对象,通过getClass()获取</div><div class="line"> */</div><div class="line"> Class clazz2 = akaThinkBook.getClass();</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 总结:</div><div class="line"> *</div><div class="line"> * clazz1、clazz2在官网里称为AkaThinkBook的类类型</div><div class="line"> *</div><div class="line"> * 万事万物皆对象</div><div class="line"> *</div><div class="line"> * 类也是对象,是Class类的实例对象</div><div class="line"> *</div><div class="line"> * 这个对象我们称之为该类的类类型</div><div class="line"> *</div><div class="line"> *</div><div class="line"> */</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 一个类只可能是Class类的一个实例对象,无论采用哪种方式获取返回的都是同一个对象。</div><div class="line"> */</div><div class="line"> System.out.println(clazz1 == clazz2);</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 第三种表示方式-->不仅表示类的类类型,还代表了动态加载类</div><div class="line"> *</div><div class="line"> * 编译时刻加载类是静态加载类,运行时刻加载类是动态加载</div><div class="line"> *</div><div class="line"> */</div><div class="line"> Class clazz3 = <span class="keyword">null</span>;</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> clazz3 = Class.forName(<span class="string">"com.akathink.reflect.AkaThinkBook"</span>);</div><div class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> System.out.println(clazz1 == clazz3);</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//我们完全可以通过类的类类型创建该类的实例对象</span></div><div class="line"> AkaThinkBook book = (AkaThinkBook)clazz1.newInstance();<span class="comment">//需要有无参数的构造方法</span></div><div class="line"> book.getBookInfo();</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"></div><div class="line"> ClassUtil.printFieldMsg(akaThinkBook);</div><div class="line"> ClassUtil.printConstructorMsg(akaThinkBook);</div><div class="line"> ClassUtil.printMethodMsg(akaThinkBook);</div><div class="line"></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>运行结果:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">true</div><div class="line">true</div><div class="line">AkaThink即将出版的《音画》APP为您提供优质的音画作品,带给您美的享受!</div><div class="line"></div><div class="line"></div><div class="line">下面打印的是对象的 字段 信息:</div><div class="line"></div><div class="line">java.lang.String bookName</div><div class="line">java.lang.String bookAuthor</div><div class="line"></div><div class="line">下面打印的是对象的 构造方法 信息:</div><div class="line"></div><div class="line">com.akathink.reflect.AkaThinkBook()</div><div class="line">com.akathink.reflect.AkaThinkBook(java.lang.String , java.lang.String , )</div><div class="line"></div><div class="line">下面打印的是对象的 方法 信息:</div><div class="line"></div><div class="line">类的名称是:com.akathink.reflect.AkaThinkBook</div><div class="line">void getBookInfo()</div><div class="line">java.lang.String getBookName()</div><div class="line">void setBookName(java.lang.String , )</div><div class="line">java.lang.String getBookAuthor()</div><div class="line">void setBookAuthor(java.lang.String , )</div></pre></td></tr></table></figure>
<h2 id="方法反射的操作"><a href="#方法反射的操作" class="headerlink" title="方法反射的操作"></a>方法反射的操作</h2><p>通过上面的案例,我们可以很方便的获取都对象里面的任何字段、方法、构造方法等信息,下面我们再讲解一下如何通过反射调用方法:<br>下面是通过反射调用方法的模板:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">method.invoke(对象,参数列表)</div></pre></td></tr></table></figure></p>
<p>我们创建一个:MethodDemo.java类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.reflect;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.reflect.Method;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MethodDemo</span> </span>{</div><div class="line"></div><div class="line"> <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</div><div class="line"></div><div class="line"> AkaThinkBook akaThinkBook = <span class="keyword">new</span> AkaThinkBook(<span class="string">"魔女闹江湖"</span>, <span class="string">"顾漫"</span>);</div><div class="line"> <span class="comment">// 第一步:获取类类型</span></div><div class="line"> Class clazz = akaThinkBook.getClass();</div><div class="line"></div><div class="line"> System.out.println(<span class="string">"未修改之前书名为:"</span> + akaThinkBook.getBookName());</div><div class="line"></div><div class="line"> <span class="comment">// 第二步:获取方法</span></div><div class="line"> Method method;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> method = clazz.getMethod(<span class="string">"setBookName"</span>, String.class);</div><div class="line"> <span class="comment">// 第三步:调用setBookName(String bookName)方法</span></div><div class="line"> method.invoke(akaThinkBook, <span class="string">"微微一笑很倾城"</span>);</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"></div><div class="line"> System.out.println(<span class="string">"修改之后书名为:"</span> + akaThinkBook.getBookName());</div><div class="line"></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>运行结果</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">未修改之前书名为:魔女闹江湖</div><div class="line">修改之后书名为:微微一笑很倾城</div></pre></td></tr></table></figure>
<h2 id="通过Class、Method来认识泛型的本质"><a href="#通过Class、Method来认识泛型的本质" class="headerlink" title="通过Class、Method来认识泛型的本质"></a>通过Class、Method来认识泛型的本质</h2><p>创建一个ArrayListDemo.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.reflect;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.reflect.Method;</div><div class="line"><span class="keyword">import</span> java.util.ArrayList;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ArrayListDemo</span> </span>{</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</div><div class="line"></div><div class="line"> ArrayList mDataList1 = <span class="keyword">new</span> ArrayList();</div><div class="line"> <span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 我曾经见过的一个面试题:如何让ArrayList<String>类型的变量添加一个int类型的值,下面就以此为例来介绍如何通过反射了解集合泛型的本质</div><div class="line"> *</div><div class="line"> *</div><div class="line"> */</div><div class="line"> ArrayList<String> mDataList2 = <span class="keyword">new</span> ArrayList<String>();</div><div class="line"></div><div class="line"> System.out.println(mDataList1.getClass() == mDataList2.getClass());</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> *</div><div class="line"> *</div><div class="line"> * 返回true说明编译之后集合的泛型是去泛型话的</div><div class="line"> *</div><div class="line"> * Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了</div><div class="line"> *</div><div class="line"> * 反射的操作都是编译之后的操作</div><div class="line"> *</div><div class="line"> * 验证:我们可以通过方法的反射来操作,绕过编译</div><div class="line"> *</div><div class="line"> *</div><div class="line"> */</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> Method m = mDataList2.getClass().getMethod(<span class="string">"add"</span>, Object.class);</div><div class="line"></div><div class="line"> m.invoke(mDataList2, <span class="number">10</span>);</div><div class="line"> m.invoke(mDataList2, <span class="number">20</span>);</div><div class="line"> m.invoke(mDataList2, <span class="number">30</span>);</div><div class="line"></div><div class="line"></div><div class="line"> System.out.println(mDataList2);</div><div class="line"></div><div class="line"> } <span class="keyword">catch</span> (Exception e1) {</div><div class="line"> e1.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>运行结果</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">true</div><div class="line">[10, 20, 30]</div></pre></td></tr></table></figure>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><a href="http://www.imooc.com/learn/199" target="_blank" rel="external">http://www.imooc.com/learn/199</a><br><a href="http://www.cnblogs.com/yaozhongxiao/archive/2013/05/21/3091353.html" target="_blank" rel="external">http://www.cnblogs.com/yaozhongxiao/archive/2013/05/21/3091353.html</a></p>
]]></content>
<summary type="html">
<h1 id="背景知识"><a href="#背景知识" class="headerlink" title="背景知识"></a>背景知识</h1><p>在了解反射之前,我们首先了解一下Class和Object:</p>
<ul>
<li>Class: 所有类的根源,是整个Ja
</summary>
<category term="内功修养" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Java" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/"/>
<category term="反射" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/%E5%8F%8D%E5%B0%84/"/>
<category term="公共基础知识" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/%E5%8F%8D%E5%B0%84/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="内功修养" scheme="http://akathink.com/tags/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Java" scheme="http://akathink.com/tags/Java/"/>
<category term="反射" scheme="http://akathink.com/tags/%E5%8F%8D%E5%B0%84/"/>
<category term="公共基础知识" scheme="http://akathink.com/tags/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
</entry>
<entry>
<title>彻底搞懂Java注解Annotation</title>
<link href="http://akathink.com/2016/08/11/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%87%82Java%E6%B3%A8%E8%A7%A3Annotation/"/>
<id>http://akathink.com/2016/08/11/彻底搞懂Java注解Annotation/</id>
<published>2016-08-11T02:29:25.000Z</published>
<updated>2016-08-11T09:35:16.000Z</updated>
<content type="html"><![CDATA[<h1 id="注解的定义"><a href="#注解的定义" class="headerlink" title="注解的定义"></a>注解的定义</h1><ul>
<li>定义</li>
</ul>
<p>注解:提供一种为程序元素设置元数据的方法。</p>
<font color="#8855cc" size="4">基本原则:注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。</font>
<p>注解(也被成为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。 ———摘自《Thinking in Java》</p>
<font color="#8855cc" size="4">简单来说注解的作用就是将我们的需要的数据储存起来,在以后的某一个时刻(可能是编译时,也可能是运行时)去调用它。</font>
<ul>
<li>元数据</li>
</ul>
<p>元数据:就是关于数据的数据</p>
<p>元数据的作用:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">1. 编写文档:通过代码里标识的元数据生成文档;</div><div class="line">2. 代码分析:通过代码里标识的元数据对代码进行分析;</div><div class="line">3. 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。</div></pre></td></tr></table></figure></p>
<h1 id="为什么要学习注解?"><a href="#为什么要学习注解?" class="headerlink" title="为什么要学习注解?"></a>为什么要学习注解?</h1><ul>
<li>能够读懂别人使用注解实现的开源库</li>
<li>让编程变得更加简洁</li>
</ul>
<h1 id="注解的功能"><a href="#注解的功能" class="headerlink" title="注解的功能"></a>注解的功能</h1><ul>
<li>作为特定的标记,用于告诉编译器一些信息</li>
<li>编译时动态处理,如动态生成代码</li>
<li>运行时动态处理,作为额外信息的载体,如得到注解信息</li>
</ul>
<h1 id="注解的分类"><a href="#注解的分类" class="headerlink" title="注解的分类"></a>注解的分类</h1><ul>
<li>标准注解:Override、Deprecated、SuppressWarnings<br>标准 Annotation 是指 Java 自带的几个 Annotation,上面三个分别表示重写函数,不鼓励使用(有更好方式、使用有风险或已不在维护),忽略某项 Warning;</li>
<li>元注解:@Retention、@Target、@Inherited、@Documented<br>元 Annotation 是指用来定义 Annotation 的 Annotation,在自定义注解部分将会详细介绍;</li>
<li>自定义注解<br>自定义 Annotation 表示自己根据需要定义的 Annotation,定义时需要用到上面的元 Annotation<br>这里是一种分类而已,也可以根据作用域分为源码时、编译时、运行时 Annotation,后面在自定义 Annotation 时会具体介绍。</li>
</ul>
<h1 id="自定义注解"><a href="#自定义注解" class="headerlink" title="自定义注解"></a>自定义注解</h1><p>因为自定义注解,是使用元注解来实现的,所以我们先详细的了解一下元注解,然后再通过一个例子来讲解如何实现和使用自定义注解。</p>
<h2 id="元注解"><a href="#元注解" class="headerlink" title="元注解"></a>元注解</h2><ul>
<li><strong>@Target</strong></li>
</ul>
<p>说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。</p>
<p><strong><font color="#ff0000" size="4">作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)</font></strong></p>
<p>取值(ElementType)有:</p>
<ol>
<li>CONSTRUCTOR:用于描述构造器</li>
<li>FIELD:用于描述域</li>
<li>LOCAL_VARIABLE:用于描述局部变量</li>
<li>METHOD:用于描述方法</li>
<li>PACKAGE:用于描述包</li>
<li>PARAMETER:用于描述参数</li>
<li>TYPE:用于描述类、接口(包括注解类型) 或enum声明</li>
</ol>
<p><strong>@Target的源码</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Documented</span></div><div class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</div><div class="line"><span class="meta">@Target</span>(ElementType.ANNOTATION_TYPE)</div><div class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Target {</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Returns an array of the kinds of elements an annotation type</div><div class="line"> * can be applied to.</div><div class="line"> * <span class="doctag">@return</span> an array of the kinds of elements an annotation type</div><div class="line"> * can be applied to</div><div class="line"> */</div><div class="line"> ElementType[] value();</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">enum</span> ElementType {</div><div class="line"> <span class="comment">/** Class, interface (including annotation type), or enum declaration */</span></div><div class="line"> TYPE,</div><div class="line"></div><div class="line"> <span class="comment">/** Field declaration (includes enum constants) */</span></div><div class="line"> FIELD,</div><div class="line"></div><div class="line"> <span class="comment">/** Method declaration */</span></div><div class="line"> METHOD,</div><div class="line"></div><div class="line"> <span class="comment">/** Formal parameter declaration */</span></div><div class="line"> PARAMETER,</div><div class="line"></div><div class="line"> <span class="comment">/** Constructor declaration */</span></div><div class="line"> CONSTRUCTOR,</div><div class="line"></div><div class="line"> <span class="comment">/** Local variable declaration */</span></div><div class="line"> LOCAL_VARIABLE,</div><div class="line"></div><div class="line"> <span class="comment">/** Annotation type declaration */</span></div><div class="line"> ANNOTATION_TYPE,</div><div class="line"></div><div class="line"> <span class="comment">/** Package declaration */</span></div><div class="line"> PACKAGE,</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Type parameter declaration</div><div class="line"> *</div><div class="line"> * <span class="doctag">@since</span> 1.8</div><div class="line"> */</div><div class="line"> TYPE_PARAMETER,</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Use of a type</div><div class="line"> *</div><div class="line"> * <span class="doctag">@since</span> 1.8</div><div class="line"> */</div><div class="line"> TYPE_USE</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li><strong>@Retention</strong></li>
</ul>
<p>定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。</p>
<p><strong><font color="#ff0000" size="4">作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)</font></strong></p>
<p>取值(RetentionPoicy)有:</p>
<ol>
<li>SOURCE:在源文件中有效(即源文件保留)</li>
<li>CLASS:在class文件中有效(即class保留)</li>
<li>RUNTIME:在运行时有效(即运行时保留)</li>
</ol>
<p><strong>@Retention的源码</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Documented</span></div><div class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</div><div class="line"><span class="meta">@Target</span>(ElementType.ANNOTATION_TYPE)</div><div class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Retention {</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Returns the retention policy.</div><div class="line"> * <span class="doctag">@return</span> the retention policy</div><div class="line"> */</div><div class="line"> <span class="function">RetentionPolicy <span class="title">value</span><span class="params">()</span></span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">enum</span> RetentionPolicy {</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Annotations are to be discarded by the compiler.</div><div class="line"> */</div><div class="line"> SOURCE,</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Annotations are to be recorded in the class file by the compiler</div><div class="line"> * but need not be retained by the VM at run time. This is the default</div><div class="line"> * behavior.</div><div class="line"> */</div><div class="line"> CLASS,</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Annotations are to be recorded in the class file by the compiler and</div><div class="line"> * retained by the VM at run time, so they may be read reflectively.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@see</span> java.lang.reflect.AnnotatedElement</div><div class="line"> */</div><div class="line"> RUNTIME</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li><strong>@Documented</strong></li>
</ul>
<p>用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。</p>
<p><strong>@Documented的源码</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Documented</span></div><div class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</div><div class="line"><span class="meta">@Target</span>(ElementType.ANNOTATION_TYPE)</div><div class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Documented {</div><div class="line">}</div></pre></td></tr></table></figure>
<ul>
<li><strong>@Inherited</strong></li>
</ul>
<p>@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。</p>
<p>注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。</p>
<p>当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。</p>
<p><strong>@Inherited的源码</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Documented</span></div><div class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</div><div class="line"><span class="meta">@Target</span>(ElementType.ANNOTATION_TYPE)</div><div class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Inherited {</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="实现和使用自定义注解"><a href="#实现和使用自定义注解" class="headerlink" title="实现和使用自定义注解"></a>实现和使用自定义注解</h2><p>使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。</p>
<ul>
<li><p>定义注解格式</p>
<p>public <em>@interface</em> 注解名 {定义体}</p>
</li>
<li><p>注解参数的可支持数据类型</p>
</li>
</ul>
<ol>
<li>所有基本数据类型(int,float,boolean,byte,double,char,long,short)</li>
<li>String类型</li>
<li>Class类型</li>
<li>enum类型</li>
<li>Annotation类型</li>
<li>以上所有类型的数组</li>
</ol>
<p>Annotation类型里面的参数该怎么设定: </p>
<ol>
<li>首先,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型; </li>
<li>其次,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String; </li>
<li>最后,如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.例:下面的例子FruitName注解就只有一个参数成员。</li>
</ol>
<h3 id="下面通过源码来展示自定义注解:"><a href="#下面通过源码来展示自定义注解:" class="headerlink" title="下面通过源码来展示自定义注解:"></a>下面通过源码来展示自定义注解:</h3><p>首先,我们自定义一个注解:AuthorAnnotation 来标记作者的信息</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.annotation;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.annotation.Documented;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.ElementType;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.Retention;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.RetentionPolicy;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.Target;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * 自定义注解:作者信息注解</div><div class="line"> *</div><div class="line"> * <span class="doctag">@author</span> LiuQingJie</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="meta">@Target</span>(ElementType.FIELD)</div><div class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</div><div class="line"><span class="meta">@Documented</span></div><div class="line"><span class="keyword">public</span> <span class="meta">@interface</span> AuthorAnnotation {</div><div class="line"> <span class="comment">// 名字</span></div><div class="line"> <span class="function">String <span class="title">name</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"> <span class="comment">// 年龄</span></div><div class="line"> <span class="function"><span class="keyword">int</span> <span class="title">age</span><span class="params">()</span> <span class="keyword">default</span> 19</span>;</div><div class="line"></div><div class="line"> <span class="comment">// 性别</span></div><div class="line"> <span class="function">String <span class="title">gender</span><span class="params">()</span> <span class="keyword">default</span> "男"</span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>其次,再定义一个注解:BookAnnotation 来标记故事书籍的内容信息</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.annotation;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.annotation.Documented;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.ElementType;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.Inherited;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.Retention;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.RetentionPolicy;</div><div class="line"><span class="keyword">import</span> java.lang.annotation.Target;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 自定义注解:树的信息注解</div><div class="line"> *</div><div class="line"> * <span class="doctag">@author</span> LiuQingJie</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="meta">@Target</span>({ ElementType.TYPE, ElementType.METHOD })</div><div class="line"><span class="meta">@Retention</span>(RetentionPolicy.RUNTIME)</div><div class="line"><span class="meta">@Documented</span></div><div class="line"><span class="meta">@Inherited</span></div><div class="line"><span class="keyword">public</span> <span class="meta">@interface</span> BookAnnotation {</div><div class="line"> <span class="comment">// 书名</span></div><div class="line"> <span class="function">String <span class="title">bookName</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"> <span class="comment">// 女主人公</span></div><div class="line"> <span class="function">String <span class="title">heroine</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"> <span class="comment">// 书的简介</span></div><div class="line"> <span class="function">String <span class="title">briefOfBook</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"> <span class="comment">// 书的销量</span></div><div class="line"> <span class="function"><span class="keyword">int</span> <span class="title">sales</span><span class="params">()</span> <span class="keyword">default</span> 10000</span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>最后,我们定义一种类型的书:LoveStoryBook,类注解标记的是《泡沫之夏》,为了区分,方法注解标记的是《微微一笑很倾城》</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.entity;</div><div class="line"></div><div class="line"><span class="keyword">import</span> com.akathink.annotation.AuthorAnnotation;</div><div class="line"><span class="keyword">import</span> com.akathink.annotation.BookAnnotation;</div><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 爱的故事</div><div class="line"> *</div><div class="line"> * <span class="doctag">@author</span> LiuQingJie</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="meta">@BookAnnotation</span>(bookName = <span class="string">"泡沫之夏"</span>,</div><div class="line"> heroine = <span class="string">"尹夏沫"</span>,</div><div class="line"> briefOfBook = <span class="string">"淡漠安静的性格使得欧辰与洛熙为她神魂颠倒。她是冷漠与激情混合体,"</span></div><div class="line"> + <span class="string">"只是在经过种种遭遇,饱尝了人间冷暖后。她用冷漠的外衣将自己包裹住,不愿"</span></div><div class="line"> + <span class="string">"让人看见自己真实的性格,最后与欧辰携手走进婚姻的殿堂。"</span>,</div><div class="line"> sales = <span class="number">1000000</span>)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoveStoryBook</span> </span>{</div><div class="line"></div><div class="line"> <span class="meta">@AuthorAnnotation</span>(name = <span class="string">"明晓溪"</span>, age = <span class="number">28</span>, gender = <span class="string">"女"</span>)</div><div class="line"> <span class="keyword">private</span> String user;</div><div class="line"></div><div class="line"> <span class="meta">@BookAnnotation</span>(bookName = <span class="string">"微微一笑很倾城"</span>,</div><div class="line"> heroine = <span class="string">"顾漫"</span>,</div><div class="line"> briefOfBook = <span class="string">"《微微一笑很倾城》一书中出现的游戏叫梦游江湖,女主角PK榜上排名第六的芦"</span></div><div class="line"> + <span class="string">"苇微微是一身劲装背着大刀的红衣女侠,男主角第一高手一笑奈何则是一身白衣纤尘不"</span></div><div class="line"> + <span class="string">"染衣袂飘飘潇洒出尘的琴师。两人在经典地点长安城朱雀桥相遇并举行婚礼。书中游戏"</span></div><div class="line"> + <span class="string">"既有一般游戏常见的跑环、摆摊,也有现阶段游戏不存在的宝宝结婚、抢亲等功能。"</span>,</div><div class="line"> sales = <span class="number">800000</span>)</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getBookInfo</span><span class="params">()</span></span>{</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<h3 id="注解解析"><a href="#注解解析" class="headerlink" title="注解解析"></a>注解解析</h3><p>上面已经将要注解的类和两个注解类实现了,下面定义一个类:ParseAnnotation,来解析我们自定义的注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.annotation;</div><div class="line"></div><div class="line"><span class="keyword">import</span> java.lang.annotation.Annotation;</div><div class="line"><span class="keyword">import</span> java.lang.reflect.Field;</div><div class="line"><span class="keyword">import</span> java.lang.reflect.Method;</div><div class="line"></div><div class="line"><span class="keyword">import</span> com.akathink.entity.LoveStoryBook;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ParseAnnotation</span> </span>{</div><div class="line"> <span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 解析类注解</div><div class="line"> * LoveStoryBook</div><div class="line"> * <span class="doctag">@throws</span> ClassNotFoundException</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">parseTypeAnnotation</span><span class="params">()</span> <span class="keyword">throws</span> ClassNotFoundException</span>{</div><div class="line"> <span class="meta">@SuppressWarnings</span>(<span class="string">"rawtypes"</span>)</div><div class="line"> Class clazz = Class.forName(<span class="string">"com.akathink.entity.LoveStoryBook"</span>);</div><div class="line"> Annotation[] annotations = clazz.getAnnotations();</div><div class="line"> <span class="keyword">for</span> (Annotation annotation : annotations) {</div><div class="line"> BookAnnotation bookAnnotation = (BookAnnotation) annotation;</div><div class="line"> System.out.println(<span class="string">"书名:"</span> + bookAnnotation.bookName() + <span class="string">"\n"</span> +</div><div class="line"> <span class="string">"女主人公:"</span> + bookAnnotation.heroine() + <span class="string">"\n"</span> +</div><div class="line"> <span class="string">"书的简介:"</span> + bookAnnotation.briefOfBook() + <span class="string">"\n"</span>+</div><div class="line"> <span class="string">"书的销量:"</span> + bookAnnotation .sales() + <span class="string">"\n"</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 解析方法注解</div><div class="line"> * <span class="doctag">@throws</span> ClassNotFoundException</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">parseMethodAnnotation</span><span class="params">()</span> <span class="keyword">throws</span> ClassNotFoundException</span>{</div><div class="line"> Method[] methods = LoveStoryBook.class.getDeclaredMethods();</div><div class="line"> <span class="keyword">for</span> (Method method : methods) {</div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 判断方法中是否有指定注解类型的注解</div><div class="line"> */ </div><div class="line"> <span class="keyword">boolean</span> hasAnnotation = method.isAnnotationPresent(BookAnnotation.class);</div><div class="line"> <span class="keyword">if</span>(hasAnnotation){</div><div class="line"> BookAnnotation bookAnnotation = (BookAnnotation) method.getAnnotation(BookAnnotation.class);</div><div class="line"> System.out.println(<span class="string">"书名:"</span> + bookAnnotation.bookName() + <span class="string">"\n"</span> +</div><div class="line"> <span class="string">"女主人公:"</span> + bookAnnotation.heroine() + <span class="string">"\n"</span> +</div><div class="line"> <span class="string">"书的简介:"</span> + bookAnnotation.briefOfBook() + <span class="string">"\n"</span>+</div><div class="line"> <span class="string">"书的销量:"</span> + bookAnnotation .sales() + <span class="string">"\n"</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 解析域注解</div><div class="line"> * <span class="doctag">@throws</span> ClassNotFoundException</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">parseFieldAnnotation</span><span class="params">()</span> <span class="keyword">throws</span> ClassNotFoundException</span>{</div><div class="line"> Field[] fields = LoveStoryBook.class.getDeclaredFields();</div><div class="line"> <span class="keyword">for</span> (Field field : fields) {</div><div class="line"> <span class="keyword">boolean</span> hasAnnotation = field.isAnnotationPresent(AuthorAnnotation.class);</div><div class="line"> <span class="keyword">if</span>(hasAnnotation){</div><div class="line"> AuthorAnnotation authorAnnotation = field.getAnnotation(AuthorAnnotation.class);</div><div class="line"> System.out.println(<span class="string">"作者:"</span> +authorAnnotation.name() + <span class="string">"\n"</span> +</div><div class="line"> <span class="string">"年龄:"</span> + authorAnnotation.age() + <span class="string">"\n"</span> +</div><div class="line"> <span class="string">"性别:"</span> + authorAnnotation.gender() + <span class="string">"\n"</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>最后的最后就是验证我们自定义的注解是否正确:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.annotation;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AnnotationDemo</span> </span>{</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException </span>{</div><div class="line"> <span class="comment">//解析域的注解</span></div><div class="line"> System.out.println(<span class="string">"下面是解析域的注解信息:\n\n"</span>);</div><div class="line"> ParseAnnotation.parseFieldAnnotation();</div><div class="line"> <span class="comment">//解析方法的注解</span></div><div class="line"> System.out.println(<span class="string">"下面是解析方法的注解信息:\n\n"</span>);</div><div class="line"> ParseAnnotation.parseMethodAnnotation();</div><div class="line"> <span class="comment">//解析类的注解</span></div><div class="line"> System.out.println(<span class="string">"下面是解析类的注解信息:\n\n"</span>);</div><div class="line"> ParseAnnotation.parseTypeAnnotation();</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>运行结果</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line">下面是解析域的注解信息:</div><div class="line"></div><div class="line"></div><div class="line">作者:明晓溪</div><div class="line">年龄:28</div><div class="line">性别:女</div><div class="line"></div><div class="line">下面是解析方法的注解信息:</div><div class="line"></div><div class="line"></div><div class="line">书名:微微一笑很倾城</div><div class="line">女主人公:顾漫</div><div class="line">书的简介:《微微一笑很倾城》一书中出现的游戏叫梦游江湖,女主角PK榜上排名第六的芦苇微微是一身劲装背着大刀的红衣女侠,男主角第一高手一笑奈何则是一身白衣纤尘不染衣袂飘飘潇洒出尘的琴师。两人在经典地点长安城朱雀桥相遇并举行婚礼。书中游戏既有一般游戏常见的跑环、摆摊,也有现阶段游戏不存在的宝宝结婚、抢亲等功能。</div><div class="line">书的销量:800000</div><div class="line"></div><div class="line">下面是解析类的注解信息:</div><div class="line"></div><div class="line"></div><div class="line">书名:泡沫之夏</div><div class="line">女主人公:尹夏沫</div><div class="line">书的简介:淡漠安静的性格使得欧辰与洛熙为她神魂颠倒。她是冷漠与激情混合体,只是在经过种种遭遇,饱尝了人间冷暖后。她用冷漠的外衣将自己包裹住,不愿让人看见自己真实的性格,最后与欧辰携手走进婚姻的殿堂。</div><div class="line">书的销量:1000000</div></pre></td></tr></table></figure>
<h1 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h1><ul>
<li>对局部变量的注解只能在源码级别上进行处理,class文件并不描述局部变量。因此,所有的局部变量注解在编译完一个类的时候就会被遗弃掉。同样的,对包的注解不能在源码级别之外存在。</li>
<li>一条没有@Target限制的注解可以应用于任何项上。</li>
<li>@Inherited元注解只能应用于对类的注解</li>
</ul>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p>《Java核心技术卷二》<br>《Thinking in Java》<br><a href="http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html" target="_blank" rel="external">http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html</a><br><a href="http://a.codekk.com/detail/Android/Trinea/公共技术点之%20Java%20注解%20Annotation" target="_blank" rel="external">http://a.codekk.com/detail/Android/Trinea/公共技术点之%20Java%20注解%20Annotation</a><br><a href="http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html" target="_blank" rel="external">http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html</a></p>
]]></content>
<summary type="html">
<h1 id="注解的定义"><a href="#注解的定义" class="headerlink" title="注解的定义"></a>注解的定义</h1><ul>
<li>定义</li>
</ul>
<p>注解:提供一种为程序元素设置元数据的方法。</p>
<font col
</summary>
<category term="内功修养" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Java" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/"/>
<category term="注解" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/%E6%B3%A8%E8%A7%A3/"/>
<category term="公共基础知识" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/Java/%E6%B3%A8%E8%A7%A3/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="内功修养" scheme="http://akathink.com/tags/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="Java" scheme="http://akathink.com/tags/Java/"/>
<category term="公共基础知识" scheme="http://akathink.com/tags/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="注解" scheme="http://akathink.com/tags/%E6%B3%A8%E8%A7%A3/"/>
</entry>
<entry>
<title>彻底搞懂红黑树</title>
<link href="http://akathink.com/2016/08/08/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%87%82%E7%BA%A2%E9%BB%91%E6%A0%91/"/>
<id>http://akathink.com/2016/08/08/彻底搞懂红黑树/</id>
<published>2016-08-08T11:29:18.000Z</published>
<updated>2016-08-10T13:51:09.000Z</updated>
<content type="html"><![CDATA[<h1 id="背景知识"><a href="#背景知识" class="headerlink" title="背景知识"></a>背景知识</h1><h2 id="二叉树"><a href="#二叉树" class="headerlink" title="二叉树"></a>二叉树</h2><h3 id="定义:"><a href="#定义:" class="headerlink" title="定义:"></a>定义:</h3><p>二叉树(Binary Tree)是n(n >= 0)个节点的有限集合。该集合或者未空集(称为空二叉树),或者由一个根节点和两棵互不相交的,分别称为根节点的左子树和右子树的二叉树组成。</p>
<h3 id="二叉树特点"><a href="#二叉树特点" class="headerlink" title="二叉树特点"></a>二叉树特点</h3><ul>
<li>每个节点 <font color="#00ffff" size="4">最多</font> 有两棵子树。所以二叉树中不存在大于2的节点。</li>
<li>左子树和右子树是有顺序的,次序不能任一颠倒。就像人的双手和双脚,显然左手和右手,左脚和右脚都是不能颠倒顺序呼唤的,否则那也太别扭了。</li>
<li>即使树中某节点只有一棵子树,也要区分它是左子树还是右子树。</li>
</ul>
<h2 id="特殊二叉树"><a href="#特殊二叉树" class="headerlink" title="特殊二叉树"></a>特殊二叉树</h2><ul>
<li>斜树:顾名思义,斜树一定是斜的,所有的节点都只有左子树的二叉树叫左斜树,所有节点都是只有右子树的二叉树叫右斜树,两者统称为斜树。</li>
<li>满二叉树:在一棵二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。</li>
<li>完全二叉树:对一棵具有n个节点的二叉树按层序编号,如果编号为i(1<=i<=n)的节点与同样深度的满二叉树编号为i的节点在二叉树中位置完全相同,则称该二叉树为完全二叉树。满二叉树一定是完全二叉树,但完全二叉树不一定是满的。</li>
<li>赫夫曼树:是一种带权路径长度最短的树。</li>
<li><p>平衡二叉树:是一种 <strong><font color="#00ffff" size="4">二叉排序树(或者叫二叉查找树)</font></strong>,其中每个节点的左子树和右子树的高度差至多等于1.<br>那么什么是二叉排序树呢?二叉排序树(Binary Sort Tree),又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;</div><div class="line">若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;</div><div class="line">它的左右子树也分别为二叉排序树。</div></pre></td></tr></table></figure>
</li>
<li><p>红黑树:具体定义和性质请往下看。</p>
</li>
</ul>
<h1 id="红黑树"><a href="#红黑树" class="headerlink" title="红黑树"></a>红黑树</h1><h2 id="定义:-1"><a href="#定义:-1" class="headerlink" title="定义:"></a>定义:</h2><p>红黑树,一种自平衡的 <strong><font color="#00ffff" size="4">二叉查找树</font></strong>,但在每个节点上有一个额外的存储位表示节点的颜色,可以是Red或者Black。这些颜色位用来确保红黑树在插入和删除操作后仍能近乎平衡。</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E7%BA%A2%E9%BB%91%E6%A0%91%E7%A4%BA%E6%84%8F%E5%9B%BE.jpg" alt="红黑树示意图"></p>
<h2 id="红黑树的五个性质:"><a href="#红黑树的五个性质:" class="headerlink" title="红黑树的五个性质:"></a>红黑树的五个性质:</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">* 性质一:节点要么是红色要么是黑色。</div><div class="line">* 性质二:根节点是黑色。</div><div class="line">* 性质三:所有叶子节点都是黑色(叶子是NIL节点,被称为<font color=#00ffff size=4>黑哨兵</font>)。</div><div class="line">* 性质四:每个红色节点的两个子节点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色节点)。</div><div class="line">* 性质五:从任一节点到每个叶子节点的所有路径都包含相同数目的黑色节点。</div></pre></td></tr></table></figure>
<p>这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。</p>
<h2 id="红黑树的应用场景"><a href="#红黑树的应用场景" class="headerlink" title="红黑树的应用场景"></a>红黑树的应用场景</h2><p>到此,我们可能已经对红黑树有了一点初步的认识了,但是我们却不知道为什么要有红黑树,红黑树是为了解决什么问题被提出来的呢?<br>我们知道,二叉查找树在大多数情况下查找和插入在效率上是没有问题的,但是在最坏的情况下效率比较低,但是平衡二叉树能够保证在最坏的情况下也能达到lgN,要实现这一目标,我们就要保证在插入完成后始终保持平衡状态。在一棵具有N个节点的树中,我们希望该树的高度能够维持在lgN左右,这样我们就能保证只需要lgN次比较操作就可以查找到想要的值。不幸的是,每次插入元素之后维持树的平衡状态太昂贵。所以就出现一些新的数据结构来保证在最坏的情况下插入和查找效率都能保证在对数的时间复杂度内完成。而我们所讲的红黑树就属于此新的数据结构之一,除此之外还有B树等数据结构。</p>
<p>HashMap Java1.8版本对HashMap做了优化,采用数组+链表+红黑树的数据结构,除此之外TreeMap也是采用的红黑树的数据结构来实现的。</p>
<h2 id="旋转操作"><a href="#旋转操作" class="headerlink" title="旋转操作"></a>旋转操作</h2><p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E5%B7%A6%E6%97%8B%E5%8F%B3%E6%97%8B%E7%A4%BA%E6%84%8F%E5%9B%BE.jpg" alt="左旋和右旋"></p>
<h2 id="红黑树查询操作"><a href="#红黑树查询操作" class="headerlink" title="红黑树查询操作"></a>红黑树查询操作</h2><h2 id="红黑树插入操作"><a href="#红黑树插入操作" class="headerlink" title="红黑树插入操作"></a>红黑树插入操作</h2><p>若将一个节点插入到红黑树中,我们需要执行哪些操作呢?</p>
<ul>
<li>首先,将红黑树当作一棵二叉查找树,将节点插入;</li>
<li>其次,将待插入节点着色为红色;</li>
<li>最后,通过“旋转和重新着色”等一系列操作来修正该树,使之重新成为一棵红黑树。</li>
</ul>
<p>下面分别解释一下这三步操作:</p>
<h3 id="第一步:将红黑树当作一棵二叉查找树,将节点插入"><a href="#第一步:将红黑树当作一棵二叉查找树,将节点插入" class="headerlink" title="第一步:将红黑树当作一棵二叉查找树,将节点插入"></a>第一步:将红黑树当作一棵二叉查找树,将节点插入</h3><p>红黑树本身就是一棵二叉查找树,将新节点插入后,该树仍然是一棵二叉查找树。也就意味着,树的键值仍然是有序的。此外,无论是左旋还是右旋,若旋转之前这棵树是二叉查找树,那么旋转之后它一定还是二叉查找树。这也就意味着,任何的旋转和重新着色操作,都不会改变它仍然是一棵二叉查找树的事实。</p>
<h3 id="第二步:将待插入节点着色为红色"><a href="#第二步:将待插入节点着色为红色" class="headerlink" title="第二步:将待插入节点着色为红色"></a>第二步:将待插入节点着色为红色</h3><p>为什么插入的节点是红色,而不是黑色呢?</p>
<p>如果插入的是黑色节点,则肯定会在某条路径上增加黑色节点的数目,从而导致整棵树高度的不平衡,也就违反了红黑树的第五条性质;但如果新节点的父节点为红色时(如下图),将会违反红黑树性质四:一条路径上不能出现连续的两个红色节点,这时就需要通过一系列操作来使红黑树保持平衡。</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E7%BA%A2%E9%BB%91%E6%A0%91%E4%B9%8B%E6%8F%92%E5%85%A5%E7%BA%A2%E8%89%B2%E8%8A%82%E7%82%B9.jpg" alt="红黑树之插入红色节点"></p>
<p>若将插入节点更改为“红色”节点,会违背红黑树的哪些性质呢?</p>
<ul>
<li>对于性质一,因为我们已经将插入节点涂成红色了,所以肯定不会违背。</li>
<li>对于性质二,因为我们是将红黑树当作二叉查找树,然后执行的插入操作。而根据二叉查找树的特点。插入操作不会改变根节点,所以根节点依然是黑色,也不会违背该性质。</li>
<li>对于性质三:因为叶子节点是黑哨兵,都是一些空节点,我们此时插入的是非空节点,所以也不会违背该性质。</li>
<li>对于性质四:<font color="#0891ff" size="4">有可能会违背</font>。</li>
<li>对于性质五:因为插入的是红色节点,肯定不会影响某条路径上的黑色节点的数目的,所以肯定不会违背性质五。</li>
</ul>
<p>经过上面的分析可知,想办法使之满足“性质四”,就可以将树重新构造成红黑树了。</p>
<h3 id="第三步:通过“旋转和重新着色”等一系列操作来修正该树,使之重新成为一棵红黑树"><a href="#第三步:通过“旋转和重新着色”等一系列操作来修正该树,使之重新成为一棵红黑树" class="headerlink" title="第三步:通过“旋转和重新着色”等一系列操作来修正该树,使之重新成为一棵红黑树"></a>第三步:通过“旋转和重新着色”等一系列操作来修正该树,使之重新成为一棵红黑树</h3><p>为了更清晰地了解红黑树的插入操作,下面将会分具体的几种情况来介绍:</p>
<p>假设我们将要插入的节点用“新”表示,新插入节点的父节点用“父”表示,使用“叔”字表示“父”节点的兄弟节点,使用“祖”字表示“父”节点的父节点。</p>
<ul>
<li>黑“父”</li>
</ul>
<p>如下图所示,如果“新”节点的父节点为黑色,那么插入一个红节点,将不会影响红黑树的平衡,此时插入操作完成。红黑树比AVL树优秀的地方之一在于黑父的情况比较常见,从而使红黑树需要旋转的概率相对AVL树来说会少一些。</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E9%BB%91%E7%88%B6new.jpg" alt="黑父"></p>
<ul>
<li>红“父”</li>
</ul>
<p>如下图所示。如果“新”节点的父节点为红色,若要新插入红色的“新”节点就违背了性质四:每条路径上不能有连续的两个红节点。由于”父”节点为红色,那么“祖”节点肯定为黑色。蓝色节点表示颜色未知。由于有可能需要根节点到“新”节点的路径上进行多次旋转操作,而每次进行不平衡判断的起始点都不一样,所以我们使用一个黑色箭头指向这个起始点,并称之为判定点。</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E7%BA%A2%E7%88%B6new.jpg" alt="红父"></p>
<ol>
<li>红”叔”</li>
</ol>
<p>当“叔”节点为红色时,如下图所示,无需进行旋转操作,只要将父和叔节点变为黑色,将”祖”节点变为红色即可。但由于祖父节点的父节点有可能为红色,从而违反红黑树性质。此时必须将祖父节点作为新的判定点继续向上进行平衡操作。</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E7%BA%A2%E5%8F%94.jpg" alt="红叔"></p>
<p>需要注意,无论“父”在”叔“的左边还是右边,无论“新”是”父”的左孩子还是右孩子,它们的操作都是完全一样的。</p>
<ol>
<li>黑“叔”</li>
</ol>
<ul>
<li>情形1:</li>
</ul>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E9%BB%91%E5%8F%94LL%E6%97%8B%E8%BD%AC.jpg" alt="黑叔LL旋转"></p>
<ul>
<li>情形2:</li>
</ul>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E9%BB%91%E6%A0%91LR%E6%97%8B%E8%BD%AC.jpg" alt="黑叔LR旋转"></p>
<ul>
<li>情形3:</li>
</ul>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E9%BB%91%E5%8F%94RR%E6%97%8B%E8%BD%AC.jpg" alt="黑叔RR旋转"></p>
<ul>
<li>情形4:</li>
</ul>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E9%BB%91%E5%8F%94RL%E6%97%8B%E8%BD%AC.jpg" alt="黑叔RL旋转"></p>
<p>可以观察到,当旋转完成后,新的旋转根全部为黑色,此时不需要再向上回溯进行平衡操作,插入操作完成。需要注意,上面四张图的“叔”、“1”、“2”、“3”结点有可能为黑哨兵结点。</p>
<h2 id="红黑树删除操作"><a href="#红黑树删除操作" class="headerlink" title="红黑树删除操作"></a>红黑树删除操作</h2><p>相对于红黑树的查询和插入操作来说,删除操作相对会更复杂一些,也就是我们传说中所说的“请神容易送神难”!</p>
<p>那么如果我们删除一个节点,需要执行哪些操作呢?</p>
<ul>
<li>首先,将红黑树当作一棵二叉查找树,将该节点从二叉查找树中删除;</li>
<li>然后,通过“旋转和着色”等一系列操作来修正该树,使之重新成为一棵红黑树。</li>
</ul>
<p>下面分别解释一下这两步操作:</p>
<h3 id="第一步:将红黑树当作一棵二叉查找树,将节点删除。"><a href="#第一步:将红黑树当作一棵二叉查找树,将节点删除。" class="headerlink" title="第一步:将红黑树当作一棵二叉查找树,将节点删除。"></a>第一步:将红黑树当作一棵二叉查找树,将节点删除。</h3><p>这和“删除常规二叉查找树中删除节点的方法是一样的”,分三种情况:</p>
<ol>
<li>被删除节点为叶子节点,那么直接删除该节点就OK了;</li>
<li>被删除节点只有一个孩子节点,那么直接删除该节点,利用该节点的孩子节点直接顶替它的位置;</li>
<li>被删除节点有两个儿子,真正的删除点应该是所要删除节点的中序遍历前驱。</li>
</ol>
<h3 id="第二步:通过“旋转和着色”等一系列操作来修正该树,使之重新成为一棵红黑树。"><a href="#第二步:通过“旋转和着色”等一系列操作来修正该树,使之重新成为一棵红黑树。" class="headerlink" title="第二步:通过“旋转和着色”等一系列操作来修正该树,使之重新成为一棵红黑树。"></a>第二步:通过“旋转和着色”等一系列操作来修正该树,使之重新成为一棵红黑树。</h3><p>因为”第一步”中删除节点之后,可能会违背红黑树的特性。所以需要通过”旋转和重新着色”来修正该树,使之重新成为一棵红黑树。</p>
<p><img src="http://7xt310.com1.z0.glb.clouddn.com/%E7%BA%A2%E9%BB%91%E6%A0%91%E5%88%A0%E9%99%A4%E8%8A%82%E7%82%B9%E7%A4%BA%E6%84%8F%E5%9B%BE.jpg" alt="红黑树删除节点示意图"></p>
<p>由上图和第一步可以推断出,在进行删除操作时,真正的删除点必定是只有一个孩子或没有孩子的结点。而根据红黑树的性质可以得出以下两个结论:</p>
<p><strong><font color="#ff0000" size="4">1、 删除操作中真正被删除的必定是只有一个红色孩子或没有孩子的结点。</font></strong><br><strong><font color="#ff0000" size="4">2、 如果真正的删除点是一个红色结点,那么它必定是一个叶子结点。</font></strong></p>
<h1 id="完整参考代码"><a href="#完整参考代码" class="headerlink" title="完整参考代码"></a>完整参考代码</h1><p>红黑树数据结构</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div><div class="line">199</div><div class="line">200</div><div class="line">201</div><div class="line">202</div><div class="line">203</div><div class="line">204</div><div class="line">205</div><div class="line">206</div><div class="line">207</div><div class="line">208</div><div class="line">209</div><div class="line">210</div><div class="line">211</div><div class="line">212</div><div class="line">213</div><div class="line">214</div><div class="line">215</div><div class="line">216</div><div class="line">217</div><div class="line">218</div><div class="line">219</div><div class="line">220</div><div class="line">221</div><div class="line">222</div><div class="line">223</div><div class="line">224</div><div class="line">225</div><div class="line">226</div><div class="line">227</div><div class="line">228</div><div class="line">229</div><div class="line">230</div><div class="line">231</div><div class="line">232</div><div class="line">233</div><div class="line">234</div><div class="line">235</div><div class="line">236</div><div class="line">237</div><div class="line">238</div><div class="line">239</div><div class="line">240</div><div class="line">241</div><div class="line">242</div><div class="line">243</div><div class="line">244</div><div class="line">245</div><div class="line">246</div><div class="line">247</div><div class="line">248</div><div class="line">249</div><div class="line">250</div><div class="line">251</div><div class="line">252</div><div class="line">253</div><div class="line">254</div><div class="line">255</div><div class="line">256</div><div class="line">257</div><div class="line">258</div><div class="line">259</div><div class="line">260</div><div class="line">261</div><div class="line">262</div><div class="line">263</div><div class="line">264</div><div class="line">265</div><div class="line">266</div><div class="line">267</div><div class="line">268</div><div class="line">269</div><div class="line">270</div><div class="line">271</div><div class="line">272</div><div class="line">273</div><div class="line">274</div><div class="line">275</div><div class="line">276</div><div class="line">277</div><div class="line">278</div><div class="line">279</div><div class="line">280</div><div class="line">281</div><div class="line">282</div><div class="line">283</div><div class="line">284</div><div class="line">285</div><div class="line">286</div><div class="line">287</div><div class="line">288</div><div class="line">289</div><div class="line">290</div><div class="line">291</div><div class="line">292</div><div class="line">293</div><div class="line">294</div><div class="line">295</div><div class="line">296</div><div class="line">297</div><div class="line">298</div><div class="line">299</div><div class="line">300</div><div class="line">301</div><div class="line">302</div><div class="line">303</div><div class="line">304</div><div class="line">305</div><div class="line">306</div><div class="line">307</div><div class="line">308</div><div class="line">309</div><div class="line">310</div><div class="line">311</div><div class="line">312</div><div class="line">313</div><div class="line">314</div><div class="line">315</div><div class="line">316</div><div class="line">317</div><div class="line">318</div><div class="line">319</div><div class="line">320</div><div class="line">321</div><div class="line">322</div><div class="line">323</div><div class="line">324</div><div class="line">325</div><div class="line">326</div><div class="line">327</div><div class="line">328</div><div class="line">329</div><div class="line">330</div><div class="line">331</div><div class="line">332</div><div class="line">333</div><div class="line">334</div><div class="line">335</div><div class="line">336</div><div class="line">337</div><div class="line">338</div><div class="line">339</div><div class="line">340</div><div class="line">341</div><div class="line">342</div><div class="line">343</div><div class="line">344</div><div class="line">345</div><div class="line">346</div><div class="line">347</div><div class="line">348</div><div class="line">349</div><div class="line">350</div><div class="line">351</div><div class="line">352</div><div class="line">353</div><div class="line">354</div><div class="line">355</div><div class="line">356</div><div class="line">357</div><div class="line">358</div><div class="line">359</div><div class="line">360</div><div class="line">361</div><div class="line">362</div><div class="line">363</div><div class="line">364</div><div class="line">365</div><div class="line">366</div><div class="line">367</div><div class="line">368</div><div class="line">369</div><div class="line">370</div><div class="line">371</div><div class="line">372</div><div class="line">373</div><div class="line">374</div><div class="line">375</div><div class="line">376</div><div class="line">377</div><div class="line">378</div><div class="line">379</div><div class="line">380</div><div class="line">381</div><div class="line">382</div><div class="line">383</div><div class="line">384</div><div class="line">385</div><div class="line">386</div><div class="line">387</div><div class="line">388</div><div class="line">389</div><div class="line">390</div><div class="line">391</div><div class="line">392</div><div class="line">393</div><div class="line">394</div><div class="line">395</div><div class="line">396</div><div class="line">397</div><div class="line">398</div><div class="line">399</div><div class="line">400</div><div class="line">401</div><div class="line">402</div><div class="line">403</div><div class="line">404</div><div class="line">405</div><div class="line">406</div><div class="line">407</div><div class="line">408</div><div class="line">409</div><div class="line">410</div><div class="line">411</div><div class="line">412</div><div class="line">413</div><div class="line">414</div><div class="line">415</div><div class="line">416</div><div class="line">417</div><div class="line">418</div><div class="line">419</div><div class="line">420</div><div class="line">421</div><div class="line">422</div><div class="line">423</div><div class="line">424</div><div class="line">425</div><div class="line">426</div><div class="line">427</div><div class="line">428</div><div class="line">429</div><div class="line">430</div><div class="line">431</div><div class="line">432</div><div class="line">433</div><div class="line">434</div><div class="line">435</div><div class="line">436</div><div class="line">437</div><div class="line">438</div><div class="line">439</div><div class="line">440</div><div class="line">441</div><div class="line">442</div><div class="line">443</div><div class="line">444</div><div class="line">445</div><div class="line">446</div><div class="line">447</div><div class="line">448</div><div class="line">449</div><div class="line">450</div><div class="line">451</div><div class="line">452</div><div class="line">453</div><div class="line">454</div><div class="line">455</div><div class="line">456</div><div class="line">457</div><div class="line">458</div><div class="line">459</div><div class="line">460</div><div class="line">461</div><div class="line">462</div><div class="line">463</div><div class="line">464</div><div class="line">465</div><div class="line">466</div><div class="line">467</div><div class="line">468</div><div class="line">469</div><div class="line">470</div><div class="line">471</div><div class="line">472</div><div class="line">473</div><div class="line">474</div><div class="line">475</div><div class="line">476</div><div class="line">477</div><div class="line">478</div><div class="line">479</div><div class="line">480</div><div class="line">481</div><div class="line">482</div><div class="line">483</div><div class="line">484</div><div class="line">485</div><div class="line">486</div><div class="line">487</div><div class="line">488</div><div class="line">489</div><div class="line">490</div><div class="line">491</div><div class="line">492</div><div class="line">493</div><div class="line">494</div><div class="line">495</div><div class="line">496</div><div class="line">497</div><div class="line">498</div><div class="line">499</div><div class="line">500</div><div class="line">501</div><div class="line">502</div><div class="line">503</div><div class="line">504</div><div class="line">505</div><div class="line">506</div><div class="line">507</div><div class="line">508</div><div class="line">509</div><div class="line">510</div><div class="line">511</div><div class="line">512</div><div class="line">513</div><div class="line">514</div><div class="line">515</div><div class="line">516</div><div class="line">517</div><div class="line">518</div><div class="line">519</div><div class="line">520</div><div class="line">521</div><div class="line">522</div><div class="line">523</div><div class="line">524</div><div class="line">525</div><div class="line">526</div><div class="line">527</div><div class="line">528</div><div class="line">529</div><div class="line">530</div><div class="line">531</div><div class="line">532</div><div class="line">533</div><div class="line">534</div><div class="line">535</div><div class="line">536</div><div class="line">537</div><div class="line">538</div><div class="line">539</div><div class="line">540</div><div class="line">541</div><div class="line">542</div><div class="line">543</div><div class="line">544</div><div class="line">545</div><div class="line">546</div><div class="line">547</div><div class="line">548</div><div class="line">549</div><div class="line">550</div><div class="line">551</div><div class="line">552</div><div class="line">553</div><div class="line">554</div><div class="line">555</div><div class="line">556</div><div class="line">557</div><div class="line">558</div><div class="line">559</div><div class="line">560</div><div class="line">561</div><div class="line">562</div><div class="line">563</div><div class="line">564</div><div class="line">565</div><div class="line">566</div><div class="line">567</div><div class="line">568</div><div class="line">569</div><div class="line">570</div><div class="line">571</div><div class="line">572</div><div class="line">573</div><div class="line">574</div><div class="line">575</div><div class="line">576</div><div class="line">577</div><div class="line">578</div><div class="line">579</div><div class="line">580</div><div class="line">581</div><div class="line">582</div><div class="line">583</div><div class="line">584</div><div class="line">585</div><div class="line">586</div><div class="line">587</div><div class="line">588</div><div class="line">589</div><div class="line">590</div><div class="line">591</div><div class="line">592</div><div class="line">593</div><div class="line">594</div><div class="line">595</div><div class="line">596</div><div class="line">597</div><div class="line">598</div><div class="line">599</div><div class="line">600</div><div class="line">601</div><div class="line">602</div><div class="line">603</div><div class="line">604</div><div class="line">605</div><div class="line">606</div><div class="line">607</div><div class="line">608</div><div class="line">609</div><div class="line">610</div><div class="line">611</div><div class="line">612</div><div class="line">613</div><div class="line">614</div><div class="line">615</div><div class="line">616</div><div class="line">617</div><div class="line">618</div><div class="line">619</div><div class="line">620</div><div class="line">621</div><div class="line">622</div><div class="line">623</div><div class="line">624</div><div class="line">625</div><div class="line">626</div><div class="line">627</div><div class="line">628</div><div class="line">629</div><div class="line">630</div><div class="line">631</div><div class="line">632</div><div class="line">633</div><div class="line">634</div><div class="line">635</div><div class="line">636</div><div class="line">637</div><div class="line">638</div><div class="line">639</div><div class="line">640</div><div class="line">641</div><div class="line">642</div><div class="line">643</div><div class="line">644</div><div class="line">645</div><div class="line">646</div><div class="line">647</div><div class="line">648</div><div class="line">649</div><div class="line">650</div><div class="line">651</div><div class="line">652</div><div class="line">653</div><div class="line">654</div><div class="line">655</div><div class="line">656</div><div class="line">657</div><div class="line">658</div><div class="line">659</div><div class="line">660</div><div class="line">661</div><div class="line">662</div><div class="line">663</div><div class="line">664</div><div class="line">665</div><div class="line">666</div><div class="line">667</div><div class="line">668</div><div class="line">669</div><div class="line">670</div><div class="line">671</div><div class="line">672</div><div class="line">673</div><div class="line">674</div><div class="line">675</div><div class="line">676</div><div class="line">677</div><div class="line">678</div><div class="line">679</div><div class="line">680</div><div class="line">681</div><div class="line">682</div><div class="line">683</div><div class="line">684</div><div class="line">685</div><div class="line">686</div><div class="line">687</div><div class="line">688</div><div class="line">689</div><div class="line">690</div><div class="line">691</div><div class="line">692</div><div class="line">693</div><div class="line">694</div><div class="line">695</div><div class="line">696</div><div class="line">697</div><div class="line">698</div><div class="line">699</div><div class="line">700</div><div class="line">701</div><div class="line">702</div><div class="line">703</div><div class="line">704</div><div class="line">705</div><div class="line">706</div><div class="line">707</div><div class="line">708</div><div class="line">709</div><div class="line">710</div><div class="line">711</div><div class="line">712</div><div class="line">713</div><div class="line">714</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> datastructure;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 红黑树的数据结构</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> <T></div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RBTree</span><<span class="title">T</span> <span class="keyword">extends</span> <span class="title">Comparable</span><<span class="title">T</span>>> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">private</span> RBTNode<T> mRoot;<span class="comment">// 根节点</span></div><div class="line"></div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">boolean</span> RED = <span class="keyword">false</span>;</div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">boolean</span> BLACK = <span class="keyword">true</span>;</div><div class="line"></div><div class="line"> <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RBTNode</span><<span class="title">T</span> <span class="keyword">extends</span> <span class="title">Comparable</span><<span class="title">T</span>>> </span>{</div><div class="line"> <span class="keyword">boolean</span> color;<span class="comment">// 颜色</span></div><div class="line"> T key;<span class="comment">// 关键字(键值)</span></div><div class="line"> RBTNode<T> left;<span class="comment">// 左孩子</span></div><div class="line"> RBTNode<T> right;<span class="comment">// 右孩子</span></div><div class="line"> RBTNode<T> parent;<span class="comment">// 父节点</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">RBTNode</span><span class="params">(<span class="keyword">boolean</span> color, T key, RBTNode<T> left, RBTNode<T> right, RBTNode<T> parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>();</div><div class="line"> <span class="keyword">this</span>.color = color;</div><div class="line"> <span class="keyword">this</span>.key = key;</div><div class="line"> <span class="keyword">this</span>.left = left;</div><div class="line"> <span class="keyword">this</span>.right = right;</div><div class="line"> <span class="keyword">this</span>.parent = parent;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> T <span class="title">getkey</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> key;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> <span class="string">""</span> + key + (<span class="keyword">this</span>.color == RED ? <span class="string">"(R)"</span> : <span class="string">"B"</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">RBTree</span><span class="params">()</span> </span>{</div><div class="line"> mRoot = <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> RBTNode<T> <span class="title">parentOf</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">return</span> node != <span class="keyword">null</span> ? node.parent : <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">colorOf</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">return</span> node != <span class="keyword">null</span> ? node.color : BLACK;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isRed</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">return</span> ((node != <span class="keyword">null</span>) && (node.color == RED)) ? <span class="keyword">true</span> : <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isBlack</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">return</span> isRed(node);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">setRed</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (node != <span class="keyword">null</span>) {</div><div class="line"> node.color = RED;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">setBlack</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (node != <span class="keyword">null</span>) {</div><div class="line"> node.color = BLACK;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">setParent</span><span class="params">(RBTNode<T> node, RBTNode<T> parent)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (node != <span class="keyword">null</span>) {</div><div class="line"> node.parent = parent;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(RBTNode<T> node, <span class="keyword">boolean</span> color)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (node != <span class="keyword">null</span>) {</div><div class="line"> node.color = color;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 前序遍历红黑树</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> tree</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">preOrder</span><span class="params">(RBTNode<T> tree)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tree != <span class="keyword">null</span>) {</div><div class="line"> System.out.print(tree.key + <span class="string">" "</span>);</div><div class="line"> preOrder(tree.left);</div><div class="line"> preOrder(tree.right);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">preOrder</span><span class="params">()</span> </span>{</div><div class="line"> preOrder(mRoot);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 中序遍历红黑树</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> tree</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">inOrder</span><span class="params">(RBTNode<T> tree)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tree != <span class="keyword">null</span>) {</div><div class="line"> inOrder(tree.left);</div><div class="line"> System.out.print(tree.key + <span class="string">" "</span>);</div><div class="line"> inOrder(tree.right);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">inOrder</span><span class="params">()</span> </span>{</div><div class="line"> inOrder(mRoot);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 后序遍历红黑树</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> tree</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">postOrder</span><span class="params">(RBTNode<T> tree)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tree != <span class="keyword">null</span>) {</div><div class="line"> postOrder(tree.left);</div><div class="line"> postOrder(tree.right);</div><div class="line"> System.out.print(tree.key + <span class="string">" "</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">postOrder</span><span class="params">()</span> </span>{</div><div class="line"> postOrder(mRoot);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * (递归实现)查找"红黑树x"中键值为key的节点</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> x</div><div class="line"> * <span class="doctag">@param</span> key</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> RBTNode<T> <span class="title">search</span><span class="params">(RBTNode<T> x, T key)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (x == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> x;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>) {</div><div class="line"> <span class="keyword">return</span> search(x.left, key);</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>) {</div><div class="line"> <span class="keyword">return</span> search(x.right, key);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">return</span> x;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> RBTNode<T> <span class="title">search</span><span class="params">(T key)</span> </span>{</div><div class="line"> <span class="keyword">return</span> search(mRoot, key);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * (非递归实现)查找"红黑树x"中键值为key的节点</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> x</div><div class="line"> * <span class="doctag">@param</span> key</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> RBTNode<T> <span class="title">iterativeSearch</span><span class="params">(RBTNode<T> x, T key)</span> </span>{</div><div class="line"> <span class="keyword">while</span> (x != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">int</span> cmp = key.compareTo(x.key);</div><div class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>) {</div><div class="line"> x = x.left;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (cmp > <span class="number">0</span>) {</div><div class="line"> x = x.right;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">return</span> x;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> x;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> RBTNode<T> <span class="title">iterativeSearch</span><span class="params">(T key)</span> </span>{</div><div class="line"> <span class="keyword">return</span> iterativeSearch(key);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 查找最小结点:返回tree为根结点的红黑树的最小结点。</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> tree</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> RBTNode<T> <span class="title">minimum</span><span class="params">(RBTNode<T> tree)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tree == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">while</span> (tree.left != <span class="keyword">null</span>) {</div><div class="line"> tree = tree.left;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> tree;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> T <span class="title">minimum</span><span class="params">()</span> </span>{</div><div class="line"> RBTNode<T> p = minimum(mRoot);</div><div class="line"> <span class="keyword">if</span> (p != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> p.key;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 查找最大结点:返回tree为根结点的红黑树的最大结点。</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> tree</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> RBTNode<T> <span class="title">maximum</span><span class="params">(RBTNode<T> tree)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tree == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">while</span> (tree.right != <span class="keyword">null</span>) {</div><div class="line"> tree = tree.right;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> tree;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> T <span class="title">maximum</span><span class="params">()</span> </span>{</div><div class="line"> RBTNode<T> p = maximum(mRoot);</div><div class="line"> <span class="keyword">if</span> (p != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> p.key;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> x</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> RBTNode<T> <span class="title">successor</span><span class="params">(RBTNode<T> x)</span> </span>{</div><div class="line"> <span class="comment">// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。</span></div><div class="line"> <span class="keyword">if</span> (x.right != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> minimum(x.right);</div><div class="line"> }</div><div class="line"> <span class="comment">// 如果x没有右孩子。则x有以下两种可能:</span></div><div class="line"> <span class="comment">// (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。</span></div><div class="line"> <span class="comment">// (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。</span></div><div class="line"> RBTNode<T> y = x.parent;</div><div class="line"> <span class="keyword">while</span> ((y != <span class="keyword">null</span>) && (x == y.right)) {</div><div class="line"> x = y;</div><div class="line"> y = y.parent;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> y;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> x</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> RBTNode<T> <span class="title">predecessor</span><span class="params">(RBTNode<T> x)</span> </span>{</div><div class="line"> <span class="comment">// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。</span></div><div class="line"> <span class="keyword">if</span> (x.left != <span class="keyword">null</span>)</div><div class="line"> <span class="keyword">return</span> maximum(x.left);</div><div class="line"></div><div class="line"> <span class="comment">// 如果x没有左孩子。则x有以下两种可能:</span></div><div class="line"> <span class="comment">// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。</span></div><div class="line"> <span class="comment">// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。</span></div><div class="line"> RBTNode<T> y = x.parent;</div><div class="line"> <span class="keyword">while</span> ((y != <span class="keyword">null</span>) && (x == y.left)) {</div><div class="line"> x = y;</div><div class="line"> y = y.parent;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> y;</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">/* 对红黑树的节点(x)进行左旋转</span></div><div class="line"> *</div><div class="line"> * 左旋示意图(对节点x进行左旋):</div><div class="line"> * px px</div><div class="line"> * / /</div><div class="line"> * x y </div><div class="line"> * / \ --(左旋)-. / \ #</div><div class="line"> * lx y x ry </div><div class="line"> * / \ / \</div><div class="line"> * ly ry lx ly </div><div class="line"> *</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">leftRotate</span><span class="params">(RBTNode<T> x)</span> </span>{</div><div class="line"> <span class="comment">// 设置x的右孩子为y</span></div><div class="line"> RBTNode<T> y = x.right;</div><div class="line"></div><div class="line"> <span class="comment">// 将 “y的左孩子” 设为 “x的右孩子”;</span></div><div class="line"> <span class="comment">// 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲”</span></div><div class="line"> x.right = y.left;</div><div class="line"> <span class="keyword">if</span> (y.left != <span class="keyword">null</span>)</div><div class="line"> y.left.parent = x;</div><div class="line"></div><div class="line"> <span class="comment">// 将 “x的父亲” 设为 “y的父亲”</span></div><div class="line"> y.parent = x.parent;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (x.parent == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">this</span>.mRoot = y; <span class="comment">// 如果 “x的父亲” 是空节点,则将y设为根节点</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">if</span> (x.parent.left == x)</div><div class="line"> x.parent.left = y; <span class="comment">// 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”</span></div><div class="line"> <span class="keyword">else</span></div><div class="line"> x.parent.right = y; <span class="comment">// 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// 将 “x” 设为 “y的左孩子”</span></div><div class="line"> y.left = x;</div><div class="line"> <span class="comment">// 将 “x的父节点” 设为 “y”</span></div><div class="line"> x.parent = y;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/* </span></div><div class="line"> * 对红黑树的节点(y)进行右旋转</div><div class="line"> *</div><div class="line"> * 右旋示意图(对节点y进行左旋):</div><div class="line"> * py py</div><div class="line"> * / /</div><div class="line"> * y x </div><div class="line"> * / \ --(右旋)-. / \ #</div><div class="line"> * x ry lx y </div><div class="line"> * / \ / \ #</div><div class="line"> * lx rx rx ry</div><div class="line"> *</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">rightRotate</span><span class="params">(RBTNode<T> y)</span> </span>{</div><div class="line"> <span class="comment">// 设置x是当前节点的左孩子。</span></div><div class="line"> RBTNode<T> x = y.left;</div><div class="line"></div><div class="line"> <span class="comment">// 将 “x的右孩子” 设为 “y的左孩子”;</span></div><div class="line"> <span class="comment">// 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”</span></div><div class="line"> y.left = x.right;</div><div class="line"> <span class="keyword">if</span> (x.right != <span class="keyword">null</span>)</div><div class="line"> x.right.parent = y;</div><div class="line"></div><div class="line"> <span class="comment">// 将 “y的父亲” 设为 “x的父亲”</span></div><div class="line"> x.parent = y.parent;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (y.parent == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">this</span>.mRoot = x; <span class="comment">// 如果 “y的父亲” 是空节点,则将x设为根节点</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">if</span> (y == y.parent.right)</div><div class="line"> y.parent.right = x; <span class="comment">// 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”</span></div><div class="line"> <span class="keyword">else</span></div><div class="line"> y.parent.left = x; <span class="comment">// (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// 将 “y” 设为 “x的右孩子”</span></div><div class="line"> x.right = y;</div><div class="line"></div><div class="line"> <span class="comment">// 将 “y的父节点” 设为 “x”</span></div><div class="line"> y.parent = x;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">insertFixUp</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> RBTNode<T> parent, gparent;</div><div class="line"></div><div class="line"> <span class="comment">// 若“父节点存在,并且父节点的颜色是红色”</span></div><div class="line"> <span class="keyword">while</span> (((parent = parentOf(node)) != <span class="keyword">null</span>) && isRed(parent)) {</div><div class="line"> gparent = parentOf(parent);</div><div class="line"></div><div class="line"> <span class="comment">// 若“父节点”是“祖父节点的左孩子”</span></div><div class="line"> <span class="keyword">if</span> (parent == gparent.left) {</div><div class="line"> <span class="comment">// Case 1条件:叔叔节点是红色</span></div><div class="line"> RBTNode<T> uncle = gparent.right;</div><div class="line"> <span class="keyword">if</span> ((uncle != <span class="keyword">null</span>) && isRed(uncle)) {</div><div class="line"> setBlack(uncle);</div><div class="line"> setBlack(parent);</div><div class="line"> setRed(gparent);</div><div class="line"> node = gparent;</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> } <span class="comment">// Case 2条件:叔叔是黑色,且当前节点是右孩子</span></div><div class="line"> <span class="keyword">if</span> (parent.right == node) {</div><div class="line"> RBTNode<T> tmp;</div><div class="line"> leftRotate(parent);</div><div class="line"> tmp = parent;</div><div class="line"> parent = node;</div><div class="line"> node = tmp;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Case 3条件:叔叔是黑色,且当前节点是左孩子。</span></div><div class="line"> setBlack(parent);</div><div class="line"> setRed(gparent);</div><div class="line"> rightRotate(gparent);</div><div class="line"> } <span class="keyword">else</span> { <span class="comment">// 若“z的父节点”是“z的祖父节点的右孩子”</span></div><div class="line"> <span class="comment">// Case 1条件:叔叔节点是红色</span></div><div class="line"> RBTNode<T> uncle = gparent.left;</div><div class="line"> <span class="keyword">if</span> ((uncle != <span class="keyword">null</span>) && isRed(uncle)) {</div><div class="line"> setBlack(uncle);</div><div class="line"> setBlack(parent);</div><div class="line"> setRed(gparent);</div><div class="line"> node = gparent;</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Case 2条件:叔叔是黑色,且当前节点是左孩子</span></div><div class="line"> <span class="keyword">if</span> (parent.left == node) {</div><div class="line"> RBTNode<T> tmp;</div><div class="line"> rightRotate(parent);</div><div class="line"> tmp = parent;</div><div class="line"> parent = node;</div><div class="line"> node = tmp;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Case 3条件:叔叔是黑色,且当前节点是右孩子。</span></div><div class="line"> setBlack(parent);</div><div class="line"> setRed(gparent);</div><div class="line"> leftRotate(gparent);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// 将根节点设为黑色</span></div><div class="line"> setBlack(<span class="keyword">this</span>.mRoot);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 将结点插入到红黑树中</div><div class="line"> *</div><div class="line"> * 参数说明: node 插入的结点 // 对应《算法导论》中的node</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> <span class="keyword">int</span> cmp;</div><div class="line"> RBTNode<T> y = <span class="keyword">null</span>;</div><div class="line"> RBTNode<T> x = <span class="keyword">this</span>.mRoot;</div><div class="line"></div><div class="line"> <span class="comment">// 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。</span></div><div class="line"> <span class="keyword">while</span> (x != <span class="keyword">null</span>) {</div><div class="line"> y = x;</div><div class="line"> cmp = node.key.compareTo(x.key);</div><div class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</div><div class="line"> x = x.left;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> x = x.right;</div><div class="line"> }</div><div class="line"></div><div class="line"> node.parent = y;</div><div class="line"> <span class="keyword">if</span> (y != <span class="keyword">null</span>) {</div><div class="line"> cmp = node.key.compareTo(y.key);</div><div class="line"> <span class="keyword">if</span> (cmp < <span class="number">0</span>)</div><div class="line"> y.left = node;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> y.right = node;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">this</span>.mRoot = node;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// 2. 设置节点的颜色为红色</span></div><div class="line"> node.color = RED;</div><div class="line"></div><div class="line"> <span class="comment">// 3. 将它重新修正为一颗二叉查找树</span></div><div class="line"> insertFixUp(node);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 新建结点(key),并将其插入到红黑树中</div><div class="line"> *</div><div class="line"> * 参数说明: key 插入结点的键值</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(T key)</span> </span>{</div><div class="line"> RBTNode<T> node = <span class="keyword">new</span> RBTNode<T>(BLACK, key, <span class="keyword">null</span>, <span class="keyword">null</span>, <span class="keyword">null</span>);</div><div class="line"></div><div class="line"> <span class="comment">// 如果新建结点失败,则返回。</span></div><div class="line"> <span class="keyword">if</span> (node != <span class="keyword">null</span>)</div><div class="line"> insert(node);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 红黑树删除修正函数</div><div class="line"> *</div><div class="line"> * 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数; 目的是将它重新塑造成一颗红黑树。</div><div class="line"> *</div><div class="line"> * 参数说明: node 待修正的节点</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">removeFixUp</span><span class="params">(RBTNode<T> node, RBTNode<T> parent)</span> </span>{</div><div class="line"> RBTNode<T> other;</div><div class="line"></div><div class="line"> <span class="keyword">while</span> ((node == <span class="keyword">null</span> || isBlack(node)) && (node != <span class="keyword">this</span>.mRoot)) {</div><div class="line"> <span class="keyword">if</span> (parent.left == node) {</div><div class="line"> other = parent.right;</div><div class="line"> <span class="keyword">if</span> (isRed(other)) {</div><div class="line"> <span class="comment">// Case 1: x的兄弟w是红色的</span></div><div class="line"> setBlack(other);</div><div class="line"> setRed(parent);</div><div class="line"> leftRotate(parent);</div><div class="line"> other = parent.right;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> ((other.left == <span class="keyword">null</span> || isBlack(other.left)) && (other.right == <span class="keyword">null</span> || isBlack(other.right))) {</div><div class="line"> <span class="comment">// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的</span></div><div class="line"> setRed(other);</div><div class="line"> node = parent;</div><div class="line"> parent = parentOf(node);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (other.right == <span class="keyword">null</span> || isBlack(other.right)) {</div><div class="line"> <span class="comment">// Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。</span></div><div class="line"> setBlack(other.left);</div><div class="line"> setRed(other);</div><div class="line"> rightRotate(other);</div><div class="line"> other = parent.right;</div><div class="line"> }</div><div class="line"> <span class="comment">// Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。</span></div><div class="line"> setColor(other, colorOf(parent));</div><div class="line"> setBlack(parent);</div><div class="line"> setBlack(other.right);</div><div class="line"> leftRotate(parent);</div><div class="line"> node = <span class="keyword">this</span>.mRoot;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"></div><div class="line"> other = parent.left;</div><div class="line"> <span class="keyword">if</span> (isRed(other)) {</div><div class="line"> <span class="comment">// Case 1: x的兄弟w是红色的</span></div><div class="line"> setBlack(other);</div><div class="line"> setRed(parent);</div><div class="line"> rightRotate(parent);</div><div class="line"> other = parent.left;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> ((other.left == <span class="keyword">null</span> || isBlack(other.left)) && (other.right == <span class="keyword">null</span> || isBlack(other.right))) {</div><div class="line"> <span class="comment">// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的</span></div><div class="line"> setRed(other);</div><div class="line"> node = parent;</div><div class="line"> parent = parentOf(node);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (other.left == <span class="keyword">null</span> || isBlack(other.left)) {</div><div class="line"> <span class="comment">// Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。</span></div><div class="line"> setBlack(other.right);</div><div class="line"> setRed(other);</div><div class="line"> leftRotate(other);</div><div class="line"> other = parent.left;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。</span></div><div class="line"> setColor(other, colorOf(parent));</div><div class="line"> setBlack(parent);</div><div class="line"> setBlack(other.left);</div><div class="line"> rightRotate(parent);</div><div class="line"> node = <span class="keyword">this</span>.mRoot;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (node != <span class="keyword">null</span>)</div><div class="line"> setBlack(node);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 删除结点(node),并返回被删除的结点</div><div class="line"> *</div><div class="line"> * 参数说明: node 删除的结点</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">(RBTNode<T> node)</span> </span>{</div><div class="line"> RBTNode<T> child, parent;</div><div class="line"> <span class="keyword">boolean</span> color;</div><div class="line"></div><div class="line"> <span class="comment">// 被删除节点的"左右孩子都不为空"的情况。</span></div><div class="line"> <span class="keyword">if</span> ((node.left != <span class="keyword">null</span>) && (node.right != <span class="keyword">null</span>)) {</div><div class="line"> <span class="comment">// 被删节点的后继节点。(称为"取代节点")</span></div><div class="line"> <span class="comment">// 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。</span></div><div class="line"> RBTNode<T> replace = node;</div><div class="line"></div><div class="line"> <span class="comment">// 获取后继节点</span></div><div class="line"> replace = replace.right;</div><div class="line"> <span class="keyword">while</span> (replace.left != <span class="keyword">null</span>)</div><div class="line"> replace = replace.left;</div><div class="line"></div><div class="line"> <span class="comment">// "node节点"不是根节点(只有根节点不存在父节点)</span></div><div class="line"> <span class="keyword">if</span> (parentOf(node) != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (parentOf(node).left == node)</div><div class="line"> parentOf(node).left = replace;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> parentOf(node).right = replace;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// "node节点"是根节点,更新根节点。</span></div><div class="line"> <span class="keyword">this</span>.mRoot = replace;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// child是"取代节点"的右孩子,也是需要"调整的节点"。</span></div><div class="line"> <span class="comment">// "取代节点"肯定不存在左孩子!因为它是一个后继节点。</span></div><div class="line"> child = replace.right;</div><div class="line"> parent = parentOf(replace);</div><div class="line"> <span class="comment">// 保存"取代节点"的颜色</span></div><div class="line"> color = colorOf(replace);</div><div class="line"></div><div class="line"> <span class="comment">// "被删除节点"是"它的后继节点的父节点"</span></div><div class="line"> <span class="keyword">if</span> (parent == node) {</div><div class="line"> parent = replace;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// child不为空</span></div><div class="line"> <span class="keyword">if</span> (child != <span class="keyword">null</span>)</div><div class="line"> setParent(child, parent);</div><div class="line"> parent.left = child;</div><div class="line"></div><div class="line"> replace.right = node.right;</div><div class="line"> setParent(node.right, replace);</div><div class="line"> }</div><div class="line"></div><div class="line"> replace.parent = node.parent;</div><div class="line"> replace.color = node.color;</div><div class="line"> replace.left = node.left;</div><div class="line"> node.left.parent = replace;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (color == BLACK)</div><div class="line"> removeFixUp(child, parent);</div><div class="line"></div><div class="line"> node = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (node.left != <span class="keyword">null</span>) {</div><div class="line"> child = node.left;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> child = node.right;</div><div class="line"> }</div><div class="line"></div><div class="line"> parent = node.parent;</div><div class="line"> <span class="comment">// 保存"取代节点"的颜色</span></div><div class="line"> color = node.color;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (child != <span class="keyword">null</span>)</div><div class="line"> child.parent = parent;</div><div class="line"></div><div class="line"> <span class="comment">// "node节点"不是根节点</span></div><div class="line"> <span class="keyword">if</span> (parent != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (parent.left == node)</div><div class="line"> parent.left = child;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> parent.right = child;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">this</span>.mRoot = child;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (color == BLACK)</div><div class="line"> removeFixUp(child, parent);</div><div class="line"> node = <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 删除结点(z),并返回被删除的结点</div><div class="line"> *</div><div class="line"> * 参数说明: tree 红黑树的根结点 z 删除的结点</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">(T key)</span> </span>{</div><div class="line"> RBTNode<T> node;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> ((node = search(mRoot, key)) != <span class="keyword">null</span>)</div><div class="line"> remove(node);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 销毁红黑树</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">destroy</span><span class="params">(RBTNode<T> tree)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tree == <span class="keyword">null</span>)</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (tree.left != <span class="keyword">null</span>)</div><div class="line"> destroy(tree.left);</div><div class="line"> <span class="keyword">if</span> (tree.right != <span class="keyword">null</span>)</div><div class="line"> destroy(tree.right);</div><div class="line"></div><div class="line"> tree = <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</div><div class="line"> destroy(mRoot);</div><div class="line"> mRoot = <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"> * 打印"红黑树"</div><div class="line"> *</div><div class="line"> * key -- 节点的键值 direction -- 0,表示该节点是根节点; -1,表示该节点是它的父结点的左孩子;</div><div class="line"> * 1,表示该节点是它的父结点的右孩子。</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">(RBTNode<T> tree, T key, <span class="keyword">int</span> direction)</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (tree != <span class="keyword">null</span>) {</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (direction == <span class="number">0</span>) <span class="comment">// tree是根节点</span></div><div class="line"> System.out.printf(<span class="string">"%2d(B) is root\n"</span>, tree.key);</div><div class="line"> <span class="keyword">else</span> <span class="comment">// tree是分支节点</span></div><div class="line"> System.out.printf(<span class="string">"%2d(%s) is %2d's %6s child\n"</span>, tree.key, isRed(tree) ? <span class="string">"R"</span> : <span class="string">"B"</span>, key,</div><div class="line"> direction == <span class="number">1</span> ? <span class="string">"right"</span> : <span class="string">"left"</span>);</div><div class="line"></div><div class="line"> print(tree.left, tree.key, -<span class="number">1</span>);</div><div class="line"> print(tree.right, tree.key, <span class="number">1</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">if</span> (mRoot != <span class="keyword">null</span>)</div><div class="line"> print(mRoot, mRoot.key, <span class="number">0</span>);</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>红黑树Demo测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> com.akathink.tree;</div><div class="line"></div><div class="line"><span class="keyword">import</span> datastructure.RBTree;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * 红黑树</div><div class="line"> *</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RBTreeDemo</span> </span>{</div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> a[] = { <span class="number">23</span>, <span class="number">16</span>, <span class="number">29</span>, <span class="number">12</span>, <span class="number">18</span>, <span class="number">26</span>, <span class="number">32</span>, <span class="number">13</span>, <span class="number">30</span>,<span class="number">49</span> };</div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">boolean</span> mDebugInsert = <span class="keyword">false</span>; <span class="comment">// "插入"动作的检测开关(false,关闭;true,打开)</span></div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">boolean</span> mDebugDelete = <span class="keyword">false</span>; <span class="comment">// "删除"动作的检测开关(false,关闭;true,打开)</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</div><div class="line"> <span class="keyword">int</span> i, ilen = a.length;</div><div class="line"> RBTree<Integer> tree = <span class="keyword">new</span> RBTree<Integer>();</div><div class="line"></div><div class="line"> System.out.printf(<span class="string">"== 原始数据: "</span>);</div><div class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < ilen; i++)</div><div class="line"> System.out.printf(<span class="string">"%d "</span>, a[i]);</div><div class="line"> System.out.printf(<span class="string">"\n"</span>);</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < ilen; i++) {</div><div class="line"> tree.insert(a[i]);</div><div class="line"> <span class="comment">// 设置mDebugInsert=true,测试"添加函数"</span></div><div class="line"> <span class="keyword">if</span> (mDebugInsert) {</div><div class="line"> System.out.printf(<span class="string">"== 添加节点: %d\n"</span>, a[i]);</div><div class="line"> System.out.printf(<span class="string">"== 树的详细信息: \n"</span>);</div><div class="line"> tree.print();</div><div class="line"> System.out.printf(<span class="string">"\n"</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> System.out.printf(<span class="string">"== 前序遍历: "</span>);</div><div class="line"> tree.preOrder();</div><div class="line"></div><div class="line"> System.out.printf(<span class="string">"\n== 中序遍历: "</span>);</div><div class="line"> tree.inOrder();</div><div class="line"></div><div class="line"> System.out.printf(<span class="string">"\n== 后序遍历: "</span>);</div><div class="line"> tree.postOrder();</div><div class="line"> System.out.printf(<span class="string">"\n"</span>);</div><div class="line"></div><div class="line"> System.out.printf(<span class="string">"== 最小值: %s\n"</span>, tree.minimum());</div><div class="line"> System.out.printf(<span class="string">"== 最大值: %s\n"</span>, tree.maximum());</div><div class="line"> System.out.printf(<span class="string">"== 树的详细信息: \n"</span>);</div><div class="line"> tree.print();</div><div class="line"> System.out.printf(<span class="string">"\n"</span>);</div><div class="line"></div><div class="line"> <span class="comment">// 设置mDebugDelete=true,测试"删除函数"</span></div><div class="line"> <span class="keyword">if</span> (mDebugDelete) {</div><div class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < ilen; i++) {</div><div class="line"> tree.remove(a[i]);</div><div class="line"></div><div class="line"> System.out.printf(<span class="string">"== 删除节点: %d\n"</span>, a[i]);</div><div class="line"> System.out.printf(<span class="string">"== 树的详细信息: \n"</span>);</div><div class="line"> tree.print();</div><div class="line"> System.out.printf(<span class="string">"\n"</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// 销毁二叉树</span></div><div class="line"> tree.clear();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>运行结果</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">== 原始数据: 23 16 29 12 18 26 32 13 30 49</div><div class="line">== 前序遍历: 23 16 12 13 18 29 26 32 30 49</div><div class="line">== 中序遍历: 12 13 16 18 23 26 29 30 32 49</div><div class="line">== 后序遍历: 13 12 18 16 26 30 49 32 29 23</div><div class="line">== 最小值: 12</div><div class="line">== 最大值: 49</div><div class="line">== 树的详细信息:</div><div class="line">23(B) is root</div><div class="line">16(R) is 23's left child</div><div class="line">12(B) is 16's left child</div><div class="line">13(R) is 12's right child</div><div class="line">18(B) is 16's right child</div><div class="line">29(R) is 23's right child</div><div class="line">26(B) is 29's left child</div><div class="line">32(B) is 29's right child</div><div class="line">30(R) is 32's left child</div><div class="line">49(R) is 32's right child</div></pre></td></tr></table></figure>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p>《大话数据结构》<br><a href="http://www.tuicool.com/articles/J3iMf2R" target="_blank" rel="external">http://www.tuicool.com/articles/J3iMf2R</a><br><a href="http://blog.csdn.net/eric491179912/article/details/6179908" target="_blank" rel="external">http://blog.csdn.net/eric491179912/article/details/6179908</a><br><a href="http://www.cnblogs.com/yangecnu/p/Introduce-2-3-Search-Tree.html" target="_blank" rel="external">http://www.cnblogs.com/yangecnu/p/Introduce-2-3-Search-Tree.html</a><br><a href="http://www.cnblogs.com/daoluanxiaozi/p/3340382.html" target="_blank" rel="external">http://www.cnblogs.com/daoluanxiaozi/p/3340382.html</a><br><a href="http://blog.csdn.net/loongshawn/article/details/50414608" target="_blank" rel="external">http://blog.csdn.net/loongshawn/article/details/50414608</a></p>
]]></content>
<summary type="html">
<h1 id="背景知识"><a href="#背景知识" class="headerlink" title="背景知识"></a>背景知识</h1><h2 id="二叉树"><a href="#二叉树" class="headerlink" title="二叉树"></a>二叉
</summary>
<category term="内功修养" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="数据结构" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
<category term="树" scheme="http://akathink.com/categories/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%A0%91/"/>
<category term="内功修养" scheme="http://akathink.com/tags/%E5%86%85%E5%8A%9F%E4%BF%AE%E5%85%BB/"/>
<category term="数据结构" scheme="http://akathink.com/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
<category term="红黑树" scheme="http://akathink.com/tags/%E7%BA%A2%E9%BB%91%E6%A0%91/"/>
<category term="树" scheme="http://akathink.com/tags/%E6%A0%91/"/>
</entry>
<entry>
<title>彻底搞懂Android安全架构:基础篇</title>
<link href="http://akathink.com/2016/08/05/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%87%82Android%E5%AE%89%E5%85%A8%E6%9E%B6%E6%9E%84:%E5%9F%BA%E7%A1%80%E7%AF%87/"/>
<id>http://akathink.com/2016/08/05/彻底搞懂Android安全架构:基础篇/</id>
<published>2016-08-05T02:21:52.000Z</published>
<updated>2016-08-08T12:59:56.000Z</updated>
<content type="html"><![CDATA[<h1 id="安全要解决什么问题?"><a href="#安全要解决什么问题?" class="headerlink" title="安全要解决什么问题?"></a>安全要解决什么问题?</h1><ul>
<li>保密(Security、Confidentiality):只想让部分有权限的人知晓,其他人是看不到的;</li>
<li>鉴别、认证(Authentication):确保通信的对方就是自己信得过的人;</li>
<li>完整性(Integrity):能够验证信息在传输过程中是否发生了篡改,或者数据丢失等现象</li>
<li>不可否认性(Non-repudiation):谁发的信息,能够表明发送者等身份。</li>
</ul>
<p>一些常用术语:</p>
<ul>
<li>密钥:分为加密密钥和解密密钥。</li>
<li>明文:没有进行加密,能够直接代表原文含义的信息。</li>
<li>密文:经过加密处理之后,隐藏原文含义的信息。</li>