-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1847 lines (1426 loc) · 352 KB
/
index.html
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<link rel="dns-prefetch" href="http://yoursite.com">
<title>Hexo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="Yuan Best">
<meta name="twitter:card" content="summary">
<link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link rel="stylesheet" type="text/css" href="/./main.0cf68a.css">
<style type="text/css">
#container.show {
background: linear-gradient(200deg,#a0cfe4,#e8c37e);
}
</style>
<meta name="generator" content="Hexo 4.2.1"></head>
<body>
<div id="container" q-class="show:isCtnShow">
<canvas id="anm-canvas" class="anm-canvas"></canvas>
<div class="left-col" q-class="show:isShow">
<div class="overlay" style="background: #4d4d4d"></div>
<div class="intrude-less">
<header id="header" class="inner">
<a href="/" class="profilepic">
<img src="" class="js-avatar">
</a>
<hgroup>
<h1 class="header-author"><a href="/">Yuan Best</a></h1>
</hgroup>
<nav class="header-menu">
<ul>
<li><a href="/">主页</a></li>
<li><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
<nav class="header-smart-menu">
<a q-on="click: openSlider(e, 'innerArchive')" href="javascript:void(0)">所有文章</a>
<a q-on="click: openSlider(e, 'friends')" href="javascript:void(0)">友链</a>
<a q-on="click: openSlider(e, 'aboutme')" href="javascript:void(0)">关于我</a>
</nav>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="#" title="github"><i class="icon-github"></i></a>
<a class="weibo" target="_blank" href="#" title="weibo"><i class="icon-weibo"></i></a>
<a class="rss" target="_blank" href="#" title="rss"><i class="icon-rss"></i></a>
<a class="zhihu" target="_blank" href="#" title="zhihu"><i class="icon-zhihu"></i></a>
</div>
</nav>
</header>
</div>
</div>
<div class="mid-col" q-class="show:isShow,hide:isShow|isFalse">
<nav id="mobile-nav">
<div class="overlay js-overlay" style="background: #4d4d4d"></div>
<div class="btnctn js-mobile-btnctn">
<div class="slider-trigger list" q-on="click: openSlider(e)"><i class="icon icon-sort"></i></div>
</div>
<div class="intrude-less">
<header id="header" class="inner">
<div class="profilepic">
<img src="" class="js-avatar">
</div>
<hgroup>
<h1 class="header-author js-header-author">Yuan Best</h1>
</hgroup>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="#" title="github"><i class="icon-github"></i></a>
<a class="weibo" target="_blank" href="#" title="weibo"><i class="icon-weibo"></i></a>
<a class="rss" target="_blank" href="#" title="rss"><i class="icon-rss"></i></a>
<a class="zhihu" target="_blank" href="#" title="zhihu"><i class="icon-zhihu"></i></a>
</div>
</nav>
<nav class="header-menu js-header-menu">
<ul style="width: 50%">
<li style="width: 50%"><a href="/">主页</a></li>
<li style="width: 50%"><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
</header>
</div>
<div class="mobile-mask" style="display:none" q-show="isShow"></div>
</nav>
<div id="wrapper" class="body-wrap">
<div class="menu-l">
<div class="canvas-wrap">
<canvas data-colors="#eaeaea" data-sectionHeight="100" data-contentId="js-content" id="myCanvas1" class="anm-canvas"></canvas>
</div>
<div id="js-content" class="content-ll">
<article id="post-解决eclipses完全没有自动提示的问题" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/06/30/%E8%A7%A3%E5%86%B3eclipses%E5%AE%8C%E5%85%A8%E6%B2%A1%E6%9C%89%E8%87%AA%E5%8A%A8%E6%8F%90%E7%A4%BA%E7%9A%84%E9%97%AE%E9%A2%98/">解决eclipses完全没有自动提示的问题</a>
</h1>
<a href="/2020/06/30/%E8%A7%A3%E5%86%B3eclipses%E5%AE%8C%E5%85%A8%E6%B2%A1%E6%9C%89%E8%87%AA%E5%8A%A8%E6%8F%90%E7%A4%BA%E7%9A%84%E9%97%AE%E9%A2%98/" class="archive-article-date">
<time datetime="2020-06-30T04:07:23.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-06-30</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="解决eclipses完全没有自动提示的问题:"><a href="#解决eclipses完全没有自动提示的问题:" class="headerlink" title="解决eclipses完全没有自动提示的问题:"></a>解决eclipses完全没有自动提示的问题:</h1><p><strong>步骤一</strong></p>
<p> window->Preferences->Java->Editor->content assist :<br>Enable auto activation菜单的第二项xxx triggers for java的值修改为:<br>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. (注意后面还有一个空格),保存就可以了(这个是触发自动补全)。</p>
<p><img src="https://i.loli.net/2020/06/30/yrch8iR9koWn1lH.jpg" alt="1.jpg"> </p>
<p> </p>
<p><strong>步骤二</strong><br>window->Preferences->Java->Editor->content assist=>Advanced,按如下修改:</p>
<p><img src="https://i.imgur.com/ehEbHDm.jpg" alt="Imgur.jpg"></p>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2020/06/30/%E8%A7%A3%E5%86%B3eclipses%E5%AE%8C%E5%85%A8%E6%B2%A1%E6%9C%89%E8%87%AA%E5%8A%A8%E6%8F%90%E7%A4%BA%E7%9A%84%E9%97%AE%E9%A2%98/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-Java-SE核心基础精要" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/06/30/Java-SE%E6%A0%B8%E5%BF%83%E5%9F%BA%E7%A1%80%E7%B2%BE%E8%A6%81/">Java-SE核心基础精要</a>
</h1>
<a href="/2020/06/30/Java-SE%E6%A0%B8%E5%BF%83%E5%9F%BA%E7%A1%80%E7%B2%BE%E8%A6%81/" class="archive-article-date">
<time datetime="2020-06-30T03:54:08.632Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-06-30</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="Java-基础核心总结"><a href="#Java-基础核心总结" class="headerlink" title="Java 基础核心总结"></a>Java 基础核心总结</h1><p>先来看一下本篇文章的思维导图吧,我会围绕下面这些内容进行讲解。内容很干,小伙伴们看完还希望不吝转发。(高清思维导图版本关注作者公众号 <code>Java建设者</code> 回复 <code>Java666</code> 获取,其他思维导图获取方式在文末)。</p>
<p><img src="https://img2020.cnblogs.com/blog/1515111/202005/1515111-20200509064225879-1748594128.png" alt=""></p>
<h2 id="Java-概述"><a href="#Java-概述" class="headerlink" title="Java 概述"></a>Java 概述</h2><h3 id="什么是-Java?"><a href="#什么是-Java?" class="headerlink" title="什么是 Java?"></a>什么是 Java?</h3><p>Java 是 Sun Microsystems 于1995 年首次发布的一种<code>编程语言</code>和计算平台。编程语言还比较好理解,那么什么是 <code>计算平台</code> 呢?</p>
<blockquote>
<p>计算平台是在电脑中运行应用程序(软件)的环境,包括<code>硬件环境</code>和<code>软件环境</code>。一般系统平台包括一台电脑的硬件体系结构、操作系统、运行时库。</p>
</blockquote>
<p>Java 是快速,安全和可靠的。 从笔记本电脑到数据中心,从游戏机到科学超级计算机,从手机到互联网,Java 无处不在!Java 主要分为三个版本</p>
<ul>
<li>JavaSE(J2SE)(Java2 Platform Standard Edition,java平台标准版)</li>
<li>JavaEE(J2EE)(Java 2 Platform,Enterprise Edition,java平台企业版)</li>
<li>JavaME(J2ME)(Java 2 Platform Micro Edition,java平台微型版)。</li>
</ul>
<h3 id="Java-的特点"><a href="#Java-的特点" class="headerlink" title="Java 的特点"></a>Java 的特点</h3><ul>
<li>Java 是一门<code>面向对象</code>的编程语言</li>
</ul>
<p>什么是面向对象?<code>面向对象(Object Oriented)</code> 是一种软件开发思想。它是对现实世界的一种抽象,面向对象会把相关的数据和方法组织为一个整体来看待。</p>
<p>相对的另外一种开发思想就是面向过程的开发思想,什么面向过程?<code>面向过程(Procedure Oriented)</code> 是一种以过程为中心的编程思想。举个例子:比如你是个学生,你每天去上学需要做几件事情?</p>
<p>起床、穿衣服、洗脸刷牙,吃饭,去学校。一般是顺序性的完成一系列动作。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">student</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">student_wakeUp</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">student_cloth</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">student_wash</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">student_eating</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">student_gotoSchool</span><span class="params">()</span></span>{...}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>而面向对象可以把学生进行抽象,所以这个例子就会变为</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">student</span>()</span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">wakeUp</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">cloth</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">wash</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">eating</span><span class="params">()</span></span>{...}</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">gotoSchool</span><span class="params">()</span></span>{...}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>可以不用严格按照顺序来执行每个动作。这是特点一。</p>
<ul>
<li>Java 摒弃了 C++ 中难以理解的多继承、指针、内存管理等概念;不用手动管理对象的生命周期,这是特征二。</li>
<li>Java 语言具有功能强大和简单易用两个特征,现在企业级开发,快速敏捷开发,尤其是各种框架的出现,使 Java 成为越来越火的一门语言。这是特点三。</li>
<li>Java 是一门静态语言,静态语言指的就是在编译期间就能够知道数据类型的语言,在运行前就能够检查类型的正确性,一旦类型确定后就不能再更改,比如下面这个例子。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">foo</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> x = <span class="number">5</span>;</span><br><span class="line"> <span class="keyword">boolean</span> b = x;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>静态语言主要有 <strong>Pascal, Perl, C/C++, JAVA, C#, Scala</strong> 等。</p>
<p>相对应的,动态语言没有任何特定的情况需要指定变量的类型,在运行时确定的数据类型。比如有*<em>Lisp, Perl, Python、Ruby、JavaScript *</em>等。</p>
<p>从设计的角度上来说,所有的语言都是设计用来把人类可读的代码转换为机器指令。动态语言是为了能够让程序员提高编码效率,因此你可以使用更少的代码来实现功能。静态语言设计是用来让硬件执行的更高效,因此需要程序员编写准确无误的代码,以此来让你的代码尽快的执行。从这个角度来说,静态语言的执行效率要比动态语言高,速度更快。这是特点四。</p>
<ul>
<li>Java 具有平台独立性和可移植性</li>
</ul>
<p>Java 有一句非常著名的口号: <code>Write once, run anywhere</code>,也就是一次编写、到处运行。为什么 Java 能够吹出这种牛批的口号来?核心就是 <code>JVM</code>。我们知道,计算机应用程序和硬件之间会屏蔽很多细节,它们之间依靠操作系统完成调度和协调,大致的体系结构如下</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwycV.png" alt="YKwycV.png"></p>
<p>那么加上 Java 应用、JVM 的体系结构会变为如下</p>
<img src="https://s1.ax1x.com/2020/05/08/YKws10.png" alt="YKws10.png" style="zoom:50%;" />
<p>Java 是跨平台的,已编译的 Java 程序可以在任何带有 JVM 的平台上运行。你可以在 Windows 平台下编写代码,然后拿到 Linux 平台下运行,该如何实现呢?</p>
<p>首先你需要在应用中编写 Java 代码;</p>
<p>用 <code>Eclipse</code> 或者 <code>javac</code> 把 Java 代码编译为 <code>.class</code> 文件;</p>
<p>然后把你的 .class 文件打成 <code>.jar</code> 文件;</p>
<p>然后你的 .jar 文件就能够在 Windows 、Mac OS X、Linux 系统下运行了。不同的操作系统有不同的 JVM 实现,切换平台时,不需要再次编译你的 Java 代码了。这是特点五。</p>
<ul>
<li>Java 能够容易实现多线程</li>
</ul>
<p>Java 是一门高级语言,高级语言会对用户屏蔽很多底层实现细节。比如 Java 是如何实现多线程的。从操作系统的角度来说,实现多线程的方式主要有下面这几种</p>
<p><strong>在用户空间中实现多线程</strong></p>
<p><strong>在内核空间中实现多线程</strong></p>
<p><strong>在用户和内核空间中混合实现线程</strong></p>
<p>而我认为 Java 应该是在 <code>用户空间</code> 实现的多线程,内核是感知不到 Java 存在多线程机制的。这是特点六。</p>
<ul>
<li>Java 具有高性能</li>
</ul>
<p>我们编写的代码,经过 javac 编译器编译称为 <code>字节码(bytecode)</code>,经过 JVM 内嵌的解释器将字节码转换为机器代码,这是解释执行,这种转换过程效率较低。但是部分 JVM 的实现比如 <code>Hotspot JVM</code> 都提供了 <code>JIT(Just-In-Time)</code> 编译器,也就是通常所说的动态编译器,JIT 能够在运行时将热点代码编译机器码,这种方式运行效率比较高,这是编译执行。所以 Java 不仅仅只是一种解释执行的语言。这是特点七。</p>
<ul>
<li>Java 语言具有健壮性</li>
</ul>
<p>Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证。这也是 Java 与 C 语言的重要区别。这是特点八。</p>
<ul>
<li>Java 很容易开发分布式项目</li>
</ul>
<p>Java 语言支持 Internet 应用的开发,Java 中有 net api,它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、ServerSocket等。Java的 <code>RMI(远程方法激活)</code>机制也是开发分布式应用的重要手段。这是特点九。</p>
<h3 id="Java-开发环境"><a href="#Java-开发环境" class="headerlink" title="Java 开发环境"></a>Java 开发环境</h3><h4 id="JDK"><a href="#JDK" class="headerlink" title="JDK"></a>JDK</h4><p><code>JDK(Java Development Kit)</code>称为 Java 开发包或 Java 开发工具,是一个编写 Java 的 Applet 小程序和应用程序的程序开发环境。JDK是整个Java的核心,包括了<code>Java运行环境(Java Runtime Environment)</code>,一些<code>Java 工具</code> 和 <code>Java 的核心类库(Java API)</code>。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwgnU.png" alt="YKwgnU.png"></p>
<p>我们可以认真研究一下这张图,它几乎包括了 Java 中所有的概念,我使用的是 <code>jdk1.8</code>,可以点进去 <code>Description of Java Conceptual Diagram</code>, 可以发现这里面包括了所有关于 Java 的描述</p>
<img src="https://s1.ax1x.com/2020/05/08/YKw2BF.png" alt="YKw2BF.png" style="zoom:50%;" />
<p>Oracle 提供了两种 Java 平台的实现,一种是我们上面说的 JDK,Java 开发标准工具包,一种是 JRE,叫做Java Runtime Environment,Java 运行时环境。JDK 的功能要比 JRE 全很多。</p>
<h4 id="JRE"><a href="#JRE" class="headerlink" title="JRE"></a>JRE</h4><p>JRE 是个运行环境,JDK 是个开发环境。因此写 Java 程序的时候需要 JDK,而运行 Java 程序的时候就需要JRE。而 JDK 里面已经包含了JRE,因此只要安装了JDK,就可以编辑 Java 程序,也可以正常运行 Java 程序。但由于 JDK 包含了许多与运行无关的内容,占用的空间较大,因此运行普通的 Java 程序无须安装 JDK,而只需要安装 JRE 即可。</p>
<h2 id="Java-开发环境配置"><a href="#Java-开发环境配置" class="headerlink" title="Java 开发环境配置"></a>Java 开发环境配置</h2><p>这个地方不再多说了,网上有很多教程配置的资料可供参考。</p>
<h2 id="Java-基本语法"><a href="#Java-基本语法" class="headerlink" title="Java 基本语法"></a>Java 基本语法</h2><p>在配置完 Java 开发环境,并下载 Java 开发工具(Eclipse、IDEA 等)后,就可以写 Java 代码了,因为本篇文章是从头梳理 Java 体系,所以有必要从基础的概念开始谈起。</p>
<h3 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h3><p>在 Java 中,数据类型只有<code>四类八种</code></p>
<ul>
<li>整数型:byte、short、int、long</li>
</ul>
<p>byte 也就是字节,1 byte = 8 bits,byte 的默认值是 0 ;</p>
<p>short 占用两个字节,也就是 16 位,1 short = 16 bits,它的默认值也是 0 ;</p>
<p>int 占用四个字节,也就是 32 位,1 int = 32 bits,默认值是 0 ;</p>
<p>long 占用八个字节,也就是 64 位,1 long = 64 bits,默认值是 0L;</p>
<p>所以整数型的占用字节大小空间为 long > int > short > byte</p>
<ul>
<li>浮点型</li>
</ul>
<p>浮点型有两种数据类型:float 和 double</p>
<p>float 是单精度浮点型,占用 4 位,1 float = 32 bits,默认值是 0.0f;</p>
<p>double 是双精度浮点型,占用 8 位,1 double = 64 bits,默认值是 0.0d;</p>
<ul>
<li>字符型</li>
</ul>
<p>字符型就是 char,char 类型是一个单一的 16 位 Unicode 字符,最小值是 <code>\u0000 (也就是 0 )</code>,最大值是 <code>\uffff (即为 65535)</code>,char 数据类型可以存储任何字符,例如 char a = ‘A’。</p>
<ul>
<li>布尔型</li>
</ul>
<p>布尔型指的就是 boolean,boolean 只有两种值,true 或者是 false,只表示 1 位,默认值是 false。</p>
<p>以上 <code>x 位</code>都指的是在内存中的占用。</p>
<p>![image-20200516070605375](/Users/mr.l/Library/Application Support/typora-user-images/image-20200516070605375.png)</p>
<h3 id="基础语法"><a href="#基础语法" class="headerlink" title="基础语法"></a>基础语法</h3><ul>
<li>大小写敏感:Java 是对大小写敏感的语言,例如 Hello 与 hello 是不同的,这其实就是 Java 的字符串表示方式</li>
<li>类名:对于所有的类来说,首字母应该大写,例如 <code>MyFirstClass</code></li>
<li>包名:包名应该尽量保证小写,例如 <code>my.first.package</code></li>
<li>方法名:方法名首字母需要小写,后面每个单词字母都需要大写,例如 <code>myFirstMethod()</code></li>
</ul>
<h3 id="运算符"><a href="#运算符" class="headerlink" title="运算符"></a>运算符</h3><p>运算符不只 Java 中有,其他语言也有运算符,运算符是一些特殊的符号,主要用于数学函数、一些类型的赋值语句和逻辑比较方面,我们就以 Java 为例,来看一下运算符。</p>
<ul>
<li>赋值运算符</li>
</ul>
<p>赋值运算符使用操作符 <code>=</code> 来表示,它的意思是把 = 号右边的值复制给左边,右边的值可以是任何常数、变量或者表达式,但左边的值必须是一个明确的,已经定义的变量。比如 <code>int a = 4</code>。</p>
<p>但是对于对象来说,复制的不是对象的值,而是对象的引用,所以如果说将一个对象复制给另一个对象,实际上是将<strong>一个对象的引用赋值给另一个对象</strong>。</p>
<ul>
<li>算数运算符</li>
</ul>
<p>算数运算符就和数学中的数值计算差不多,主要有 </p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKw4hR.png" alt="YKw4hR.png"></p>
<p>算数运算符需要注意的就是<code>优先级问题</code>,当一个表达式中存在多个操作符时,操作符的优先级顺序就决定了计算顺序,最简单的规则就是先乘除后加减,<code>()</code> 的优先级最高,没必要记住所有的优先级顺序,不确定的直接用 () 就可以了。</p>
<ul>
<li>自增、自减运算符</li>
</ul>
<p>这个就不文字解释了,解释不如直接看例子明白</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> a = <span class="number">5</span>;</span><br><span class="line">b = ++a;</span><br><span class="line">c = a++;</span><br></pre></td></tr></table></figure>
<ul>
<li>比较运算符</li>
</ul>
<p>比较运算符用于程序中的变量之间,变量和自变量之间以及其他类型的信息之间的比较。</p>
<p>比较运算符的运算结果是 boolean 型。当运算符对应的关系成立时,运算的结果为 true,否则为 false。比较运算符共有 6 个,通常作为判断的依据用于条件语句中。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwfAJ.png" alt="YKwfAJ.png"></p>
<ul>
<li>逻辑运算符</li>
</ul>
<p>逻辑运算符主要有三种,与、或、非</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwhN9.png" alt="YKwhN9.png"></p>
<p>下面是逻辑运算符对应的 true/false 符号表</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwI91.png" alt="YKwI91.png"></p>
<ul>
<li>按位运算符</li>
</ul>
<p>按位运算符用来操作整数基本类型中的每个<code>比特</code>位,也就是二进制位。按位操作符会对两个参数中对应的位执行布尔代数运算,并最终生成一个结果。</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>作用</th>
</tr>
</thead>
<tbody><tr>
<td>&</td>
<td>与 eg: 4 & 5 = 4</td>
</tr>
<tr>
<td>|</td>
<td>或 eg: 4 | 5 = 5</td>
</tr>
<tr>
<td>~</td>
<td>非 eg: ~4 = ~5</td>
</tr>
<tr>
<td>^</td>
<td>异或 eg : 4 ^ 5 = 1</td>
</tr>
</tbody></table>
<p>如果进行比较的双方是数字的话,那么进行比较就会变为按位运算。</p>
<p>按位与:按位进行与运算(AND),两个操作数中位都为1,结果才为1,否则结果为0。需要首先把比较双方转换成二进制再按每个位进行比较</p>
<p>按位或:按位进行或运算(OR),两个位只要有一个为1,那么结果就是1,否则就为0。</p>
<p>按位异或:按位进行异或运算(XOR),如果位为0,结果是1,如果位为1,结果是0。</p>
<p>按位非:按位进行取反运算(NOT),两个操作数的位中,相同则结果为0,不同则结果为1。</p>
<ul>
<li>移位运算符</li>
</ul>
<p>移位运算符用来将操作数向某个方向(向左或者右)移动指定的二进制位数。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwTc6.png" alt="YKwTc6.png"></p>
<ul>
<li>三元运算符</li>
</ul>
<p>三元运算符是类似 <code>if...else...</code> 这种的操作符,语法为:<strong>条件表达式?表达式 1:表达式 2</strong>。问号前面的位置是判断的条件,判断结果为布尔型,为 true 时调用表达式 1,为 false 时调用表达式 2。</p>
<h2 id="Java-执行控制流程"><a href="#Java-执行控制流程" class="headerlink" title="Java 执行控制流程"></a>Java 执行控制流程</h2><p>Java 中的控制流程其实和 C 一样,在 Java 中,流程控制会涉及到包括 <strong>if-else、while、do-while、for、return、break</strong> 以及选择语句 <code>switch</code>。下面以此进行分析</p>
<h3 id="条件语句"><a href="#条件语句" class="headerlink" title="条件语句"></a>条件语句</h3><p>条件语句可根据不同的条件执行不同的语句。包括 if 条件语句与 switch 多分支语句。</p>
<h4 id="if-条件语句"><a href="#if-条件语句" class="headerlink" title="if 条件语句"></a>if 条件语句</h4><p>if 语句可以单独判断表达式的结果,表示表达的执行结果,例如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">if</span>(a > <span class="number">10</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">false</span>;</span><br></pre></td></tr></table></figure>
<h4 id="if…else-条件语句"><a href="#if…else-条件语句" class="headerlink" title="if…else 条件语句"></a>if…else 条件语句</h4><p>if 语句还可以与 else 连用,通常表现为 <strong>如果满足某种条件,就进行某种处理,否则就进行另一种处理</strong>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">int</span> b = <span class="number">11</span>;</span><br><span class="line"><span class="keyword">if</span>(a >= b){</span><br><span class="line"> System.out.println(<span class="string">"a >= b"</span>);</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"> System.out.println(<span class="string">"a < b"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>if 后的 () 内的表达式必须是 boolean 型的。如果为 true,则执行 if 后的复合语句;如果为 false,则执行 else 后的复合语句。</p>
<h4 id="if…else-if-多分支语句"><a href="#if…else-if-多分支语句" class="headerlink" title="if…else if 多分支语句"></a>if…else if 多分支语句</h4><p>上面中的 if…else 是单分支和两个分支的判断,如果有多个判断条件,就需要使用 <strong>if…else if</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> x = <span class="number">40</span>;</span><br><span class="line"><span class="keyword">if</span>(x > <span class="number">60</span>) {</span><br><span class="line"> System.out.println(<span class="string">"x的值大于60"</span>);</span><br><span class="line">} <span class="keyword">else</span> <span class="keyword">if</span> (x > <span class="number">30</span>) {</span><br><span class="line"> System.out.println(<span class="string">"x的值大于30但小于60"</span>);</span><br><span class="line">} <span class="keyword">else</span> <span class="keyword">if</span> (x > <span class="number">0</span>) {</span><br><span class="line"> System.out.println(<span class="string">"x的值大于0但小于30"</span>);</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> System.out.println(<span class="string">"x的值小于等于0"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="switch-多分支语句"><a href="#switch-多分支语句" class="headerlink" title="switch 多分支语句"></a>switch 多分支语句</h4><p>一种比 *<em>if…else if *</em> 语句更优雅的方式是使用 <code>switch</code> 多分支语句,它的示例如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">switch</span> (week) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> System.out.println(<span class="string">"Monday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line"> System.out.println(<span class="string">"Tuesday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line"> System.out.println(<span class="string">"Wednesday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line"> System.out.println(<span class="string">"Thursday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">5</span>:</span><br><span class="line"> System.out.println(<span class="string">"Friday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">6</span>:</span><br><span class="line"> System.out.println(<span class="string">"Saturday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">7</span>:</span><br><span class="line"> System.out.println(<span class="string">"Sunday"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> System.out.println(<span class="string">"No Else"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="循环语句"><a href="#循环语句" class="headerlink" title="循环语句"></a>循环语句</h3><p>循环语句就是在满足一定的条件下反复执行某一表达式的操作,直到满足循环语句的要求。使用的循环语句主要有 *<em>for、do…while() 、 while *</em>,</p>
<h4 id="while-循环语句"><a href="#while-循环语句" class="headerlink" title="while 循环语句"></a>while 循环语句</h4><p>while 循环语句的循环方式为利用一个条件来控制是否要继续反复执行这个语句。while 循环语句的格式如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(布尔值){</span><br><span class="line"> 表达式</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>它的含义是,当 (布尔值) 为 true 的时候,执行下面的表达式,布尔值为 false 的时候,结束循环,布尔值其实也是一个表达式,比如 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">while</span>(a > <span class="number">5</span>){</span><br><span class="line"> a--;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="do…while-循环"><a href="#do…while-循环" class="headerlink" title="do…while 循环"></a>do…while 循环</h4><p>while 与 do…while 循环的唯一区别是 do…while 语句至少执行一次,即使第一次的表达式为 false。而在 while 循环中,如果第一次条件为 false,那么其中的语句根本不会执行。在实际应用中,while 要比 do…while 应用的更广。它的一般形式如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> b = <span class="number">10</span>;</span><br><span class="line"><span class="comment">// do···while循环语句</span></span><br><span class="line"><span class="keyword">do</span> {</span><br><span class="line"> System.out.println(<span class="string">"b == "</span> + b);</span><br><span class="line"> b--;</span><br><span class="line">} <span class="keyword">while</span>(b == <span class="number">1</span>);</span><br></pre></td></tr></table></figure>
<h4 id="for-循环语句"><a href="#for-循环语句" class="headerlink" title="for 循环语句"></a>for 循环语句</h4><p>for 循环是我们经常使用的循环方式,这种形式会在第一次迭代前进行初始化。它的形式如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(初始化; 布尔表达式; 步进){}</span><br></pre></td></tr></table></figure>
<p>每次迭代前会测试布尔表达式。如果获得的结果是 false,就会执行 for 语句后面的代码;每次循环结束,会按照步进的值执行下一次循环。</p>
<p><strong>逗号操作符</strong></p>
<p>这里不可忽略的一个就是逗号操作符,Java 里唯一用到逗号操作符的就是 for 循环控制语句。在表达式的初始化部分,可以使用一系列的逗号分隔的语句;通过逗号操作符,可以在 for 语句内定义多个变量,但它们必须具有相同的类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>,j = i + <span class="number">10</span>;i < <span class="number">5</span>;i++, j = j * <span class="number">2</span>){}</span><br></pre></td></tr></table></figure>
<p><strong>for-each 语句</strong></p>
<p>在 Java JDK 1.5 中还引入了一种更加简洁的、方便对数组和集合进行遍历的方法,即 <code>for-each</code> 语句,例子如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> array[] = {<span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>};</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> arr : array) {</span><br><span class="line"> System.out.println(arr);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="跳转语句"><a href="#跳转语句" class="headerlink" title="跳转语句"></a>跳转语句</h3><p>Java 语言中,有三种跳转语句: <strong>break、continue 和 return</strong></p>
<h4 id="break-语句"><a href="#break-语句" class="headerlink" title="break 语句"></a>break 语句</h4><p>break 语句我们在 switch 中已经见到了,它是用于终止循环的操作,实际上 break 语句在for、while、do···while循环语句中,用于强行退出当前循环,例如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>;i < <span class="number">10</span>;i++){</span><br><span class="line"> <span class="keyword">if</span>(i == <span class="number">5</span>){</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="continue-语句"><a href="#continue-语句" class="headerlink" title="continue 语句"></a>continue 语句</h4><p>continue 也可以放在循环语句中,它与 break 语句具有相反的效果,它的作用是用于执行下一次循环,而不是退出当前循环,还以上面的例子为主</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>;i < <span class="number">10</span>;i++){</span><br><span class="line"> </span><br><span class="line"> System.out.printl(<span class="string">" i = "</span> + i );</span><br><span class="line"> <span class="keyword">if</span>(i == <span class="number">5</span>){</span><br><span class="line"> System.out.printl(<span class="string">"continue ... "</span>);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong>return 语句</strong></p>
<p>return 语句可以从一个方法返回,并把控制权交给调用它的语句。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h2><p>下面我们来探讨面向对象的思想,面向对象的思想已经逐步取代了过程化的思想 — 面向过程,Java 是面向对象的高级编程语言,面向对象语言具有如下特征</p>
<ul>
<li><p>面向对象是一种常见的思想,比较符合人们的思考习惯;</p>
</li>
<li><p>面向对象可以将复杂的业务逻辑简单化,增强代码复用性;</p>
</li>
<li><p>面向对象具有抽象、封装、继承、多态等特性。</p>
</li>
</ul>
<p>面向对象的编程语言主要有:C++、Java、C#等。</p>
<p>所以必须熟悉面向对象的思想才能编写出 Java 程序。</p>
<h3 id="类也是一种对象"><a href="#类也是一种对象" class="headerlink" title="类也是一种对象"></a>类也是一种对象</h3><p>现在我们来认识一个面向对象的新的概念 — 类,什么是类,它就相当于是一系列对象的抽象,就比如书籍一样,类相当于是书的封面,大多数面向对象的语言都使用 <code>class</code> 来定义类,它告诉你它里面定义的对象都是什么样的,我们一般使用下面来定义类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ClassName</span> </span>{</span><br><span class="line"> <span class="comment">// body;</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>代码段中涉及一个新的概念 <code>//</code> ,这个我们后面会说。上面,你声明了一个 class 类,现在,你就可以使用 new 来创建这个对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ClassName classname = <span class="keyword">new</span> ClassName();</span><br></pre></td></tr></table></figure>
<p>一般,类的命名遵循<code>驼峰原则</code>,它的定义如下</p>
<blockquote>
<p>骆驼式命名法(Camel-Case)又称驼峰式命名法,是电脑程式编写时的一套命名规则(惯例)。正如它的名称 CamelCase 所表示的那样,是指混合使用大小写字母来构成变量和函数的名字。程序员们为了自己的代码能更容易的在同行之间交流,所以多采取统一的可读性比较好的命名方式。</p>
</blockquote>
<h3 id="对象的创建"><a href="#对象的创建" class="headerlink" title="对象的创建"></a>对象的创建</h3><p>在 Java 中,<strong>万事万物都是对象</strong>。这句话相信你一定不陌生,尽管一切都看作是对象,但是你操纵的却是一个对象的 <code>引用(reference)</code>。在这里有一个很形象的比喻:你可以把车钥匙和车看作是一组<strong>对象引用和对象</strong>的组合。当你想要开车的时候,你首先需要拿出车钥匙点击开锁的选项,停车时,你需要点击加锁来锁车。车钥匙相当于就是引用,车就是对象,由车钥匙来驱动车的加锁和开锁。并且,即使没有车的存在,车钥匙也是一个独立存在的实体,也就是说,<strong>你有一个对象引用,但你不一定需要一个对象与之关联</strong>,也就是</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Car carKey;</span><br></pre></td></tr></table></figure>
<p>这里创建的只是引用,而并非对象,但是如果你想要使用 s 这个引用时,会返回一个异常,告诉你需要一个对象来和这个引用进行关联。一种安全的做法是,在创建对象引用时同时把一个对象赋给它。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Car carKey = <span class="keyword">new</span> Car();</span><br></pre></td></tr></table></figure>
<p>在 Java 中,一旦创建了一个引用,就希望它能与一个新的对象进行关联,通常使用 <code>new</code> 操作符来实现这一目的。new 的意思是,给我一个新<code>对象</code>,如果你不想相亲,自己 new 一个对象就好了。祝你下辈子幸福。</p>
<h3 id="属性和方法"><a href="#属性和方法" class="headerlink" title="属性和方法"></a>属性和方法</h3><p>类一个最基本的要素就是有属性和方法。</p>
<p>属性也被称为字段,它是类的重要组成部分,属性可以是任意类型的对象,也可以是基本数据类型。例如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span>{</span><br><span class="line"> <span class="keyword">int</span> a;</span><br><span class="line"> Apple apple;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>类中还应该包括方法,方法表示的是 <strong>做某些事情的方式</strong>。方法其实就是函数,只不过 Java 习惯把函数称为方法。这种叫法也体现了面向对象的概念。</p>
<p>方法的基本组成包括 <strong>方法名称、参数、返回值和方法体</strong>, 下面是它的示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getResult</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中,<code>getResult</code> 就是方法名称、<code>()</code> 里面表示方法接收的参数、<code>return</code> 表示方法的返回值。有一种特殊的参数类型 — <code>void</code> 表示方法无返回值。<code>{}</code> 包含的代码段被称为方法体。</p>
<h4 id="构造方法"><a href="#构造方法" class="headerlink" title="构造方法"></a>构造方法</h4><p>在 Java 中,有一种特殊的方法被称为 <code>构造方法</code>,也被称为构造函数、构造器等。在 Java 中,通过提供这个构造器,来确保每个对象都被初始化。构造方法只能在对象的创建时期调用一次,保证了对象初始化的进行。构造方法比较特殊,它没有参数类型和返回值,它的名称要和类名保持一致,并且构造方法可以有多个,下面是一个构造方法的示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> sum;</span><br><span class="line"> String color;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">()</span></span>{}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(<span class="keyword">int</span> sum)</span></span>{}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(String color)</span></span>{}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(<span class="keyword">int</span> sum,String color)</span></span>{}</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上面定义了一个 Apple 类,你会发现这个 Apple 类没有参数类型和返回值,并且有多个以 Apple 同名的方法,而且各个 Apple 的参数列表都不一样,这其实是一种多态的体现,我们后面会说。在定义完成构造方法后,我们就能够创建 Apple 对象了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">createApple</span> </span>{</span><br><span class="line"></span><br><span 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>{</span><br><span class="line"> Apple apple1 = <span class="keyword">new</span> Apple();</span><br><span class="line"> Apple apple2 = <span class="keyword">new</span> Apple(<span class="number">1</span>);</span><br><span class="line"> Apple apple3 = <span class="keyword">new</span> Apple(<span class="string">"red"</span>);</span><br><span class="line"> Apple apple4 = <span class="keyword">new</span> Apple(<span class="number">2</span>,<span class="string">"color"</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如上面所示,我们定义了四个 Apple 对象,并调用了 Apple 的四种不同的构造方法,其中,不加任何参数的构造方法被称为默认的构造方法,也就是</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Apple apple1 = <span class="keyword">new</span> Apple();</span><br></pre></td></tr></table></figure>
<p>如果类中没有定义任何构造方法,那么 JVM 会为你自动生成一个构造方法,如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> sum;</span><br><span class="line"> String color;</span><br><span class="line"> </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">createApple</span> </span>{</span><br><span class="line"></span><br><span 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>{</span><br><span class="line"> Apple apple1 = <span class="keyword">new</span> Apple();</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上面代码不会发生编译错误,因为 Apple 对象包含了一个默认的构造方法。</p>
<p>默认的构造方法也被称为默认构造器或者无参构造器。</p>
<p>这里需要注意一点的是,即使 JVM 会为你默认添加一个无参的构造器,但是如果你手动定义了任何一个构造方法,<strong>JVM 就不再为你提供默认的构造器,你必须手动指定,否则会出现编译错误</strong>。</p>
<img src="https://s1.ax1x.com/2020/05/08/YKwbnO.png" alt="YKwbnO.png" style="zoom:50%;" />
<p>显示的错误是,必须提供 Apple 带有 int 参数的构造函数,而默认的无参构造函数没有被允许使用。</p>
<h4 id="方法重载"><a href="#方法重载" class="headerlink" title="方法重载"></a>方法重载</h4><p>在 Java 中一个很重要的概念是方法的重载,它是类名的不同表现形式。我们上面说到了构造函数,其实构造函数也是重载的一种。另外一种就是方法的重载</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> sum;</span><br><span class="line"> String color;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">()</span></span>{}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(<span class="keyword">int</span> sum)</span></span>{}</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getApple</span><span class="params">(<span class="keyword">int</span> num)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getApple</span><span class="params">(String color)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"color"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如上面所示,就有两种重载的方式,一种是 Apple 构造函数的重载,一种是 getApple 方法的重载。</p>
<p>但是这样就涉及到一个问题,要是有几个相同的名字,Java 如何知道你调用的是哪个方法呢?这里记住一点即可,<strong>每个重载的方法都有独一无二的参数列表</strong>。其中包括参数的类型、顺序、参数数量等,满足一种一个因素就构成了重载的必要条件。</p>
<p>请记住下面重载的条件</p>
<ul>
<li><p>方法名称必须相同。</p>
</li>
<li><p>参数列表必须不同(个数不同、或类型不同、参数类型排列顺序不同等)。</p>
</li>
<li><p>方法的返回类型可以相同也可以不相同。</p>
</li>
<li><p>仅仅返回类型不同不足以成为方法的重载。</p>
</li>
<li><p>重载是发生在编译时的,因为编译器可以根据参数的类型来选择使用哪个方法。</p>
</li>
</ul>
<h4 id="方法的重写"><a href="#方法的重写" class="headerlink" title="方法的重写"></a>方法的重写</h4><p>方法的重写与重载虽然名字很相似,但却完全是不同的东西。方法重写的描述是对<code>子类和父类</code>之间的。而重载指的是同一类中的。例如如下代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Fruit</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.printl(<span class="string">'eat fruit'</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Apple</span> <span class="keyword">extends</span> <span class="title">Fruit</span></span>{</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.printl(<span class="string">'eat apple'</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上面这段代码描述的就是重写的代码,你可以看到,子类 Apple 中的方法和父类 Fruit 中的方法同名,所以,我们能够推断出重写的原则</p>
<ul>
<li>重写的方法必须要和父类保持一致,包括<strong>返回值类型,方法名,参数列表</strong> 也都一样。</li>
<li>重写的方法可以使用 <code>@Override</code> 注解来标识</li>
<li>子类中重写方法的访问权限不能低于父类中方法的访问权限。</li>
</ul>
<h3 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h3><h4 id="类的初始化"><a href="#类的初始化" class="headerlink" title="类的初始化"></a>类的初始化</h4><p>上面我们创建出来了一个 Car 这个对象,其实在使用 new 关键字创建一个对象的时候,其实是调用了这个对象无参数的构造方法进行的初始化,也就是如下这段代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Car</span><span class="params">()</span></span>{}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这个无参数的构造函数可以隐藏,由 JVM 自动添加。也就是说,构造函数能够确保类的初始化。</p>
<h4 id="成员初始化"><a href="#成员初始化" class="headerlink" title="成员初始化"></a>成员初始化</h4><p>Java 会尽量保证每个变量在使用前都会获得初始化,初始化涉及两种初始化。</p>
<ul>
<li><p>一种是编译器默认指定的字段初始化,基本数据类型的初始化</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKw7jK.png" alt="YKw7jK.png"></p>
<p>一种是其他对象类型的初始化,String 也是一种对象,对象的初始值都为 <code>null</code> ,其中也包括基本类型的包装类。</p>
</li>
<li><p>一种是指定数值的初始化,例如</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> a = <span class="number">11</span></span><br></pre></td></tr></table></figure>
<p>也就是说, 指定 a 的初始化值不是 0 ,而是 11。其他基本类型和对象类型也是一样的。</p>
<h4 id="构造器初始化"><a href="#构造器初始化" class="headerlink" title="构造器初始化"></a>构造器初始化</h4><p>可以利用构造器来对某些方法和某些动作进行初始化,确定初始值,例如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Counter</span></span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Counter</span><span class="params">()</span></span>{</span><br><span class="line"> i = <span class="number">11</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>利用构造函数,能够把 i 的值初始化为 11。</p>
<h4 id="初始化顺序"><a href="#初始化顺序" class="headerlink" title="初始化顺序"></a>初始化顺序</h4><p>首先先来看一下有哪些需要探讨的初始化顺序</p>
<ul>
<li><p>静态属性:static 开头定义的属性</p>
</li>
<li><p>静态方法块: static {} 包起来的代码块</p>
</li>
<li><p>普通属性: 非 static 定义的属性</p>
</li>
<li><p>普通方法块: {} 包起来的代码块</p>
</li>
<li><p>构造函数: 类名相同的方法</p>
</li>
<li><p>方法: 普通方法</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LifeCycle</span> </span>{</span><br><span class="line"> <span class="comment">// 静态属性</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> String staticField = getStaticField();</span><br><span class="line"> <span class="comment">// 静态方法块</span></span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> System.out.println(staticField);</span><br><span class="line"> System.out.println(<span class="string">"静态方法块初始化"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 普通属性</span></span><br><span class="line"> <span class="keyword">private</span> String field = getField();</span><br><span class="line"> <span class="comment">// 普通方法块</span></span><br><span class="line"> {</span><br><span class="line"> System.out.println(field);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 构造函数</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">LifeCycle</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"构造函数初始化"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">getStaticField</span><span class="params">()</span> </span>{</span><br><span class="line"> String statiFiled = <span class="string">"Static Field Initial"</span>;</span><br><span class="line"> <span class="keyword">return</span> statiFiled;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">getField</span><span class="params">()</span> </span>{</span><br><span class="line"> String filed = <span class="string">"Field Initial"</span>;</span><br><span class="line"> <span class="keyword">return</span> filed;</span><br><span class="line"> } </span><br><span class="line"> <span class="comment">// 主函数</span></span><br><span 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[] argc)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> LifeCycle();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这段代码的执行结果就反应了它的初始化顺序</p>
<p>静态属性初始化<br>静态方法块初始化<br>普通属性初始化<br>普通方法块初始化<br>构造函数初始化</p>
<h4 id="数组初始化"><a href="#数组初始化" class="headerlink" title="数组初始化"></a>数组初始化</h4><p>数组是相同类型的、用一个标识符名称封装到一起的一个对象序列或基本类型数据序列。数组是通过方括号下标操作符 <code>[]</code> 来定义使用。</p>
<p>一般数组是这么定义的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span>[] a1;</span><br><span class="line"></span><br><span class="line"><span class="comment">//或者</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> a1[];</span><br></pre></td></tr></table></figure>
<p>两种格式的含义是一样的。</p>
<ul>
<li>直接给每个元素赋值 : int array[4] = {1,2,3,4};</li>
<li>给一部分赋值,后面的都为 0 : int array[4] = {1,2};</li>
<li>由赋值参数个数决定数组的个数 : int array[] = {1,2};</li>
</ul>
<p><strong>可变参数列表</strong></p>
<p>Java 中一种数组冷门的用法就是<code>可变参数</code> ,可变参数的定义如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span>... numbers)</span></span>{</span><br><span class="line"> <span class="keyword">int</span> sum = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> num : numbers){</span><br><span class="line"> sum += num;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> sum;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>然后,你可以使用下面这几种方式进行可变参数的调用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">add(); <span class="comment">// 不传参数</span></span><br><span class="line">add(<span class="number">1</span>); <span class="comment">// 传递一个参数</span></span><br><span class="line">add(<span class="number">2</span>,<span class="number">1</span>); <span class="comment">// 传递多个参数</span></span><br><span class="line">add(<span class="keyword">new</span> Integer[] {<span class="number">1</span>, <span class="number">3</span>, <span class="number">2</span>}); <span class="comment">// 传递数组</span></span><br></pre></td></tr></table></figure>
<h3 id="对象的销毁"><a href="#对象的销毁" class="headerlink" title="对象的销毁"></a>对象的销毁</h3><p>虽然 Java 语言是基于 C++ 的,但是它和 C/C++ 一个重要的特征就是不需要手动管理对象的销毁工作。在著名的一书 《深入理解 Java 虚拟机》中提到一个观点</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwqBD.png" alt="YKwqBD.png"></p>
<p>在 Java 中,我们不再需要手动管理对象的销毁,它是由 <code>Java 虚拟机</code>进行管理和销毁的。虽然我们不需要手动管理对象,但是你需要知道 <code>对象作用域</code> 这个概念。</p>
<h4 id="对象作用域"><a href="#对象作用域" class="headerlink" title="对象作用域"></a>对象作用域</h4><p>J多数语言都有<code>作用域(scope)</code> 这个概念。作用域决定了其内部定义的变量名的可见性和生命周期。在 C、C++ 和 Java 中,作用域通常由 <code>{}</code> 的位置来决定,例如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="keyword">int</span> a = <span class="number">11</span>;</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> b = <span class="number">12</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>a 变量会在两个 <code>{}</code> 作用域内有效,而 b 变量的值只能在它自己的 <code>{}</code> 内有效。</p>
<p>虽然存在作用域,但是不允许这样写</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="keyword">int</span> x = <span class="number">11</span>;</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = <span class="number">12</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这种写法在 C/C++ 中是可以的,但是在 Java 中不允许这样写,因为 Java 设计者认为这样写会导致程序混乱。</p>
<p>###this 和 super</p>
<p>this 和 super 都是 Java 中的关键字</p>
<p>this 表示的当前对象,this 可以调用方法、调用属性和指向对象本身。this 在 Java 中的使用一般有三种:指向当前对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">Apple <span class="title">eatApple</span><span class="params">()</span></span>{</span><br><span class="line"> i++;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span 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>{</span><br><span class="line"> Apple apple = <span class="keyword">new</span> Apple();</span><br><span class="line"> apple.eatApple().eatApple();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这段代码比较精妙,精妙在哪呢,我一个 eatApple() 方法竟然可以调用多次,你在后面还可以继续调用,这就很神奇了,为啥呢?其实就是 this 在作祟了,我在 <code>eatApple</code> 方法中加了一个 <code>return this</code> 的返回值,也就是说哪个对象调用 eatApple 方法都能返回对象的自身。</p>
<p>this 还可以修饰属性,最常见的就是在构造方法中使用 this ,如下所示</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> num;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(<span class="keyword">int</span> num)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>.num = num;</span><br><span class="line"> }</span><br><span class="line"></span><br><span 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>{</span><br><span class="line"> <span class="keyword">new</span> Apple(<span class="number">10</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>main 方法中传递了一个 int 值为 10 的参数,它表示的就是苹果的数量,并把这个数量赋给了 num 全局变量。所以 num 的值现在就是 10。</p>
<p>this 还可以和构造函数一起使用,充当一个全局关键字的效果</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> num;</span><br><span class="line"> <span class="keyword">private</span> String color;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(<span class="keyword">int</span> num)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>(num,<span class="string">"红色"</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(String color)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>(<span class="number">1</span>,color);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(<span class="keyword">int</span> num, String color)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.num = num;</span><br><span class="line"> <span class="keyword">this</span>.color = color;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>你会发现上面这段代码使用的不是 this, 而是 <code>this(参数)</code>。它相当于调用了其他构造方法,然后传递参数进去。这里注意一点:this() 必须放在构造方法的第一行,否则编译不通过</p>
<img src="https://s1.ax1x.com/2020/05/08/YKwLHe.png" alt="YKwLHe.png" style="zoom:50%;" />
<p>如果你把 this 理解为指向自身的一个引用,那么 super 就是指向父类的一个引用。super 关键字和 this 一样,你可以使用 <code>super.对象</code> 来引用父类的成员,如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Fruit</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> num;</span><br><span class="line"> String color;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"eat Fruit"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Apple</span> <span class="keyword">extends</span> <span class="title">Fruit</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.num = <span class="number">10</span>;</span><br><span class="line"> System.out.println(<span class="string">"eat "</span> + num + <span class="string">" Apple"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>你也可以使用 <code>super(参数)</code> 来调用父类的构造函数,这里不再举例子了。</p>
<p>下面为你汇总了 this 关键字和 super 关键字的比较。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwXAH.png" alt="YKwXAH.png"></p>
<h2 id="访问控制权限"><a href="#访问控制权限" class="headerlink" title="访问控制权限"></a>访问控制权限</h2><p>访问控制权限又称为<code>封装</code>,它是面向对象三大特性中的一种,我之前在学习过程中经常会忽略封装,心想这不就是一个访问修饰符么,怎么就是三大特性的必要条件了?后来我才知道,<strong>如果你信任的下属对你隐瞒 bug,你是根本不知道的</strong>。</p>
<p>访问控制权限其实最核心就是一点:只对需要的类可见。</p>
<p>Java中成员的访问权限共有四种,分别是 <strong>public、protected、default、private</strong>,它们的可见性如下</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwjNd.png" alt="YKwjNd.png"></p>
<h3 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h3><p>继承是所有 <code>OOP(Object Oriented Programming)</code> 语言和 Java 语言都不可或缺的一部分。只要我们创建了一个类,就隐式的继承自 <code>Object</code> 父类,只不过没有指定。如果你显示指定了父类,那么你继承于父类,而你的父类继承于 Object 类。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKw6XT.png" alt="YKw6XT.png"></p>
<p>继承的关键字是 <code>extends</code> ,如上图所示,如果使用了 extends 显示指定了继承,那么我们可以说 Father 是父类,而 Son 是子类,用代码表示如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Father</span></span>{}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Father</span></span>{}</span><br></pre></td></tr></table></figure>
<p>继承双方拥有某种共性的特征</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Father</span></span>{</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">feature</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"父亲的特征"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Father</span> </span>{</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果 Son 没有实现自己的方法的话,那么默认就是用的是父类的 <code>feature</code> 方法。如果子类实现了自己的 feature 方法,那么就相当于是重写了父类的 feature 方法,这也是我们上面提到的重写了。</p>
<h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>多态指的是同一个行为具有多个不同表现形式。是指一个类实例(对象)的相同方法在不同情形下具有不同表现形式。封装和继承是多态的基础,也就是说,多态只是一种表现形式而已。</p>
<p>如何实现多态?多态的实现具有三种充要条件</p>
<ul>
<li>继承</li>
<li>重写父类方法</li>
<li>父类引用指向子类对象</li>
</ul>
<p>比如下面这段代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Fruit</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> num;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"eat Fruit"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Apple</span> <span class="keyword">extends</span> <span class="title">Fruit</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">eat</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.num = <span class="number">10</span>;</span><br><span class="line"> System.out.println(<span class="string">"eat "</span> + num + <span class="string">" Apple"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span 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>{</span><br><span class="line"> Fruit fruit = <span class="keyword">new</span> Apple();</span><br><span class="line"> fruit.eat();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>你可以发现 <code>main</code> 方法中有一个很神奇的地方,<code>Fruit fruit = new Apple()</code>,Fruit 类型的对象竟然指向了 Apple 对象的引用,这其实就是多态 -> 父类引用指向子类对象,因为 Apple 继承于 Fruit,并且重写了 eat 方法,所以能够表现出来多种状态的形式。</p>
<h3 id="组合"><a href="#组合" class="headerlink" title="组合"></a>组合</h3><p>组合其实不难理解,就是将对象引用置于新类中即可。组合也是一种提高类的复用性的一种方式。如果你想让类具有更多的扩展功能,你需要记住一句话<strong>多用组合,少用继承</strong>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SoccerPlayer</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> Soccer soccer;</span><br><span class="line"> </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Soccer</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> String soccerName; </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>代码中 SoccerPlayer 引用了 Soccer 类,通过引用 Soccer 类,来达到调用 soccer 中的属性和方法。</p>
<p>组合和继承是有区别的,它们的主要区别如下。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwv4A.png" alt="YKwv4A.png"></p>
<p>关于继承和组合孰优孰劣的争论没有结果,只要发挥各自的长处和优点即可,一般情况下,组合和继承也是一对可以连用的好兄弟。</p>
<h3 id="代理"><a href="#代理" class="headerlink" title="代理"></a>代理</h3><p>除了继承和组合外,另外一种值得探讨的关系模型称为 <code>代理</code>。代理的大致描述是,A 想要调用 B 类的方法,A 不直接调用,A 会在自己的类中创建一个 B 对象的代理,再由代理调用 B 的方法。例如如下代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Destination</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">todo</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"control..."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Device</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> Destination destination;</span><br><span class="line"> <span class="keyword">private</span> DeviceController deviceController;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">control</span><span class="params">(Destination destination)</span></span>{</span><br><span class="line"> destination.todo();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeviceController</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Device name;</span><br><span class="line"> <span class="keyword">private</span> Destination destination;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">control</span><span class="params">(Destination destination)</span></span>{</span><br><span class="line"> destination.todo();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="向上转型"><a href="#向上转型" class="headerlink" title="向上转型"></a>向上转型</h3><p>向上转型代表了父类与子类之间的关系,其实父类和子类之间不仅仅有向上转型,还有向下转型,它们的转型后的范围不一样</p>
<ul>
<li><code>向上转型</code>:通过子类对象(小范围)转化为父类对象(大范围),这种转换是自动完成的,不用强制。</li>
<li><code>向下转型</code> : 通过父类对象(大范围)实例化子类对象(小范围),这种转换不是自动完成的,需要强制指定。</li>
</ul>
<h3 id="static"><a href="#static" class="headerlink" title="static"></a>static</h3><p>static 是 Java 中的关键字,它的意思是 <code>静态的</code>,static 可以用来修饰成员变量和方法,static 用在没有创建对象的情况下调用 方法/变量。</p>
<ul>
<li>用 static 声明的成员变量为静态成员变量,也成为类变量。类变量的生命周期和类相同,在整个应用程序执行期间都有效。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> String name = <span class="string">"cxuan"</span>;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用 static 修饰的方法称为静态方法,静态方法能够直接使用<strong>类名.方法名</strong> 进行调用。由于静态方法不依赖于任何对象就可以直接访问,因此对于静态方法来说,是没有 this 关键字的,实例变量都会有 this 关键字。在静态方法中不能访问类的非静态成员变量和非静态方法,</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printMessage</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"cxuan is writing the article"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>static 除了修饰属性和方法外,还有<code>静态代码块</code> 的功能,可用于类的初始化操作。进而提升程序的性能。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StaicBlock</span> </span>{</span><br><span class="line"> <span class="keyword">static</span>{</span><br><span class="line"> System.out.println(<span class="string">"I'm A static code block"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>由于静态代码块随着类的加载而执行,因此,很多时候会将只需要进行一次的初始化操作放在 static 代码块中进行。</p>
<h3 id="final"><a href="#final" class="headerlink" title="final"></a>final</h3><p>final 的意思是最后的、最终的,它可以修饰类、属性和方法。</p>
<ul>
<li>final 修饰类时,表明这个类不能被继承。final 类中的成员变量可以根据需要设为 final,但是要注意 final 类中的所有成员方法都会被隐式地指定为 final 方法。</li>
<li>final 修饰方法时,表明这个方法不能被任何子类重写,因此,如果只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为 final。</li>
<li>final 修饰变量分为两种情况,一种是修饰基本数据类型,表示数据类型的值不能被修改;一种是修饰引用类型,表示对其初始化之后便不能再让其指向另一个对象。</li>
</ul>
<h2 id="接口和抽象类"><a href="#接口和抽象类" class="headerlink" title="接口和抽象类"></a>接口和抽象类</h2><h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><p>接口相当于就是对外的一种约定和标准,这里拿操作系统举例子,为什么会有操作系统?就会为了屏蔽软件的复杂性和硬件的简单性之间的差异,为软件提供统一的标准。</p>
<p>在 Java 语言中,接口是由 <code>interface</code> 关键字来表示的,比如我们可以向下面这样定义一个接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CxuanGoodJob</span> </span>{}</span><br></pre></td></tr></table></figure>
<p>比如我们定义了一个 CxuanGoodJob 的接口,然后你就可以在其内部定义 cxuan 做的好的那些事情,比如 cxuan 写的文章不错。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CxuanGoodJob</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">writeWell</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这里隐含了一些接口的特征:</p>
<ul>
<li><code>interface</code> 接口是一个完全抽象的类,他不会提供任何方法的实现,只是会进行方法的定义。</li>
<li>接口中只能使用两种访问修饰符,一种是 <code>public</code>,它对整个项目可见;一种是 <code>default</code> 缺省值,它只具有包访问权限。</li>
<li>接口只提供方法的定义,接口没有实现,但是接口可以被其他类实现。也就是说,实现接口的类需要提供方法的实现,实现接口使用 <code>implements</code> 关键字来表示,一个接口可以有多个实现。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CXuanWriteWell</span> <span class="keyword">implements</span> <span class="title">CxuanGoodJob</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">writeWell</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"Cxuan write Java is vary well"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>接口不能被实例化,所以接口中不能有任何构造方法,你定义构造方法编译会出错。</li>
<li>接口的实现比如实现接口的全部方法,否则必须定义为<code>抽象类</code>,这就是我们下面要说的内容</li>
</ul>
<h3 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h3><p>抽象类是一种抽象能力弱于接口的类,在 Java 中,抽象类使用 <code>abstract</code> 关键字来表示。如果把接口形容为狗这个物种,那么抽象类可以说是毛发是白色、小体的品种,而实现类可以是具体的类,比如说是博美、泰迪等。你可以像下面这样定义抽象类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Dog</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">FurColor</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">WhiteDog</span> <span class="keyword">implements</span> <span class="title">Dog</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">FurColor</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"Fur is white"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">SmallBody</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在抽象类中,具有如下特征</p>
<ul>
<li><p>如果一个类中有抽象方法,那么这个类一定是抽象类,也就是说,使用关键字 <code>abstract</code> 修饰的方法一定是抽象方法,具有抽象方法的类一定是抽象类。实现类方法中只有方法具体的实现。</p>
</li>
<li><p>抽象类中不一定只有抽象方法,抽象类中也可以有具体的方法,你可以自己去选择是否实现这些方法。</p>
</li>
<li><p>抽象类中的约束不像接口那么严格,你可以在抽象类中定义 <strong>构造方法、抽象方法、普通属性、方法、静态属性和静态方法</strong></p>
</li>
<li><p>抽象类和接口一样不能被实例化,实例化只能实例化<code>具体的类</code></p>
</li>
</ul>
<h2 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h2><p>异常是程序经常会出现的,发现错误的最佳时机是在编译阶段,也就是你试图在运行程序之前。但是,在编译期间并不能找到所有的错误,有一些 <code>NullPointerException</code> 和 <code>ClassNotFoundException</code> 异常在编译期找不到,这些异常是 RuntimeException 运行时异常,这些异常往往在运行时才能被发现。</p>
<p>我们写 Java 程序经常会出现两种问题,一种是 java.lang.Exception ,一种是 java.lang.Error,都用来表示出现了异常情况,下面就针对这两种概念进行理解。</p>
<h3 id="认识-Exception"><a href="#认识-Exception" class="headerlink" title="认识 Exception"></a>认识 Exception</h3><p><code>Exception</code> 位于 <code>java.lang</code> 包下,它是一种顶级接口,继承于 <code>Throwable</code> 类,Exception 类及其子类都是 Throwable 的组成条件,是程序出现的合理情况。</p>
<p>在认识 Exception 之前,有必要先了解一下什么是 <code>Throwable</code>。</p>
<h3 id="什么是-Throwable"><a href="#什么是-Throwable" class="headerlink" title="什么是 Throwable"></a>什么是 Throwable</h3><p>Throwable 类是 Java 语言中所有<code>错误(errors)</code>和<code>异常(exceptions)</code>的父类。只有继承于 Throwable 的类或者其子类才能够被抛出,还有一种方式是带有 Java 中的 <code>@throw</code> 注解的类也可以抛出。</p>
<p>在<a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-11.html#jls-11.1.1" target="_blank" rel="noopener">Java规范</a>中,对非受查异常和受查异常的定义是这样的:</p>
<blockquote>
<p>The <em>unchecked exception classes</em> are the run-time exception classes and the error classes.</p>
</blockquote>
<blockquote>
<p>The <em>checked exception classes</em> are all exception classes other than the unchecked exception classes. That is, the checked exception classes are <code>Throwable</code> and all its subclasses other than <code>RuntimeException</code> and its subclasses and <code>Error</code>and its subclasses.</p>
</blockquote>
<p>也就是说,除了 <code>RuntimeException</code> 和其子类,以及<code>error</code>和其子类,其它的所有异常都是 <code>checkedException</code>。</p>
<p>那么,按照这种逻辑关系,我们可以对 Throwable 及其子类进行归类分析</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YKwz9I.png" alt="YKwz9I.png"></p>
<p>可以看到,Throwable 位于异常和错误的最顶层,我们查看 Throwable 类中发现它的方法和属性有很多,我们只讨论其中几个比较常用的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 返回抛出异常的详细信息</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> string <span class="title">getMessage</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> string <span class="title">getLocalizedMessage</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//返回异常发生时的简要描述</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span>;</span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="comment">// 打印异常信息到标准输出流上</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">printStackTrace</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">printStackTrace</span><span class="params">(PrintStream s)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">printStackTrace</span><span class="params">(PrintWriter s)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="comment">// 记录栈帧的的当前状态</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> Throwable <span class="title">fillInStackTrace</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<p>此外,因为 Throwable 的父类也是 <code>Object</code>,所以常用的方法还有继承其父类的<code>getClass()</code> 和 <code>getName()</code> 方法。</p>
<h3 id="常见的-Exception"><a href="#常见的-Exception" class="headerlink" title="常见的 Exception"></a>常见的 Exception</h3><p>下面我们回到 Exception 的探讨上来,现在你知道了 Exception 的父类是 Throwable,并且 Exception 有两种异常,一种是 <code>RuntimeException</code> ;一种是 <code>CheckedException</code>,这两种异常都应该去<code>捕获</code>。</p>
<p>下面列出了一些 Java 中常见的异常及其分类,这块面试官也可能让你举出几个常见的异常情况并将其分类</p>
<p>RuntimeException</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YK0S3t.png" alt="YK0S3t.png"></p>
<p>CheckedException</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YK0pgP.png" alt="YK0pgP.png"></p>
<h3 id="与-Exception-有关的-Java-关键字"><a href="#与-Exception-有关的-Java-关键字" class="headerlink" title="与 Exception 有关的 Java 关键字"></a>与 Exception 有关的 Java 关键字</h3><p>那么 Java 中是如何处理这些异常的呢?在 Java 中有这几个关键字 <strong>throws、throw、try、finally、catch</strong> 下面我们分别来探讨一下</p>
<h4 id="throws-和-throw"><a href="#throws-和-throw" class="headerlink" title="throws 和 throw"></a>throws 和 throw</h4><p>在 Java 中,异常也就是一个对象,它能够被程序员自定义抛出或者应用程序抛出,必须借助于 <code>throws</code> 和 <code>throw</code> 语句来定义抛出异常。</p>
<p>throws 和 throw 通常是成对出现的,例如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">cacheException</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Exception();</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。<br>throws 语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。</p>
<p>throws 主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。<br>throw 是具体向外抛异常的动作,所以它是抛出一个异常实例。</p>
<h4 id="try-、finally-、catch"><a href="#try-、finally-、catch" class="headerlink" title="try 、finally 、catch"></a>try 、finally 、catch</h4><p>这三个关键字主要有下面几种组合方式 <strong>try…catch 、try…finally、try…catch…finally</strong>。</p>
<p>try…catch 表示对某一段代码可能抛出异常进行的捕获,如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">cacheException</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.out.println(<span class="string">"1"</span>);</span><br><span class="line"> }<span class="keyword">catch</span> (Exception e){</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>try…finally 表示对一段代码不管执行情况如何,都会走 finally 中的代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">cacheException</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"enter: i="</span> + i);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.out.println(<span class="string">"execute: i="</span> + i);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> System.out.println(<span class="string">"leave: i="</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>try…catch…finally 也是一样的,表示对异常捕获后,再走 finally 中的代码逻辑。</p>
<h3 id="什么是-Error"><a href="#什么是-Error" class="headerlink" title="什么是 Error"></a>什么是 Error</h3><p>Error 是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。这些错误是不可检查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况,比如 <code>OutOfMemoryError</code> 和 <code>StackOverflowError</code>异常的出现会有几种情况,这里需要先介绍一下 Java 内存模型 JDK1.7。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YK09jf.png" alt="YK09jf.png"></p>
<p>其中包括两部分,<strong>由所有线程共享的数据区和线程隔离的数据区</strong>组成,在上面的 Java 内存模型中,<strong>只有程序计数器</strong>是不会发生 <code>OutOfMemoryError</code> 情况的区域,程序计数器控制着计算机指令的分支、循环、跳转、异常处理和线程恢复,并且程序计数器是每个线程私有的。</p>
<blockquote>
<p>什么是线程私有:表示的就是各条线程之间互不影响,独立存储的内存区域。</p>
</blockquote>
<p>如果应用程序执行的是 Java 方法,那么这个计数器记录的就是<code>虚拟机字节码</code>指令的地址;如果正在执行的是 <code>Native</code> 方法,这个计数器值则为<code>空(Undefined)</code>。</p>
<p>除了程序计数器外,其他区域:<code>方法区(Method Area)</code>、<code>虚拟机栈(VM Stack)</code>、<code>本地方法栈(Native Method Stack)</code> 和 <code>堆(Heap)</code> 都是可能发生 OutOfMemoryError 的区域。</p>
<ul>
<li><p>虚拟机栈:如果线程请求的栈深度大于虚拟机栈所允许的深度,将会出现 <code>StackOverflowError</code> 异常;如果虚拟机动态扩展无法申请到足够的内存,将出现 <code>OutOfMemoryError</code>。</p>
</li>
<li><p>本地方法栈和虚拟机栈一样</p>
</li>
<li><p>堆:Java 堆可以处于物理上不连续,逻辑上连续,就像我们的磁盘空间一样,如果堆中没有内存完成实例分配,并且堆无法扩展时,将会抛出 OutOfMemoryError。</p>
</li>
<li><p>方法区:方法区无法满足内存分配需求时,将抛出 OutOfMemoryError 异常。</p>
</li>
</ul>
<p>在 Java 中,你可以把异常理解为是一种能够提高你程序健壮性的机制,它能够让你在编写代码中注意这些问题,也可以说,如果你写代码不会注意这些异常情况,你是无法成为一位硬核程序员的。</p>
<h2 id="内部类"><a href="#内部类" class="headerlink" title="内部类"></a>内部类</h2><p>距今为止,我们了解的都是普通类的定义,那就是直接在 IDEA 中直接新建一个 class 。</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YK0Pu8.png" alt="YK0Pu8.png"></p>
<p>新建完成后,你就会拥有一个 class 文件的定义,这种操作太简单了,时间长了就会枯燥,我们年轻人多需要更新潮和骚气的写法,好吧,既然你提到了那就使用 <code>内部类</code>吧,这是一种有用而且骚气的定义类的方式,内部类的定义非常简单:<strong>可以将一个类的定义放在另一个类的内部,这就是内部类</strong>。</p>
<p>内部类是一种非常有用的特性,定义在类内部的类,持有外部类的引用,但却对其他外部类不可见,看起来就像是一种隐藏代码的机制,就和 <code>弗兰奇将军</code> 似的,弗兰奇可以和弗兰奇将军进行通讯,但是外面的敌人却无法直接攻击到弗兰奇本体。</p>
<img src="https://s1.ax1x.com/2020/05/08/YK0iDS.png" alt="YK0iDS.png" style="zoom:50%;" />
<p>下面我们就来聊一聊创建内部类的方式。</p>
<h3 id="创建内部类"><a href="#创建内部类" class="headerlink" title="创建内部类"></a>创建内部类</h3><p>定义内部类非常简单,就是直接将一个类定义在外围类的里面,如下代码所示</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OuterClass</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String name ;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"> </span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">InnerClass</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">InnerClass</span><span class="params">()</span></span>{</span><br><span class="line"> name = <span class="string">"cxuan"</span>;</span><br><span class="line"> age = <span class="number">25</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在这段代码中,InnerClass 就是 OuterClass 的一个内部类。也就是说,每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。这也是隐藏了内部实现细节。<strong>内部类拥有外部类的访问权</strong>。</p>
<p>内部类不仅仅能够定义在类的内部,还可以定义在方法和作用域内部,这种被称为<code>局部内部类</code>,除此之外,还有匿名内部类、内部类可以实现 Java 中的 <code>多重继承</code>。下面是定义内部类的方式</p>
<ul>
<li>一个在方法中定义的类(局部内部类)</li>
<li>一个定义在作用域内的类,这个作用域在方法的内部(成员内部类)</li>
<li>一个实现了接口的匿名类(匿名内部类)</li>
<li>一个匿名类,它扩展了非默认构造器的类</li>
<li>一个匿名类,执行字段初始化操作</li>
<li>一个匿名类,它通过实例初始化实现构造</li>
</ul>
<p>由于每个类都会产生一个 <code>.class</code> 文件,其中包含了如何创建该类型的对象的全部信息,那么,如何表示内部类的信息呢?可以使用 <code>$</code> 来表示,比如 <strong>OuterClass$InnerClass.class</strong>。</p>
<h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><p>集合在我们的日常开发中所使用的次数简直太多了,你已经把它们都用的熟透了,但是作为一名合格的程序员,你不仅要了解它的基本用法,你还要了解它的源码;存在即合理,你还要了解它是如何设计和实现的,你还要了解它的衍生过程。</p>
<p>这篇博客就来详细介绍一下 Collection 这个庞大集合框架的家族体系和成员,让你了解它的设计与实现。</p>
<p><strong>是时候祭出这张神图了</strong></p>
<p><img src="https://s1.ax1x.com/2020/05/08/YK0AEQ.png" alt="YK0AEQ.png"></p>
<p>首先来介绍的就是列表爷爷辈儿的接口- <strong>Iterator</strong></p>
<h3 id="Iterable-接口"><a href="#Iterable-接口" class="headerlink" title="Iterable 接口"></a>Iterable 接口</h3><p>实现此接口允许对象成为 for-each 循环的目标,也就是增强 for 循环,它是 Java 中的一种<code>语法糖</code>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">List<Object> list = <span class="keyword">new</span> ArrayList();</span><br><span class="line"><span class="keyword">for</span> (Object obj: list){}</span><br></pre></td></tr></table></figure>
<p>除了实现此接口的对象外,数组也可以用 for-each 循环遍历,如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Object[] list = <span class="keyword">new</span> Object[<span class="number">10</span>];</span><br><span class="line"><span class="keyword">for</span> (Object obj: list){}</span><br></pre></td></tr></table></figure>
<p><strong>其他遍历方式</strong></p>
<p>jdk 1.8之前<code>Iterator</code>只有 iterator 一个方法,就是</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">Iterator<T> <span class="title">iterator</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<p>实现次接口的方法能够创建一个轻量级的迭代器,用于安全的遍历元素,移除元素,添加元素。这里面涉及到一个 <code>fail-fast</code> 机制。</p>
<p>总之一点就是能创建迭代器进行元素的添加和删除的话,就尽量使用迭代器进行添加和删除。 </p>
<p>也可以使用迭代器的方式进行遍历</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(Iterator it = coll.iterator(); it.hasNext(); ){</span><br><span class="line"> System.out.println(it.next());</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="顶层接口"><a href="#顶层接口" class="headerlink" title="顶层接口"></a>顶层接口</h3><p>Collection 是一个顶层接口,它主要用来定义集合的约定</p>
<p>List 接口也是一个顶层接口,它继承了 Collection 接口 ,同时也是 ArrayList、LinkedList 等集合元素的父类</p>
<p>Set 接口位于与 List 接口同级的层次上,它同时也继承了 Collection 接口。Set 接口提供了额外的规定。它对add、equals、hashCode 方法提供了额外的标准。</p>
<p>Queue 是和 List、Set 接口并列的 Collection 的三大接口之一。Queue 的设计用来在处理之前保持元素的访问次序。除了 Collection 基础的操作之外,队列提供了额外的插入,读取,检查操作。</p>
<p>SortedSet 接口直接继承于 Set 接口,使用 Comparable 对元素进行自然排序或者使用 Comparator 在创建时对元素提供定制的排序规则。set 的迭代器将按升序元素顺序遍历集合。</p>
<p>Map 是一个支持 key-value 存储的对象,Map 不能包含重复的 key,每个键最多映射一个值。这个接口代替了Dictionary 类,Dictionary 是一个抽象类而不是接口。</p>
<h4 id="ArrayList"><a href="#ArrayList" class="headerlink" title="ArrayList"></a>ArrayList</h4><p>ArrayList 是实现了 List 接口的<code>可扩容数组(动态数组)</code>,它的内部是基于数组实现的。它的具体定义如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ArrayList</span><<span class="title">E</span>> <span class="keyword">extends</span> <span class="title">AbstractList</span><<span class="title">E</span>> <span class="keyword">implements</span> <span class="title">List</span><<span class="title">E</span>>, <span class="title">RandomAccess</span>, <span class="title">Cloneable</span>, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span> </span>{...}</span><br></pre></td></tr></table></figure>
<ul>
<li>ArrayList 可以实现所有可选择的列表操作,允许所有的元素,包括空值。ArrayList 还提供了内部存储 list 的方法,它能够完全替代 Vector,只有一点例外,ArrayList 不是线程安全的容器。</li>
<li>ArrayList 有一个容量的概念,这个数组的容量就是 List 用来存储元素的容量。</li>
<li>ArrayList 不是线程安全的容器,如果多个线程中至少有两个线程修改了 ArrayList 的结构的话就会导致线程安全问题,作为替代条件可以使用线程安全的 List,应使用 <code>Collections.synchronizedList</code> 。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List list = Collections.synchronizedList(<span class="keyword">new</span> ArrayList(...))</span><br></pre></td></tr></table></figure>
<ul>
<li>ArrayList 具有 fail-fast 快速失败机制,能够对 ArrayList 作出失败检测。当在迭代集合的过程中该集合在结构上发生改变的时候,就有可能会发生 fail-fast,即抛出 <code>ConcurrentModificationException</code>异常。</li>
</ul>
<h4 id="Vector"><a href="#Vector" class="headerlink" title="Vector"></a>Vector</h4><p>Vector 同 ArrayList 一样,都是基于数组实现的,只不过 Vector 是一个线程安全的容器,它对内部的每个方法都简单粗暴的上锁,避免多线程引起的安全性问题,但是通常这种同步方式需要的开销比较大,因此,访问元素的效率要远远低于 ArrayList。</p>
<p>还有一点在于扩容上,ArrayList 扩容后的数组长度会增加 50%,而 Vector 的扩容长度后数组会增加一倍。</p>
<h4 id="LinkedList-类"><a href="#LinkedList-类" class="headerlink" title="LinkedList 类"></a>LinkedList 类</h4><p>LinkedList 是一个双向链表,允许存储任何元素(包括 null )。它的主要特性如下:</p>
<ul>
<li>LinkedList 所有的操作都可以表现为双向性的,索引到链表的操作将遍历从头到尾,视哪个距离近为遍历顺序。</li>
<li>注意这个实现也不是线程安全的,如果多个线程并发访问链表,并且至少其中的一个线程修改了链表的结构,那么这个链表必须进行外部加锁。或者使用</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List list = Collections.synchronizedList(<span class="keyword">new</span> LinkedList(...))</span><br></pre></td></tr></table></figure>
<h4 id="Stack"><a href="#Stack" class="headerlink" title="Stack"></a>Stack</h4><p>堆栈是我们常说的<code>后入先出(吃了吐)</code>的容器 。它继承了 Vector 类,提供了通常用的 push 和 pop 操作,以及在栈顶的 peek 方法,测试 stack 是否为空的 empty 方法,和一个寻找与栈顶距离的 search 方法。</p>
<p>第一次创建栈,不包含任何元素。一个更完善,可靠性更强的 LIFO 栈操作由 Deque 接口和他的实现提供,应该优先使用这个类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Deque<Integer> stack = <span class="keyword">new</span> ArrayDeque<Integer>()</span><br></pre></td></tr></table></figure>
<h4 id="HashSet"><a href="#HashSet" class="headerlink" title="HashSet"></a>HashSet</h4><p>HashSet 是 Set 接口的实现类,由哈希表支持(实际上 HashSet 是 HashMap 的一个实例)。它不能保证集合的迭代顺序。这个类允许 null 元素。</p>
<ul>
<li>注意这个实现不是线程安全的。如果多线程并发访问 HashSet,并且至少一个线程修改了set,必须进行外部加锁。或者使用 <code>Collections.synchronizedSet()</code> 方法重写。</li>
<li>这个实现支持 fail-fast 机制。</li>
</ul>
<h4 id="TreeSet"><a href="#TreeSet" class="headerlink" title="TreeSet"></a>TreeSet</h4><p>TreeSet 是一个基于 TreeMap 的 NavigableSet 实现。这些元素使用他们的自然排序或者在创建时提供的Comparator 进行排序,具体取决于使用的构造函数。</p>
<ul>
<li>此实现为基本操作 add,remove 和 contains 提供了 log(n) 的时间成本。</li>
<li>注意这个实现不是线程安全的。如果多线程并发访问 TreeSet,并且至少一个线程修改了 set,必须进行外部加锁。或者使用</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SortedSet s = Collections.synchronizedSortedSet(<span class="keyword">new</span> TreeSet(...))</span><br></pre></td></tr></table></figure>
<ul>
<li>这个实现持有 fail-fast 机制。</li>
</ul>
<h4 id="LinkedHashSet-类"><a href="#LinkedHashSet-类" class="headerlink" title="LinkedHashSet 类"></a>LinkedHashSet 类</h4><p>LinkedHashSet 继承于 Set,先来看一下 LinkedHashSet 的继承体系:</p>
<img src="https://s1.ax1x.com/2020/05/08/YK0FHg.png" alt="YK0FHg.png" style="zoom:50%;" />
<p>LinkedHashSet 是 Set 接口的 Hash 表和 LinkedList 的实现。这个实现不同于 HashSet 的是它维护着一个贯穿所有条目的双向链表。此链表定义了元素插入集合的顺序。注意:如果元素重新插入,则插入顺序不会受到影响。</p>
<ul>
<li>LinkedHashSet 有两个影响其构成的参数: 初始容量和加载因子。它们的定义与 HashSet 完全相同。但请注意:对于 LinkedHashSet,选择过高的初始容量值的开销要比 HashSet 小,因为 LinkedHashSet 的迭代次数不受容量影响。</li>
<li>注意 LinkedHashSet 也不是线程安全的,如果多线程同时访问 LinkedHashSet,必须加锁,或者通过使用 </li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Collections.synchronizedSet</span><br></pre></td></tr></table></figure>
<ul>
<li>该类也支持fail-fast机制</li>
</ul>
<h4 id="PriorityQueue"><a href="#PriorityQueue" class="headerlink" title="PriorityQueue"></a>PriorityQueue</h4><p>PriorityQueue 是 AbstractQueue 的实现类,优先级队列的元素根据自然排序或者通过在构造函数时期提供Comparator 来排序,具体根据构造器判断。PriorityQueue 不允许 null 元素。</p>
<ul>
<li>队列的头在某种意义上是指定顺序的最后一个元素。队列查找操作 poll,remove,peek 和 element 访问队列头部元素。</li>
<li>优先级队列是无限制的,但具有内部 capacity,用于控制用于在队列中存储元素的数组大小。</li>
<li>该类以及迭代器实现了 Collection、Iterator 接口的所有可选方法。这个迭代器提供了 <code>iterator()</code> 方法不能保证以任何特定顺序遍历优先级队列的元素。如果你需要有序遍历,考虑使用 <code>Arrays.sort(pq.toArray())</code>。</li>
<li>注意这个实现不是线程安全的,多线程不应该并发访问 PriorityQueue 实例如果有某个线程修改了队列的话,使用线程安全的类 <code>PriorityBlockingQueue</code>。</li>
</ul>
<h4 id="HashMap"><a href="#HashMap" class="headerlink" title="HashMap"></a>HashMap</h4><p>HashMap 是一个利用哈希表原理来存储元素的集合,并且允许空的 key-value 键值对。HashMap 是非线程安全的,也就是说在多线程的环境下,可能会存在问题,而 Hashtable 是线程安全的容器。HashMap 也支持 fail-fast 机制。HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。可以使用 <code>Collections.synchronizedMap(new HashMap(...))</code> 来构造一个线程安全的 HashMap。</p>
<h4 id="TreeMap-类"><a href="#TreeMap-类" class="headerlink" title="TreeMap 类"></a>TreeMap 类</h4><p>一个基于 NavigableMap 实现的红黑树。这个 map 根据 key 自然排序存储,或者通过 Comparator 进行定制排序。</p>
<ul>
<li><p>TreeMap 为 containsKey,get,put 和remove方法提供了 log(n) 的时间开销。</p>
</li>
<li><p>注意这个实现不是线程安全的。如果多线程并发访问 TreeMap,并且至少一个线程修改了 map,必须进行外部加锁。这通常通过在自然封装集合的某个对象上进行同步来实现,或者使用 <code>SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...))</code>。</p>
</li>
<li><p>这个实现持有fail-fast机制。</p>
</li>
</ul>
<h4 id="LinkedHashMap-类"><a href="#LinkedHashMap-类" class="headerlink" title="LinkedHashMap 类"></a>LinkedHashMap 类</h4><p>LinkedHashMap 是 Map 接口的哈希表和链表的实现。这个实现与 HashMap 不同之处在于它维护了一个贯穿其所有条目的双向链表。这个链表定义了遍历顺序,通常是插入 map 中的顺序。</p>
<ul>
<li><p>它提供一个特殊的 LinkedHashMap(int,float,boolean) 构造器来创建 LinkedHashMap,其遍历顺序是其最后一次访问的顺序。</p>
</li>
<li><p>可以重写 removeEldestEntry(Map.Entry) 方法,以便在将新映射添加到 map 时强制删除过期映射的策略。</p>
</li>
<li><p>这个类提供了所有可选择的 map 操作,并且允许 null 元素。由于维护链表的额外开销,性能可能会低于HashMap,有一条除外:遍历 LinkedHashMap 中的 collection-views 需要与 map.size 成正比,无论其容量如何。HashMap 的迭代看起来开销更大,因为还要求时间与其容量成正比。</p>
</li>
<li><p>LinkedHashMap 有两个因素影响了它的构成:初始容量和加载因子。</p>
</li>
<li><p>注意这个实现不是线程安全的。如果多线程并发访问LinkedHashMap,并且至少一个线程修改了map,必须进行外部加锁。这通常通过在自然封装集合的某个对象上进行同步来实现 <code>Map m = Collections.synchronizedMap(new LinkedHashMap(...))</code>。</p>
</li>
<li><p>这个实现持有fail-fast机制。</p>
</li>
</ul>
<h4 id="Hashtable-类"><a href="#Hashtable-类" class="headerlink" title="Hashtable 类"></a>Hashtable 类</h4><p>Hashtable 类实现了一个哈希表,能够将键映射到值。任何非空对象都可以用作键或值。</p>
<ul>
<li>此实现类支持 fail-fast 机制</li>
<li>与新的集合实现不同,Hashtable 是线程安全的。如果不需要线程安全的容器,推荐使用 HashMap,如果需要多线程高并发,推荐使用 <code>ConcurrentHashMap</code>。</li>
</ul>
<h4 id="IdentityHashMap-类"><a href="#IdentityHashMap-类" class="headerlink" title="IdentityHashMap 类"></a>IdentityHashMap 类</h4><p>IdentityHashMap 是比较小众的 Map 实现了。</p>
<ul>
<li>这个类不是一个通用的 Map 实现!虽然这个类实现了 Map 接口,但它故意违反了 Map 的约定,该约定要求在比较对象时使用 equals 方法,此类仅适用于需要引用相等语义的极少数情况。</li>
<li>同 HashMap,IdentityHashMap 也是无序的,并且该类不是线程安全的,如果要使之线程安全,可以调用<code>Collections.synchronizedMap(new IdentityHashMap(...))</code>方法来实现。</li>
<li>支持fail-fast机制</li>
</ul>
<h4 id="WeakHashMap-类"><a href="#WeakHashMap-类" class="headerlink" title="WeakHashMap 类"></a>WeakHashMap 类</h4><p>WeakHashMap 类基于哈希表的 Map 基础实现,带有弱键。WeakHashMap 中的 entry 当不再使用时还会自动移除。更准确的说,给定key的映射的存在将不会阻止 key 被垃圾收集器丢弃。</p>
<ul>
<li>基于 map 接口,是一种弱键相连,WeakHashMap 里面的键会自动回收</li>
<li>支持 null 值和 null 键。</li>
<li>fast-fail 机制</li>
<li>不允许重复</li>
<li>WeakHashMap 经常用作缓存</li>
</ul>
<h3 id="Collections-类"><a href="#Collections-类" class="headerlink" title="Collections 类"></a>Collections 类</h3><p>Collections 不属于 Java 框架继承树上的内容,它属于单独的分支,Collections 是一个包装类,它的作用就是为集合框架提供某些功能实现,此类只包括静态方法操作或者返回 collections。</p>
<p><strong>同步包装</strong></p>
<p>同步包装器将自动同步(线程安全性)添加到任意集合。 六个核心集合接口(Collection,Set,List,Map,SortedSet 和 SortedMap)中的每一个都有一个静态工厂方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Collection <span class="title">synchronizedCollection</span><span class="params">(Collection c)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Set <span class="title">synchronizedSet</span><span class="params">(Set s)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> List <span class="title">synchronizedList</span><span class="params">(List list)</span></span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <K,V> <span class="function">Map<K,V> <span class="title">synchronizedMap</span><span class="params">(Map<K,V> m)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SortedSet <span class="title">synchronizedSortedSet</span><span class="params">(SortedSet s)</span></span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <K,V> <span class="function">SortedMap<K,V> <span class="title">synchronizedSortedMap</span><span class="params">(SortedMap<K,V> m)</span></span>;</span><br></pre></td></tr></table></figure>
<p><strong>不可修改的包装</strong></p>
<p>不可修改的包装器通过拦截修改集合的操作并抛出 <code>UnsupportedOperationException</code>,主要用在下面两个情景:</p>
<ul>
<li>构建集合后使其不可变。在这种情况下,最好不要去获取返回 collection 的引用,这样有利于保证不变性</li>
<li>允许某些客户端以只读方式访问你的数据结构。 你保留对返回的 collection 的引用,但分发对包装器的引用。 通过这种方式,客户可以查看但不能修改,同时保持完全访问权限。</li>
</ul>
<p>这些方法是:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Collection <span class="title">unmodifiableCollection</span><span class="params">(Collection<? extends T> c)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Set <span class="title">unmodifiableSet</span><span class="params">(Set<? extends T> s)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> List <span class="title">unmodifiableList</span><span class="params">(List<? extends T> list)</span></span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <K,V> <span class="function">Map<K, V> <span class="title">unmodifiableMap</span><span class="params">(Map<? extends K, ? extends V> m)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SortedSet <span class="title">unmodifiableSortedSet</span><span class="params">(SortedSet<? extends T> s)</span></span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <K,V> <span class="function">SortedMap<K, V> <span class="title">unmodifiableSortedMap</span><span class="params">(SortedMap<K, ? extends V> m)</span></span>;</span><br></pre></td></tr></table></figure>
<p><strong>线程安全的Collections</strong></p>
<p>Java1.5 并发包 <code>(java.util.concurrent)</code> 提供了线程安全的 collections 允许遍历的时候进行修改,通过设计iterator 为 fail-fast 并抛出 ConcurrentModificationException。一些实现类是<code>CopyOnWriteArrayList</code>,<code>ConcurrentHashMap</code>,<code>CopyOnWriteArraySet</code></p>
<p><strong>Collections 算法</strong></p>
<p>此类包含用于集合框架算法的方法,例如二进制搜索,排序,重排,反向等。</p>
<h3 id="集合实现类特征图"><a href="#集合实现类特征图" class="headerlink" title="集合实现类特征图"></a>集合实现类特征图</h3><p>下图汇总了部分集合框架的主要实现类的特征图,让你能有清晰明了看出每个实现类之间的差异性</p>
<p><img src="https://s1.ax1x.com/2020/05/08/YK0ENj.png" alt="YK0ENj.png"></p>
<p>还有一种类型是关于强引用、弱引用、虚引用的文章,请参考</p>
<p><a href="https://mp.weixin.qq.com/s/ZflBpn2TBzTNv_-G-zZxNg" target="_blank" rel="noopener">https://mp.weixin.qq.com/s/ZflBpn2TBzTNv_-G-zZxNg</a></p>
<h2 id="泛形"><a href="#泛形" class="headerlink" title="泛形"></a>泛形</h2><p>在 Jdk1.5 中,提出了一种新的概念,那就是泛型,那么什么是泛型呢?</p>
<p>泛型其实就是一种参数化的集合,它限制了你添加进集合的类型。泛型的本质就是一种参数化类型。多态也可以看作是泛型的机制。一个类继承了父类,那么就能通过它的父类找到对应的子类,但是不能通过其他类来找到具体要找的这个类。泛型的设计之处就是希望对象或方法具有最广泛的表达能力。</p>
<p>下面来看一个例子说明没有泛型的用法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">List arrayList = <span class="keyword">new</span> ArrayList();</span><br><span class="line">arrayList.add(<span class="string">"cxuan"</span>);</span><br><span class="line">arrayList.add(<span class="number">100</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i< arrayList.size();i++){</span><br><span class="line"> String item = (String)arrayList.get(i);</span><br><span class="line"> System.out.println(<span class="string">"test === "</span>, item);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这段程序不能正常运行,原因是 Integer 类型不能直接强制转换为 String 类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String</span><br></pre></td></tr></table></figure>
<p>如果我们用泛型进行改写后,示例代码如下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List<String> arrayList = <span class="keyword">new</span> ArrayList<String>();</span><br><span class="line"></span><br><span class="line">arrayList.add(<span class="number">100</span>);</span><br></pre></td></tr></table></figure>
<p>这段代码在编译期间就会报错,编译器会在编译阶段就能够帮我们发现类似这样的问题。</p>
<h3 id="泛型的使用"><a href="#泛型的使用" class="headerlink" title="泛型的使用"></a>泛型的使用</h3><p>泛型的使用有多种方式,下面我们就来一起探讨一下。</p>
<h4 id="用泛型表示类"><a href="#用泛型表示类" class="headerlink" title="用泛型表示类"></a>用泛型表示类</h4><p>泛型可以加到类上面,来表示这个类的类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//此处 T 可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GenericDemo</span><<span class="title">T</span>></span>{ </span><br><span class="line"> <span class="comment">//value 这个成员变量的类型为T,T的类型由外部指定 </span></span><br><span class="line"> <span class="keyword">private</span> T value;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">GenericDemo</span><span class="params">(T value)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.value = value;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> T <span class="title">getValue</span><span class="params">()</span></span>{ <span class="comment">//泛型方法getKey的返回值类型为T,T的类型由外部指定</span></span><br><span class="line"> <span class="keyword">return</span> value;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setValue</span><span class="params">(T value)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>.value = value</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="用泛型表示接口"><a href="#用泛型表示接口" class="headerlink" title="用泛型表示接口"></a>用泛型表示接口</h4><p>泛型接口与泛型类的定义及使用基本相同。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义一个泛型接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Generator</span><<span class="title">T</span>> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> T <span class="title">next</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>一般泛型接口常用于 <code>生成器(generator)</code> 中,生成器相当于对象工厂,是一种专门用来创建对象的类。</p>
<h4 id="泛型方法"><a href="#泛型方法" class="headerlink" title="泛型方法"></a>泛型方法</h4><p>可以使用泛型来表示方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GenericMethods</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <T> <span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(T x)</span></span>{</span><br><span class="line"> System.out.println(x.getClass().getName());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="泛型通配符"><a href="#泛型通配符" class="headerlink" title="泛型通配符"></a>泛型通配符</h4><p>List 是泛型类,为了 表示各种泛型 List 的父类,可以使用类型通配符,类型通配符使用<code>问号(?)</code>表示,它的元素类型可以匹配任何类型。例如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span 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>{</span><br><span class="line"> List<String> name = <span class="keyword">new</span> ArrayList<String>();</span><br><span class="line"> List<Integer> age = <span class="keyword">new</span> ArrayList<Integer>();</span><br><span class="line"> List<Number> number = <span class="keyword">new</span> ArrayList<Number>();</span><br><span class="line"> name.add(<span class="string">"cxuan"</span>);</span><br><span class="line"> age.add(<span class="number">18</span>);</span><br><span class="line"> number.add(<span class="number">314</span>);</span><br><span class="line"> generic(name);</span><br><span class="line"> generic(age);</span><br><span class="line"> generic(number); </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">generic</span><span class="params">(List<?> data)</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"Test cxuan :"</span> + data.get(<span class="number">0</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong>上界通配符</strong> : <? extends ClassType> 该通配符为 ClassType 的所有子类型。它表示的是任何类型都是 ClassType 类型的子类。</p>
<p><strong>下界通配符</strong>: <? super ClassType> 该通配符为 ClassType 的所有超类型。它表示的是任何类型的父类都是 ClassType。</p>
<h2 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h2><p>反射是 Java 中一个非常重要同时也是一个高级特性,基本上 Spring 等一系列框架都是基于反射的思想写成的。我们首先来认识一下什么反射。</p>
<p><strong>Java 反射机制是在程序的运行过程中,对于任何一个类,都能够知道它的所有属性和方法;对于任意一个对象,都能够知道调用它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。</strong>(来源于百度百科)</p>
<p>Java 反射机制主要提供了以下这几个功能</p>
<ul>
<li>在运行时判断任意一个对象所属的类</li>