-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
1438 lines (1438 loc) · 154 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>现在是北京时间2020年5月16日早上7:37,我在杭州的家里早早起床</title>
<url>/2020/05/16/2020-05-16/</url>
<content><![CDATA[<p>现在是北京时间2020年5月16日早上7:37,我在杭州的家里早早起床(大概不到6点就醒了),洗漱后出去买了早餐,这个时间要比平时出门上班早1个小时,难得的自由与清闲啊~~有木有?!昨天傍晚下了小雨,和同事们一起吃过饭后惊喜地发现雨停了,开心!所以出去走走都觉得好凉爽,好放松!</p>
<a id="more"></a>
<p>我的工作是单休,所以今天也是工作日,不过初创小公司,注重结果大于形式,我们都在家办公还是比较人性化的。作为一名软件工程师,我深知自己还很菜,但是大家一起组成一个团队就很强了(所以更得投入精力成为团队的扛把子吖,小克同学听到木有?!),多人协作,直接沟通,交流碰撞的同时每个人的头脑都能活跃起来,思考并输出想法,最终达成共识从而形成有效的解决方案,朴素而务实的工程师文化大概不过如此吧~~</p>
<p>最近负责的系统刚上线不久,一堆bug,一堆需求,痛并快乐着~~测试不到位,用例不足,完整的测试意识不强,后面要重视起来。不要什么事都那么独立地做,有些事一个人也不可能做到极致,要有意识地去找别人合作!</p>
<hr>
<blockquote>
<p>本周碎碎念:要变得强大起来,要追求极致,要快乐而投入地工作,要有品质有感情的生活……要活得漂亮!</p>
</blockquote>
]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>日记</tag>
<tag>思考</tag>
</tags>
</entry>
<entry>
<title>Hexo+GitHub博客管理命令汇总</title>
<url>/2018/03/06/Hexo-GitHub%E5%8D%9A%E5%AE%A2%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4%E6%B1%87%E6%80%BB/</url>
<content><![CDATA[<h2 id="Hexo-部署博客及更新博文"><a href="#Hexo-部署博客及更新博文" class="headerlink" title="[Hexo]部署博客及更新博文"></a>[Hexo]部署博客及更新博文</h2><h3 id="新建博文"><a href="#新建博文" class="headerlink" title="新建博文"></a>新建博文</h3><p>使用 Git Shell 进入本地 Blog 文件夹,输入以下命令:</p>
<pre><code>hexo n "文章题目"
</code></pre><p>命令执行完后,就会发现在Blog/source/_posts目录中多了一个文件 博文名.md,这就是我们刚才新建的博文。<br><a id="more"></a></p>
<h3 id="新建页面"><a href="#新建页面" class="headerlink" title="新建页面"></a>新建页面</h3><p>上面新建的博文是显示在单个文章界面,这里新建的页面是作为单个页面显示的,比如分类、标签、归档和关于我,你点击后都是显示为单个页面。输入以下命令:</p>
<pre><code>hexo n page "页面名称"
</code></pre><p>命令执行完后,就会发现在在Blog/source目录中多了一个文件夹,里面还有一个index.md,这就代表新建了一个页面。</p>
<h3 id="写博文"><a href="#写博文" class="headerlink" title="写博文"></a>写博文</h3><p>用文本编辑器打开上面新建的博文,如下图所示:<br>新建的页面略有不同,没有tags和categories标签。<br>三个”-“后面就是博文的正文内容,接下来就是正儿八经地撰写博文了。</p>
<p>因为这里博文都是用Markdown语言写的,所以首先需要一个好用的Markdown编辑器。目前只用过MarkdownPad,其实好用的Markdown编辑器一大堆,这里推荐两个方便使用的:</p>
<ul>
<li><p>本地编辑器:Haroopad,非常小众的一款Markdown编辑器,左边编辑右边实时预览效果,非常轻便;</p>
</li>
<li><p>在线编辑器:MaHua,也是比较小众的一款Markdown编辑器,但效果确实很棒</p>
</li>
</ul>
<p>现在打开新建的博文,开始编写,具体参考这里的Markdown教程:<a href="http://www.jianshu.com/p/1e402922ee32/" target="_blank" rel="noopener">Markdown——入门指南</a></p>
<h3 id="发博文"><a href="#发博文" class="headerlink" title="发博文"></a>发博文</h3><p>依然在 Git Shell 中进入 Blog文件夹,执行下面几条命令,将博客部署到 GitHub 上:</p>
<pre><code>hexo clean
hexo generate(若要本地预览就先执行 hexo server)
hexo deploy
</code></pre><p>快捷命令:</p>
<pre><code>hexo g == hexo generate
hexo d == hexo deploy
hexo s == hexo server
hexo n == hexo new
</code></pre><p>还能组合使用,如:</p>
<pre><code>hexo d -g
hexo s --port=4100
</code></pre><p>刷新你的个人博客,就可以看到新鲜出炉的博文了,赶紧邀请小伙伴们来欣赏吧。</p>
<h3 id="一个可能出现的错误"><a href="#一个可能出现的错误" class="headerlink" title="一个可能出现的错误"></a>一个可能出现的错误</h3><pre><code>spawn git ENOENT
</code></pre><p>解决方法在这里:<a href="http://liangwenhao.cn/2016/08/24/article18/" target="_blank" rel="noopener">spawn git ENOENT解决方法</a></p>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>工具</tag>
</tags>
</entry>
<entry>
<title>JDK源码分析之Collection</title>
<url>/2019/10/08/JDK%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8BCollection/</url>
<content><![CDATA[<p><img src="https://images.gitbook.cn/ae489970-ca62-11e9-bd50-998f3938aecb" alt="enter image description here"></p>
<p>集合的继承关系图中,看出集合的根节点是 Collection,而 Collection 下又提供了两大常用集合,分别是:</p>
<a id="more"></a>
<ul>
<li>List:使用最多的有序集合,提供方便的新增、修改、删除的操作;</li>
<li>Set:集合不允许有重复的元素,在许多需要保证元素唯一性的场景中使用。</li>
</ul>
<p>集合使用:</p>
<h4 id="1)Vector"><a href="#1)Vector" class="headerlink" title="1)Vector"></a>1)Vector</h4><p>Vector 是 Java 早期提供的线程安全的有序集合,实现了同步但是效率低已经不用了,如果不需要线程安全,不建议使用此集合,毕竟同步是有线程开销的。Stack继承了Vector</p>
<p>使用示例代码:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Vector vector = <span class="keyword">new</span> Vector();</span><br><span class="line">vector.add(<span class="string">"dog"</span>);</span><br><span class="line">vector.add(<span class="string">"cat"</span>);</span><br><span class="line">vector.remove(<span class="string">"cat"</span>);</span><br><span class="line">System.out.println(vector);</span><br></pre></td></tr></table></figure>
<p>程序执行结果:<code>[dog]</code></p>
<h4 id="2)ArrayList"><a href="#2)ArrayList" class="headerlink" title="2)ArrayList"></a>2)ArrayList</h4><p>ArrayList 是最常见的非线程安全的有序集合,因为内部是<strong>数组</strong>存储的,所以<strong>随机访问</strong>效率很高,但非尾部的插入和删除性能较低,如果在中间插入元素,之后的所有元素都要后移。ArrayList 的使用与 Vector 类似。</p>
<h4 id="3)LinkedList"><a href="#3)LinkedList" class="headerlink" title="3)LinkedList"></a>3)LinkedList</h4><p>LinkedList 是使用<strong>双向链表</strong>数据结构实现的,因此<strong>增加和删除</strong>效率比较高,而随机访问效率较差。</p>
<p>LinkedList是个双向链表,它同样可以被当作<strong>栈、队列或双端队列</strong>来使用</p>
<p>LinkedList 除了包含以上两个类的操作方法之外,还新增了几个操作方法,如 offer() 、peek() 等,具体详情,请参考以下代码:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">LinkedList linkedList = <span class="keyword">new</span> LinkedList();</span><br><span class="line"><span class="comment">// 添加元素</span></span><br><span class="line">linkedList.offer(<span class="string">"bird"</span>);</span><br><span class="line">linkedList.push(<span class="string">"cat"</span>);</span><br><span class="line">linkedList.push(<span class="string">"dog"</span>);</span><br><span class="line"><span class="comment">// 获取第一个元素</span></span><br><span class="line">System.out.println(linkedList.peek());</span><br><span class="line"><span class="comment">// 获取第一个元素,并删除此元素</span></span><br><span class="line">System.out.println(linkedList.poll());</span><br><span class="line">System.out.println(linkedList);</span><br></pre></td></tr></table></figure>
<p>程序的执行结果:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">dog</span><br><span class="line">dog</span><br><span class="line">[cat, bird]</span><br></pre></td></tr></table></figure>
<h4 id="4)HashSet"><a href="#4)HashSet" class="headerlink" title="4)HashSet"></a>4)HashSet</h4><p>HashSet 是一个没有重复元素的集合。虽然它是 Set 集合的子类,实际却为 <strong>HashMap</strong> 的实例,相关源码如下:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">public HashSet() {</span><br><span class="line"> map = new HashMap<>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>因此 HashSet 是<strong>无序集合</strong>,没有办法保证元素的顺序性。</p>
<p>HashSet 默认容量为 <strong>16</strong>,每次扩充 <strong>0.75</strong> 倍,相关源码如下:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">public HashSet(Collection<? extends E> c) {</span><br><span class="line"> map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));</span><br><span class="line"> addAll(c);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>HashSet 的使用与 Vector 类似。</p>
<h4 id="5)TreeSet"><a href="#5)TreeSet" class="headerlink" title="5)TreeSet"></a>5)TreeSet</h4><p>TreeSet 集合实现了<strong>自动排序</strong>,也就是说 TreeSet 会把你插入数据进行自动排序。</p>
<p>示例代码如下:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">TreeSet treeSet = new TreeSet();</span><br><span class="line">treeSet.add("dog");</span><br><span class="line">treeSet.add("camel");</span><br><span class="line">treeSet.add("cat");</span><br><span class="line">treeSet.add("ant");</span><br><span class="line">System.out.println(treeSet);</span><br></pre></td></tr></table></figure>
<p>程序执行结果:<code>[ant, camel, cat, dog]</code></p>
<p>可以看出,TreeSet 的使用与 Vector 类似,只是实现了自动排序。</p>
<h4 id="6)LinkedHashSet"><a href="#6)LinkedHashSet" class="headerlink" title="6)LinkedHashSet"></a>6)LinkedHashSet</h4><p>LinkedHashSet 是按照元素的 hashCode 值来决定元素的存储位置,但同时又使用链表来维护元素的次序,这样使得它看起来像是按照插入顺序保存的。</p>
<h3 id="相关问题"><a href="#相关问题" class="headerlink" title="相关问题"></a>相关问题</h3><h4 id="1-List-和-Set-有什么区别?"><a href="#1-List-和-Set-有什么区别?" class="headerlink" title="1.List 和 Set 有什么区别?"></a>1.List 和 Set 有什么区别?</h4><ul>
<li>List 允许有多个 null 值,Set 只允许有一个 null 值;</li>
<li>List 允许有重复元素,Set 不允许有重复元素;</li>
<li>List 可以保证每个元素的存储顺序,Set 无法保证元素的存储顺序。</li>
</ul>
<h4 id="2-Collection-和-Collections-有什么区别?"><a href="#2-Collection-和-Collections-有什么区别?" class="headerlink" title="2.Collection 和 Collections 有什么区别?"></a>2.Collection 和 Collections 有什么区别?</h4><p>答:Collection 和 Collections 的区别如下:</p>
<ul>
<li>Collection 是集合类的上级接口,继承它的主要有 List 和 Set;</li>
<li>Collections 是针对集合类的一个帮助类,它提供了一些列的静态方法实现,如 Collections.sort() 排序、Collections.reverse() 逆序等。</li>
</ul>
<h4 id="3-LinkedHashSet-如何保证有序和唯一性?"><a href="#3-LinkedHashSet-如何保证有序和唯一性?" class="headerlink" title="3.LinkedHashSet 如何保证有序和唯一性?"></a>3.LinkedHashSet 如何保证有序和唯一性?</h4><p>答:LinkedHashSet 底层数据结构由哈希表和链表组成,链表保证了元素的有序即存储和取出一致,哈希表保证了元素的唯一性。</p>
<h4 id="4-HashSet-是如何保证数据不可重复的?"><a href="#4-HashSet-是如何保证数据不可重复的?" class="headerlink" title="4.HashSet 是如何保证数据不可重复的?"></a>4.HashSet 是如何保证数据不可重复的?</h4><p>答:HashSet 的底层其实就是 HashMap,只不过 HashSet 实现了 Set 接口并且把数据作为 K 值,而 V 值一直使用一个相同的虚值来保存,我们可以看到源码:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> map.put(e, PRESENT)==<span class="keyword">null</span>;<span class="comment">// 调用 HashMap 的 put 方法,PRESENT 是一个至始至终都相同的虚值</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>由于 HashMap 的 K 值本身就不允许重复,并且在 HashMap 中如果 K/V 相同时,会用新的 V 覆盖掉旧的 V,然后返回旧的 V,那么在 HashSet 中执行这一句话始终会返回一个 false,导致插入失败,这样就保证了数据的不可重复性。</p>
]]></content>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>JDK源码分析之Map</title>
<url>/2019/10/09/JDK%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8BMap/</url>
<content><![CDATA[<p><img src="https://images.gitbook.cn/Fpy4Na_uWi3rK9M8kOcgYK7_uXrK" alt="avatar"></p>
<p>java.util.Map</p>
<a id="more"></a>
<h3 id="Map-简介"><a href="#Map-简介" class="headerlink" title="Map 简介"></a>Map 简介</h3><p>Map是java.util提供的一个接口,是存储键值对映射的容器。AbstractMap是由abstract修饰的Map的抽象实现。</p>
<p>Map 常用的实现类如下:</p>
<ul>
<li><strong>Hashtable</strong>:Java 早期提供的一个哈希表实现,它是线程安全的,不支持 null 键和值,因为它的性能不如 ConcurrentHashMap,所以很少被推荐使用。</li>
<li><strong>HashMap</strong>:最常用的哈希表实现,如果程序中没有多线程的需求,HashMap 是一个很好的选择,支持 null 键和值,如果在多线程中可用 ConcurrentHashMap 替代。</li>
<li><strong>TreeMap</strong>:基于红黑树的一种提供顺序访问的 Map,自身实现了 key 的自然排序,也可以指定 Comparator 来自定义排序。</li>
<li><strong>LinkedHashMap</strong>:HashMap 的一个子类,保存了记录的插入顺序,可在遍历时保持与插入一样的顺序。</li>
</ul>
<h3 id="HashMap-数据结构"><a href="#HashMap-数据结构" class="headerlink" title="HashMap 数据结构"></a>HashMap 数据结构</h3><p>HashMap 底层的数据是数组被称为哈希桶,每个桶存放的是链表,链表中的每个节点,就是 HashMap 中的每个元素。在 JDK 8 当链表长度大于等于 8 时,就会转成红黑树的数据结构,以提升查询和插入的效率。</p>
<blockquote>
<p>HashMap结构:哈希数组+链表/红黑树,key和value均可以为null<br>存储元素时,需要调用key的hashCode()方法,计算出一个哈希值<br>1.哈希值相同的元素,必定位于同一个哈希槽(链)上,但不能确定这两个元素是不是同位元素<br>在进一步判断key如果相等(必要时需要调用equals()方法)时,才能确定这两个元素属于同位元素<br>如果是存储同位元素,需要考虑是否允许覆盖旧值的问题<br>2.哈希值不同的元素,它们也可能位于同一个哈希槽(链)上,但它们肯定不是同位元素</p>
<p>ConcurrentHashMap结构:哈希数组+链表/红黑树,key和value均不能为null,ConcurrentHashMap的操作方式跟HashMap是基本统一的,不同之处在于,ConcurrentHashMap是线程安全的,其中用到了无锁编程(1.7是分段锁,1.8是CAS)。获取map.size,里面有一个final修饰的sumCount()方法,在基于CAS更新的baseCount基础上,不断遍历累加大小为2的幂的数组CounterCell(本质是一个分开计数的容器)中元素的value值。</p>
</blockquote>
<p>HashMap 数据结构,如下图:</p>
<p><img src="https://images.gitbook.cn/54a52ca0-ccc7-11e9-b229-e35eb1d6e740" alt></p>
<h4 id="1-7和1-8之间的变化"><a href="#1-7和1-8之间的变化" class="headerlink" title="1.7和1.8之间的变化"></a>1.7和1.8之间的变化</h4><p>1.7之前是数组+链表,数组节点是一个Entry的内部类</p>
<blockquote>
<p>问题:</p>
<p>1.数据插入使用了头插法,导致了resize扩容问题,resize调用了transfer方法,把里面的Node进行了一个rehash,这个过程可能会造成链表的循环,就可能在下一次get()的时候出现死循环的情况;</p>
<p>2.因为没有加锁,多线程运行时候,无法保证线程安全</p>
</blockquote>
<p>1.8之后是数组+链表+红黑树,把原来的一个Entry节点改成了Node节点(静态内部类),整个put过程做了一个优化</p>
<blockquote>
<p>扩容机制:</p>
<p>capacity容量:HashMap初始化的时候,如果没有设置capacity,默认的容量是16,loadFactor是0.75,会计算出来一个扩容的阈值threshold。</p>
<p>判断当前map.size()是否>阈值,如果大于会新创建一个2倍大小容量来将原来的size进行resize()</p>
</blockquote>
<p>ConcurrentHashMap集合容器,对比HashTable, Synchronized, Lock, Collection.Synchronized线程同步方式</p>
<p>并发度是更高的,HashTable是直接对内部的方法做了Synchronized,加了一把对象锁</p>
<p>ConcurrentHashMap只会锁住当前获取到的Entry所在节点的值,锁的粒度是更细的,并且在上锁的时候使用的是CAS+Synchronized,因此效率是更高的,并发度是更高的,并发支持更好。</p>
<h4 id="JDK1-6之后对Synchronized的优化"><a href="#JDK1-6之后对Synchronized的优化" class="headerlink" title="JDK1.6之后对Synchronized的优化"></a>JDK1.6之后对Synchronized的优化</h4><p>锁升级:无锁>偏向锁>自旋锁>重量级锁</p>
<blockquote>
<p> 先判断是否需要加锁,不涉及并发处理就是无锁,其次需要锁的时候支持偏向锁,获取到资源的线程,会让它再次获取锁,如果没有获取到就升级成一个轻量级的锁,CAS的乐观锁;如果CAS没有设置成功它会进行一个自旋,自旋到一定的次数之后才会升级成一个Synchronized的重量级的锁。</p>
</blockquote>
<h3 id="hash算法优化"><a href="#hash算法优化" class="headerlink" title="hash算法优化"></a>hash算法优化</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"> <span class="comment">// JDK1.8源码参考</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> h;</span><br><span class="line"> <span class="comment">// 原哈希值与右移16位的值进行亦或运算</span></span><br><span class="line"> <span class="keyword">return</span> (key == <span class="keyword">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h >>> <span class="number">16</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<blockquote>
<p>1111 1111 1111 1111 1010 1110 0011 1001</p>
<p>0000 0000 0000 0000 1111 1111 1111 1111</p>
<p>1111 1111 1111 1111 0101 0001 1100 0110</p>
<p>int类型,32位(4字节)长度</p>
<p>高低16位都参与运算,最终结果等价于保留高16位,低16位由高低16位亦或求得结果</p>
<p>相当于对低16位进行了转码处理,可以融合高低16位的特征,尽量避免后续的hash冲突</p>
</blockquote>
<h3 id="寻址算法优化"><a href="#寻址算法优化" class="headerlink" title="寻址算法优化"></a>寻址算法优化</h3><p>(n-1) & hash -> 数组中的某个位置</p>
<p>直接用哈希值对数组长度取模,性能比较差,为了优化这个寻址过程,确保hash&(n-1)和hash%n效果是一样的,但是与运算的性能要比hash对n取模高很多。</p>
<h3 id="hash碰撞"><a href="#hash碰撞" class="headerlink" title="hash碰撞"></a>hash碰撞</h3><p>数组 + 链表, 遍历一遍是O(n),链表很长的话,性能比较差。</p>
<p>优化:链表长度达到8之后,会把链表转换为红黑树,遍历<strong>红黑树</strong>查找某个元素时,需要O(logn),性能比链表更高一些。</p>
<h3 id="HashMap-重要方法"><a href="#HashMap-重要方法" class="headerlink" title="HashMap 重要方法"></a>HashMap 重要方法</h3><h4 id="1)添加方法:put-Object-key-Object-value"><a href="#1)添加方法:put-Object-key-Object-value" class="headerlink" title="1)添加方法:put(Object key, Object value)"></a>1)添加方法:put(Object key, Object value)</h4><p>执行流程如下:</p>
<ul>
<li>对 key 进行 hash 操作,计算存储 index;</li>
<li>判断是否有哈希碰撞,如果没碰撞直接放到哈希桶里,如果有碰撞则以链表的形式存储;</li>
<li>判断已有元素的类型,决定是追加树还是追加链表,当链表大于等于 8 时,把链表转换成红黑树;</li>
<li>如果节点已经存在就替换旧值;</li>
<li>判断是否超过阀值,如果超过就要扩容。</li>
</ul>
<p>put() 执行流程图如下:</p>
<p><img src="https://images.gitbook.cn/727836f0-ccc7-11e9-a9bd-857608719494" alt="enter image description here"></p>
<h4 id="2)获取方法:get-Object-key"><a href="#2)获取方法:get-Object-key" class="headerlink" title="2)获取方法:get(Object key)"></a>2)获取方法:get(Object key)</h4><p>执行流程如下:</p>
<ul>
<li>首先比对首节点,如果首节点的 hash 值和 key 的 hash 值相同,并且首节点的键对象和 key 相同(地址相同或 equals 相等),则返回该节点;</li>
<li>如果首节点比对不相同、那么看看是否存在下一个节点,如果存在的话,可以继续比对,如果不存在就意味着 key 没有匹配的键值对。</li>
</ul>
<h3 id="相关问题"><a href="#相关问题" class="headerlink" title="相关问题"></a>相关问题</h3><h4 id="1-Map-常见实现类有哪些?"><a href="#1-Map-常见实现类有哪些?" class="headerlink" title="1.Map 常见实现类有哪些?"></a>1.Map 常见实现类有哪些?</h4><p>答:Map 的常见实现类如下列表:</p>
<ul>
<li>Hashtable:Java 早期提供的一个哈希表实现,它是线程安全的,不支持 null 键和值,因为它的性能不如 ConcurrentHashMap,所以很少被推荐使用;</li>
<li>HashMap:最常用的哈希表实现,如果程序中没有多线程的需求,HashMap 是一个很好的选择,支持 null 键和值,如果在多线程中可用 ConcurrentHashMap 替代;</li>
<li>TreeMap:基于红黑树的一种提供顺序访问的 Map,自身实现了 key 的自然排序,也可以指定的 Comparator 来自定义排序;</li>
<li>LinkedHashMap:HashMap 的一个子类,保存了记录的插入顺序,可在遍历时保持与插入一样的顺序。</li>
</ul>
<h4 id="2-使用-HashMap-可能会遇到什么问题?如何避免?"><a href="#2-使用-HashMap-可能会遇到什么问题?如何避免?" class="headerlink" title="2.使用 HashMap 可能会遇到什么问题?如何避免?"></a>2.使用 HashMap 可能会遇到什么问题?如何避免?</h4><p>答:HashMap 在并发场景中可能出现死循环的问题,这是因为 HashMap 在扩容的时候会对链表进行一次倒序处理,假设两个线程同时执行扩容操作,第一个线程正在执行 B→A 的时候,第二个线程又执行了 A→B ,这个时候就会出现 B→A→B 的问题,造成死循环。<br>解决的方法:升级 JDK 版本,在 JDK 8 之后扩容不会再进行倒序,因此死循环的问题得到了极大的改善,但这不是终极的方案,因为 HashMap 本来就不是用在多线程版本下的,如果是多线程可使用 ConcurrentHashMap 替代 HashMap。</p>
]]></content>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>今日春分,现在是2022年3月20日星期天,凌晨5:30</title>
<url>/2022/03/20/2022-03-20/</url>
<content><![CDATA[<p>刚刷到了一个关于什么语言适合做GUI的知乎问题,想到了原生开发在底层性能优化上能做的比混合开发(运行时需预先编译为目标语言)高出很多倍。其实,是一个关于技术选型的话题。由此,我联想到了当前工作中遇到的一些问题和两年前在一家创业公司的工作经历。</p>
<a id="more"></a>
<p>当初是面临node server和java server的跨语言服务交互,涉及一些数据处理、实时交互,用户体验优化相关。今天是面临python server整体向java server过渡,其中一个用户界面需要用到两个接口进行完整的交互,一个主接口已经完全迁移到了java,另一个提供参数列表的接口还是python,界面进行了很大幅度的改变,而原先的接口交互逻辑已不适用于新的界面,同时这段时间99%精力都用在了迁移上面,迁移的目标是:100%复制原先的代码逻辑,使得每一个子流程和整体流程的输入输出保持一致。很需要细心,也需要花大量时间来完成工程量,按这个惯性思维,就会尽最大可能去适配原先的逻辑。而当新的需求接入时,很容易会有一种路径依赖,保留了原先的调用方式,反而对于新功能造成一定的冗余,画蛇添足,对于用户体验是一个很大的负面效果。</p>
<p>另外,python端的分支版本管理做的也很不规范,无法一键回滚到上一个线上版本,测试和线上使用了两个分支,并且最终rebase之后reset到了线上,管理比较混乱,导致不得不进行增量更新以实现回滚的逻辑。小改动还可以这么干,大的代码量没法这么来,风险不可控了。后面得尽快把分支规范化,线上master,开发dev,新功能feature,问题修复bugfix,不要有测试和线上不同分支的巨大分歧,起码从版本、分支上面做到合理化、规范化。</p>
<p>感悟:<br>现在是一个很难兼顾的状态,不能两全其美。感觉生活在重复上演同类境遇,这一次,愿自己全力以赴,做到最好!</p>
<p>时常去梳理当前现状,改变现状要有方案先出来。最近一两年接触的都是大量工程上的琐碎问题,技术上倒是没啥太大长进,除了21年新学习了Golang并且实际开发过一个后端项目,对于Python的开发有了更深入的理解与心得体会。对于自己的主开发语言Java,很久没有进行过更深入的学习了。今年的目标是把后端技术体系完整的梳理一遍,总结和分享相关技术,持续输出,争取产生一定的影响力。</p>
]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>日记</tag>
<tag>思考</tag>
<tag>自我审视</tag>
</tags>
</entry>
<entry>
<title>Java核心技术001</title>
<url>/2018/08/02/Java%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF001/</url>
<content><![CDATA[<h3 id="Java八大基本类型"><a href="#Java八大基本类型" class="headerlink" title="Java八大基本类型"></a>Java八大基本类型</h3><p>8种基本数据类型,其中4种整型,2种浮点类型,1种用于表示Unicode编码的字符单元的字符类型和1种用于表示真值的boolean类型。</p>
<p>int / short / long / byte / float / double / char / boolean</p>
<a id="more"></a>
<p>1字节=8位,即1byte = 8bit,有符号整数,取值范围要先去掉符号位再计算数值大小</p>
<ul>
<li>整型</li>
</ul>
<table>
<thead>
<tr>
<th>类型</th>
<th>存储需求</th>
<th>bit数</th>
<th>取值范围</th>
</tr>
</thead>
<tbody>
<tr>
<td>int</td>
<td>4 byte</td>
<td>32</td>
<td>-2^31 ~ 2^31-1(有符号整数)</td>
</tr>
<tr>
<td>short</td>
<td>2 byte</td>
<td>16</td>
<td>-2^15 ~ 2^15-1</td>
</tr>
<tr>
<td>long</td>
<td>8 byte</td>
<td>64</td>
<td></td>
</tr>
<tr>
<td>byte</td>
<td>1 byte</td>
<td>8</td>
<td>-128~127</td>
</tr>
</tbody>
</table>
<ul>
<li>浮点型</li>
</ul>
<table>
<thead>
<tr>
<th>类型</th>
<th>存储</th>
<th>bit</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>float</td>
<td>4 byte</td>
<td>32</td>
<td>float类型的数值有一个后缀F(例如:3.14F)</td>
</tr>
<tr>
<td>double</td>
<td>8 byte</td>
<td>64</td>
<td>没有后缀F的浮点数值(如3.14)默认为double类型</td>
</tr>
</tbody>
</table>
<ul>
<li>char类型</li>
</ul>
<table>
<thead>
<tr>
<th>类型</th>
<th>存储</th>
<th>bit</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>char</td>
<td>2 byte</td>
<td>16</td>
</tr>
</tbody>
</table>
<ul>
<li>boolean类型</li>
</ul>
<table>
<thead>
<tr>
<th>类型</th>
<th>存储</th>
<th>bit</th>
<th>取值范围</th>
</tr>
</thead>
<tbody>
<tr>
<td>boolean</td>
<td>1 byte</td>
<td>8</td>
<td>false、true</td>
</tr>
</tbody>
</table>
<p>Java有一个能够表示任意精度的数学包,通常称为“大数值”(big number)。虽然被称为大数值,但它并不是一种Java类型,而是一个Java对象。如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中的两个很有用的类:BigInteger,BigDecimal。这两个类可以处理包含<strong>任意长度数字序列</strong>的数值。BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点数运算。具体的用法可以参见Java API。</p>
<h3 id="类型转换"><a href="#类型转换" class="headerlink" title="类型转换"></a>类型转换</h3><h4 id="long转int"><a href="#long转int" class="headerlink" title="long转int"></a>long转int</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">long</span> a = <span class="number">100L</span>;</span><br><span class="line"><span class="keyword">int</span> b = (<span class="keyword">int</span>)a;</span><br></pre></td></tr></table></figure>
<h3 id="反射原理"><a href="#反射原理" class="headerlink" title="反射原理"></a>反射原理</h3><p>JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制。</p>
<p>Java学习之反射机制及应用场景 - 对你说早安 - 博客园<a href="https://www.cnblogs.com/lzfsuifeng/p/9590705.html" target="_blank" rel="noopener">https://www.cnblogs.com/lzfsuifeng/p/9590705.html</a></p>
<h3 id="反射机制提供了哪些功能?"><a href="#反射机制提供了哪些功能?" class="headerlink" title="反射机制提供了哪些功能?"></a>反射机制提供了哪些功能?</h3><ul>
<li>在运行时判定任意一个对象所属的类</li>
<li>在运行时判定任意一个类所具有的成员变量和方法;</li>
<li>在运行时构造任意一个类的对象;</li>
<li>在运行时调用任意一个对象的方法;</li>
<li>生成动态代理;</li>
</ul>
<h3 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h3><p>Java运行时的原理?</p>
<p>动态代理</p>
<ul>
<li>逆向代码 ,例如反编译</li>
<li>与注解相结合的框架 例如Retrofit</li>
<li>单纯的反射机制应用框架 例如EventBus 2.x</li>
<li>动态生成类框架 例如Gson</li>
</ul>
<h3 id="反射机制的优缺点:"><a href="#反射机制的优缺点:" class="headerlink" title="反射机制的优缺点:"></a>反射机制的优缺点:</h3><p> <strong>优点:</strong></p>
<p> 运行期类型的判断,动态类加载,动态代理使用反射。</p>
<p> <strong>缺点:</strong></p>
<p> 性能是一个问题,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。</p>
<p>Java中的静态变量和静态代码块是在类加载的时候就执行的,实例化对象时,先声明并实例化变量再执行构造函数。如果子类继承父类,则先执行父类的静态变量和静态代码块,再执行子类的静态变量和静态代码块。同样,接着在执行父类和子类非静态代码块和构造函数。</p>
<p>注意:(静态)变量和(静态)代码块的也是有执行顺序的,与代码书写的顺序一致。在(静态)代码块中可以使用(静态)变量,但是被使用的(静态)变量必须在(静态)代码块前面声明。</p>
<p> 最后给出执行步骤:</p>
<p><strong>1、父类静态变量和静态代码块(先声明的先执行);</strong></p>
<p><strong>2、子类静态变量和静态代码块(先声明的先执行);</strong></p>
<p><strong>3、父类的变量和代码块(先声明的先执行);</strong></p>
<p><strong>4、父类的构造函数;</strong></p>
<p><strong>5、子类的变量和代码块(先声明的先执行);</strong></p>
<p><strong>6、子类的构造函数。</strong></p>
]]></content>
</entry>
<entry>
<title>Java中接口和抽象类的分析</title>
<url>/2020/10/01/Java%E4%B8%AD%E6%8E%A5%E5%8F%A3%E5%92%8C%E6%8A%BD%E8%B1%A1%E7%B1%BB%E7%9A%84%E5%88%86%E6%9E%90/</url>
<content><![CDATA[<h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><p>接口是抽象方法的集合,如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法</p>
<a id="more"></a>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MyInterface</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 接口当中只能声明一些方法(隐式的抽象方法),但是不能有方法体</span></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">void</span> <span class="title">printName</span><span class="params">(String name)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getNmae</span><span class="params">()</span></span>;</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">MyInterfaceImpl</span> <span class="keyword">implements</span> <span class="title">MyInterface</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 抽象类实现接口的时候,需要实现接口当中声明的所有方法</span></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">printName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> System.out.println(name);</span><br><span class="line"> }</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> String <span class="title">getNmae</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"name"</span>;</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>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">MyAbstractClass</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">void</span> <span class="title">printNum</span><span class="params">(<span class="keyword">int</span> a)</span> </span>{</span><br><span class="line"> System.out.println(a);</span><br><span class="line"> }</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">abstract</span> <span class="keyword">void</span> <span class="title">service</span><span class="params">(String req, String res)</span></span>;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">// 继承抽象类的子类</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MySubAbstractClass</span> <span class="keyword">extends</span> <span class="title">MyAbstractClass</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">doSomething</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"aaa"</span>);</span><br><span class="line"> }</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">void</span> <span class="title">service</span><span class="params">(String req, String res)</span> </span>{</span><br><span class="line"> <span class="comment">// implementation</span></span><br><span class="line"> }</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"> MyAbstractClass m = <span class="keyword">new</span> MyAbstractClass() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">service</span><span class="params">(String req, String res)</span> </span>{</span><br><span class="line"> <span class="comment">// implementation</span></span><br><span class="line"> }</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><img src="https://images2015.cnblogs.com/blog/1064302/201612/1064302-20161230090438195-1243745647.png" alt></p>
<h2 id="相关问题"><a href="#相关问题" class="headerlink" title="相关问题"></a>相关问题</h2><h3 id="1、接口和抽象类有什么区别"><a href="#1、接口和抽象类有什么区别" class="headerlink" title="1、接口和抽象类有什么区别"></a>1、接口和抽象类有什么区别</h3><p>在Java语言中,抽象类abstract class和接口interface<code>是抽象定义的两种机制</code>。</p>
<p>正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。抽象类abstract class和接口interface在对于抽象定义方面具有很大的相似性,甚至可以相互替换。因此很多开发者在进行抽象定义时对二者的选择显得比较随意。其实,<code>两者之间还是有很大的区别</code>,对于它们的选择能反映出对问题本质的理解、对设计意图的理解。</p>
<p>具体如下:<br><img src="https://img-blog.csdnimg.cn/20190311215243146.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NzZG5saWppbmdyYW4=,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="2、interface应用在什么场合"><a href="#2、interface应用在什么场合" class="headerlink" title="2、interface应用在什么场合"></a>2、interface应用在什么场合</h3><ul>
<li>类与类之间<code>需要特定的接口进行协调</code>,<code>而不在乎其如何实现</code>。</li>
<li>作为能够实现特定功能的<code>标识</code>存在,也可以是什么接口方法都没有的纯粹标识。如序列化接口:<code>Serializable</code></li>
<li>需要将一组类视为单一的类,而<code>调用者只通过接口来与这组类发生联系</code>。</li>
<li>需要实现特定的<code>多项功能</code>,<code>而这些功能之间可能完全没有任何联系</code>。</li>
<li>想实现多重继承,由于<strong>Java不支持多继承</strong>,子类不能够继承多个类,但可以实现多个接口</li>
</ul>
<h3 id="3、abstract-class应用在什么场合"><a href="#3、abstract-class应用在什么场合" class="headerlink" title="3、abstract class应用在什么场合"></a>3、abstract class应用在什么场合</h3><ul>
<li>子类与子类之间有<code>共同的方法</code>(<code>甚至可以是空方法体</code>,然后由子类选择自己所感兴趣的方法来<code>覆盖 重写</code>),该方法写在抽象类中,避免每个子类再去写一遍;子类与子类之间<code>不同的方法</code>作为抽象方法,在抽象类中定义。</li>
<li>某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中<code>表示状态的属性</code>来<code>区别不同的关系</code>。</li>
<li>一些方法是<code>共同的,与状态无关的,可以共享的</code>,<code>无需子类分别实现</code>,想提供默认实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能。</li>
</ul>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>Spring容器的启动过程及生命周期</title>
<url>/2019/10/08/Spring%E5%AE%B9%E5%99%A8%E7%9A%84%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B%E5%8F%8A%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</url>
<content><![CDATA[<h3 id="Spring容器的启动过程及生命周期"><a href="#Spring容器的启动过程及生命周期" class="headerlink" title="Spring容器的启动过程及生命周期"></a>Spring容器的启动过程及生命周期</h3><h3 id="Spring-Container启动过程"><a href="#Spring-Container启动过程" class="headerlink" title="Spring Container启动过程"></a>Spring Container启动过程</h3><blockquote>
<p>创建和配置实例</p>
<p>刷新实例</p>
</blockquote>
<h1 id="Spring容器的启动全流程"><a href="#Spring容器的启动全流程" class="headerlink" title="Spring容器的启动全流程"></a>Spring容器的启动全流程</h1><p>Spring容器的启动流程如下,这是我在看源码过程中自己总结的流程图,如有错误,还望评论区指点:</p>
<p><img src="https://img2020.cnblogs.com/blog/1771072/202009/1771072-20200909164014978-2077560080.png" alt="img"></p>
<p>接下来附上源码:</p>
<blockquote>
<p>为什么是refresh方法命名,而不是init命名呢?</p>
<p>其实,在ApplicaitonContext建立起来之后,可以通过refresh进行重建,将原来的ac销毁,重新执行一次初始化操作,用refresh更加贴切。</p>
</blockquote>
<p>Bean的创建和销毁</p>
<ul>
<li><a href="https://www.cnblogs.com/summerday152/p/13639896.html#dogetbean全流程" target="_blank" rel="noopener">doGetBean全流程</a></li>
<li><a href="https://www.cnblogs.com/summerday152/p/13639896.html#createbean" target="_blank" rel="noopener">createBean</a></li>
<li>doCreateBean<ul>
<li><a href="https://www.cnblogs.com/summerday152/p/13639896.html#createbeaninstance-创建实例" target="_blank" rel="noopener">createBeanInstance 创建实例</a></li>
<li><a href="https://www.cnblogs.com/summerday152/p/13639896.html#populatebean-填充属性" target="_blank" rel="noopener">populateBean 填充属性</a></li>
<li><a href="https://www.cnblogs.com/summerday152/p/13639896.html#initializebean-回调方法" target="_blank" rel="noopener">initializeBean 回调方法</a></li>
</ul>
</li>
</ul>
<a id="more"></a>
<h3 id="循环依赖"><a href="#循环依赖" class="headerlink" title="循环依赖"></a>循环依赖</h3><p>N个类循环(嵌套)引,即N个Bean互相引用对方,最终形成<code>闭环</code>,表示对象之间的相互依赖关系</p>
<p>如果在日常开发中我们用new对象的方式,若构造函数之间发生这种<strong>循环依赖</strong>的话,程序会在运行时一直循环调用<strong>最终导致内存溢出</strong>,StackOverflowError</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">()</span> </span>{</span><br><span class="line"> B b = <span class="keyword">new</span> B();</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">B</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">B</span><span class="params">()</span> </span>{</span><br><span class="line"> A a = <span class="keyword">new</span> A();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>无法解决构造器/构造方法的循环依赖,因为一开始就实例化了,初始化</p>
<p>参考文章 <a href="https://cloud.tencent.com/developer/article/1497692" target="_blank" rel="noopener">https://cloud.tencent.com/developer/article/1497692</a></p>
<p>对于Spring解决循环依赖的认识</p>
<p>// 循环依赖:调用某实例对象的方法时,方法内部又涉及到另一个类的实例化,而B当中又依赖了A,所以这时先返回一个半成品的B,等A完成了实例化之后,再返回B的实例化,最终初始化</p>
<h5 id="1、构造器注入循环依赖"><a href="#1、构造器注入循环依赖" class="headerlink" title="1、构造器注入循环依赖"></a>1、构造器注入循环依赖</h5><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(B b)</span> </span>{</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">B</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">B</span><span class="params">(A a)</span> </span>{</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>结果:项目启动失败抛出异常<code>BeanCurrentlyInCreationException</code></p>
<p>构造器注入构成的循环依赖,此种循环依赖方式<strong>是无法解决的</strong>,只能抛出<code>BeanCurrentlyInCreationException</code>异常表示循环依赖。这也是构造器注入的最大劣势</p>
<p><code>根本原因</code>:Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是<code>已经实例化</code>,但还没初始化的状态。而构造器是完成实例化的东东(不存在中间态),所以构造器的循环依赖无法解决</p>
<h5 id="2、field属性注入(setter方法注入)循环依赖"><a href="#2、field属性注入(setter方法注入)循环依赖" class="headerlink" title="2、field属性注入(setter方法注入)循环依赖"></a>2、field属性注入(setter方法注入)循环依赖</h5><p>这种方式是我们<strong>最最最最</strong>为常用的依赖注入方式(所以猜都能猜到它肯定不会有问题啦):</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>{</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> B b;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">B</span> </span>{</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> A a;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong>结果:项目启动成功,能够正常work</strong></p>
<h5 id="3、prototype-field属性注入循环依赖"><a href="#3、prototype-field属性注入循环依赖" class="headerlink" title="3、prototype field属性注入循环依赖"></a>3、<code>prototype</code> field属性注入循环依赖</h5><p><code>prototype</code>在平时使用情况较少,但是也并不是不会使用到,因此此种方式也需要引起重视。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)</span><br><span class="line">@Service</span><br><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>{</span><br><span class="line"> @Autowired</span><br><span class="line"> private B b;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)</span><br><span class="line">@Service</span><br><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">B</span> </span>{</span><br><span class="line"> @Autowired</span><br><span class="line"> private A a;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>结果:<strong>需要注意的是</strong>本例中<strong>启动时是不会报错的</strong>(因为非单例Bean<code>默认</code>不会初始化,而是使用时才会初始化),所以很简单咱们只需要手动<code>getBean()</code>或者在一个单例Bean内<code>@Autowired</code>一下它即可</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 在单例Bean内注入</span></span><br><span class="line"> @Autowired</span><br><span class="line"> private A a;</span><br></pre></td></tr></table></figure>
<p>这样子启动就报错:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">org.springframework.beans.factory.UnsatisfiedDependencyException: <span class="built_in">Error</span> creating bean <span class="keyword">with</span> name <span class="string">'mytest.TestSpringBean'</span>: Unsatisfied dependency expressed through field <span class="string">'a'</span>; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: <span class="built_in">Error</span> creating bean <span class="keyword">with</span> name <span class="string">'a'</span>: Unsatisfied dependency expressed through field <span class="string">'b'</span>; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: <span class="built_in">Error</span> creating bean <span class="keyword">with</span> name <span class="string">'b'</span>: Unsatisfied dependency expressed through field <span class="string">'a'</span>; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: <span class="built_in">Error</span> creating bean <span class="keyword">with</span> name <span class="string">'a'</span>: Requested bean is currently <span class="keyword">in</span> creation: Is there an unresolvable circular reference?</span><br><span class="line"></span><br><span class="line"> at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:<span class="number">596</span>)</span><br><span class="line"> at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:<span class="number">90</span>)</span><br><span class="line"> at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:<span class="number">374</span>)</span><br></pre></td></tr></table></figure>
<p>如何解决??? 可能有的小伙伴看到网上有说使用<code>@Lazy</code>注解解决:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">@Lazy</span><br><span class="line">@Autowired</span><br><span class="line">private A a;</span><br></pre></td></tr></table></figure>
<p>此处负责任的告诉你这样是解决不了问题的(<strong>可能会掩盖问题</strong>),<code>@Lazy</code>只是延迟初始化而已,当你真正使用到它(初始化)的时候,依旧会报如上异常。</p>
<p>对于Spring循环依赖的情况总结如下:</p>
<ol>
<li>不能解决的情况: 1. 构造器注入循环依赖 2. <code>prototype</code> field属性注入循环依赖</li>
<li>能解决的情况: 1. field属性注入(setter方法注入)循环依赖</li>
</ol>
<h2 id="Spring解决循环依赖的原理分析"><a href="#Spring解决循环依赖的原理分析" class="headerlink" title="Spring解决循环依赖的原理分析"></a>Spring解决循环依赖的原理分析</h2><p><strong><code>Spring的循环依赖的理论依据基于Java的引用传递</code></strong>,当获得对象的引用时,<strong>对象的属性是可以延后设置的</strong>。(但是构造器必须是在获取引用之前,毕竟你的引用是靠构造器给你生成的,儿子能先于爹出生?哈哈)</p>
<h4 id="Spring创建Bean的流程"><a href="#Spring创建Bean的流程" class="headerlink" title="Spring创建Bean的流程"></a>Spring创建Bean的流程</h4><p>首先需要了解是Spring它创建Bean的流程,我把它的大致调用栈绘图如下: </p>
<p><img src="https://ask.qcloudimg.com/http-save/yehe-6158873/oepgq3cnb0.png?imageView2/2/w/1620" alt></p>
<p> 对Bean的创建最为核心三个方法解释如下:</p>
<ul>
<li><code>createBeanInstance</code>:实例化,其实也就是调用对象的<strong>构造方法</strong>实例化对象</li>
<li><code>populateBean</code>:填充属性,这一步主要是对bean的依赖属性进行注入(<code>@Autowired</code>)</li>
<li><code>initializeBean</code>:回到一些形如<code>initMethod</code>、<code>InitializingBean</code>等方法</li>
</ul>
<p>从对<code>单例Bean</code>的初始化可以看出,循环依赖主要发生在<strong>第二步(populateBean)</strong>,也就是field属性注入的处理。</p>
<h4 id="Spring容器的-39-三级缓存-39"><a href="#Spring容器的-39-三级缓存-39" class="headerlink" title="Spring容器的'三级缓存'"></a>Spring容器的<code>'三级缓存'</code></h4><p>在Spring容器的整个声明周期中,单例Bean有且仅有一个对象。这很容易让人想到可以用缓存来加速访问。 从源码中也可以看出Spring大量运用了Cache的手段,在循环依赖问题的解决过程中甚至不惜使用了“三级缓存”,这也便是它设计的精妙之处~</p>
<p><code>三级缓存</code>其实它更像是Spring容器工厂的内的<code>术语</code>,采用三级缓存模式来解决循环依赖问题,这三级缓存分别指:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultSingletonBeanRegistry</span> <span class="keyword">extends</span> <span class="title">SimpleAliasRegistry</span> <span class="keyword">implements</span> <span class="title">SingletonBeanRegistry</span> </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> <span class="keyword">final</span> Map<String, Object> singletonObjects = <span class="keyword">new</span> ConcurrentHashMap<>(<span class="number">256</span>); <span class="comment">//一级缓存</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Map<String, Object> earlySingletonObjects = <span class="keyword">new</span> HashMap<>(<span class="number">16</span>); <span class="comment">// 二级缓存</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Map<String, ObjectFactory<?>> singletonFactories = <span class="keyword">new</span> HashMap<>(<span class="number">16</span>); <span class="comment">// 三级缓存</span></span><br><span class="line"> ...</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** Names of beans that are currently in creation. */</span></span><br><span class="line"> <span class="comment">// 这个缓存也十分重要:它表示bean创建过程中都会在里面呆着~</span></span><br><span class="line"> <span class="comment">// 它在Bean开始创建时放值,创建完成时会将其移出~</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(<span class="keyword">new</span> ConcurrentHashMap<>(<span class="number">16</span>));</span><br><span class="line"></span><br><span class="line"> <span class="comment">/** Names of beans that have already been created at least once. */</span></span><br><span class="line"> <span class="comment">// 当这个Bean被创建完成后,会标记为这个 注意:这里是set集合 不会重复</span></span><br><span class="line"> <span class="comment">// 至少被创建了一次的 都会放进这里~~~~</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Set<String> alreadyCreated = Collections.newSetFromMap(<span class="keyword">new</span> ConcurrentHashMap<>(<span class="number">256</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>注:<code>AbstractBeanFactory</code>继承自<code>DefaultSingletonBeanRegistry</code>~</p>
<ol>
<li><code>singletonObjects</code>:用于存放完全初始化好的 bean,<strong>从该缓存中取出的 bean 可以直接使用</strong></li>
<li><code>earlySingletonObjects</code>:提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖</li>
<li><code>singletonFactories</code>:单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖</li>
</ol>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Spring</tag>
</tags>
</entry>
<entry>
<title>Spring事务传播机制</title>
<url>/2019/10/24/Spring%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E6%9C%BA%E5%88%B6/</url>
<content><![CDATA[<h4 id="Spring事务传播机制"><a href="#Spring事务传播机制" class="headerlink" title="Spring事务传播机制"></a>Spring事务传播机制</h4><p>1、事务抽象,特性:</p>
<p>①REQUIRED:如果当前没有事务就<strong>需要</strong>创建一个新事务,否则就加入该事务,最常用也是Spring默认设置</p>
<a id="more"></a>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"> <span class="meta">@Transactional</span>(propagation = Propagation.REQUIRED)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// 7种事务传播机制:默认都是REQUIRED </span></span><br><span class="line"> methodB();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Transactional</span>(propagation = Propagation.REQUIRED)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodB</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>使用默认的事务传播机制,执行过程如下:调用A方法开启一个事务执行方法A的代码,紧接着执行方法B的代码,提交或者回滚事务(如果方法B出现了异常,则方法A最终回滚整体单个事务)</p>
<p>②SUPPORTS:<strong>支持</strong>当前事务,如果当前存在事务,就加入该事务,否则以非事务执行</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Transactional</span>(propagation = Propagation.REQUIRED)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// 7种事务传播机制:默认都是REQUIRED </span></span><br><span class="line"> methodB();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Transactional</span>(propagation = Propagation.SUPPORTS)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodB</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>直接调用方法B不会执行事务</p>
<p>③MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,否则就<strong>强制</strong>抛出异常</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Transactional</span>(propagation = Propagation.REQUIRED)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// 7种事务传播机制:默认都是REQUIRED </span></span><br><span class="line"> methodB();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Transactional</span>(propagation = Propagation.SUPPORTS)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodB</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>直接调用方法B会报错</p>
<p>④REQUIRES_NEW:创建新事务,无论是否存在事务,都创建新事务</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Transactional</span>(propagation = Propagation.REQUIRED)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodA</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// 7种事务传播机制:默认都是REQUIRED </span></span><br><span class="line"> methodB();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Transactional</span>(propagation = Propagation.REQUIRES_NEW)</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodB</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>调用方法A会开启事务1,执行完A里面的代码后,开启事务2执行方法B里面的代码,提交或回滚事务2,最后提交或回滚事务1。事务1和事务2互不影响</p>
<p>⑤NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则把当前事务<strong>挂起</strong>(一般很少用到)</p>
<p>⑥NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常</p>
<p>⑦NESTED:嵌套事务:外层的事务如果回滚,会导致内层的事务也回滚,但内层的事务如果回滚仅仅回滚自己的代码</p>
<h4 id="相关思考:"><a href="#相关思考:" class="headerlink" title="相关思考:"></a>相关思考:</h4><p>1.有一段业务逻辑,A调用B,如果A出错了仅仅回滚A,不能回滚B,这时必须得用REQUIRES_NEW传播机制,让A和B的事务是不同的两个事务</p>
<p>2.A调用B,如果出错,B只能回滚自己,而A可以带着B一起回滚,这时得用NESTED来嵌套事务</p>
<p>Tips: Spring事务隔离级别</p>
<blockquote>
<p> Spring默认的是数据库存储引擎的事务隔离级别,mysql默认隔离级别为可重复读</p>
</blockquote>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Spring</tag>
<tag>事务</tag>
</tags>
</entry>
<entry>
<title>Spring IOC和AOP</title>
<url>/2019/07/13/Spring%20IOC%E5%92%8CAOP/</url>
<content><![CDATA[<h3 id="一、Spring"><a href="#一、Spring" class="headerlink" title="一、Spring"></a>一、Spring</h3><p>Spring的核心是IoC/DI的容器,它可以帮程序员完成组件之间的依赖关系注入,使得组件之间的依赖达到最小,进而提高组件的重用性,Spring是个低侵入性(invasive)的框架,Spring中的组件并不会意识到它正置身于Spring中,这使得组件可以轻易的从框架中脱离,而几乎不用任何修改,反过来说,组件也可以简单的方式加入至框架中,使得组件甚至框架的整合变得容易。</p>
<p>Spring最为人重视的另一方面是支持AOP(Aspect-Oriented Programming),然而AOP框架只是Spring支持的一个子框架,说Spring框架是AOP框架并不是一件适当的描述,人们对于新奇的 AOP关注映射至Spring上,使得人们对于Spring的关注集中在它的AOP框架上,虽然有所误解,但也突显了Spring的另一个令人关注的特色。</p>
<a id="more"></a>
<p>Spring是一个开源框架,是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。</p>
<p>(1)通过控制反转(IOC)达到松耦合,IOC也就是把控制权交出去,在使用中直接得到对象</p>
<p>(2)提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发(例如,商品的入库和出库是业务逻辑,而商品的入库和出库需要统一的日志记录和事务的管理是系统服务,与具体的业务无关,也就是无论业务如何,都要用到系统服务)</p>
<p>(3)包含并管理应用对象的配置和生命周期,也就是容器的作用</p>
<p>(4)将简单的组件配置、组合成为复杂的应用,也就是框架的作用</p>
<p>框架与类库的区别:</p>
<ul>
<li><p>框架一般是封装了逻辑、高内聚的,类库则是松散的工具组合</p>
</li>
<li><p>框架专注于某一领域,类库则是更通用的</p>
</li>
</ul>
<p><strong>Spring是一系列轻量级Java EE框架的集合:核心容器,Spring上下文,Spring AOP, Spring DAO, Spring ORM, Spring Web, Spring MVC。</strong></p>
<p>IOC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护,也就是不显示的进行new创建对象</p>
<p>DI(依赖注入):<strong>是控制反转的一种实现方式</strong>,由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。也就是获得依赖对象的过程由自身管理变为由IOC容器主动注入。通过<a href="https://blog.csdn.net/sinat_38259539/article/details/71799078" target="_blank" rel="noopener">反射机制</a>实现。</p>
<h4 id="控制反转:"><a href="#控制反转:" class="headerlink" title="控制反转:"></a>控制反转:</h4><p>控制反转的目的:创建对象并组装对象之间的关系。</p>
<p>IOC容器初始化时创建一系列对象,并把对象之间的依赖关系通过注入的方式组织起来,当一个类A中有另外一个B,实例化时,先实例化A这个对象,再实例化B这个对象,然后把B这个对象赋值给A,这就是IOC的组装对象,具体如下图</p>
<p><img src="https://images2017.cnblogs.com/blog/1170065/201708/1170065-20170822171719871-436013565.png" alt="img"></p>
<p>图解:业务对象进入Spring容器,然后通过配置的元数据,生产出符合我们需要的对象,当我们需要用的时候,直接从Spring容器中取出来用即可,这也就是IOC,应用程序只关心对象的使用,而不关心对象的创建</p>
<p>在IOC容器中,把所有对象称为Bean,Spring利用Bean来管理这些对象,Spring对于Bean和其他的使用有两种方式,一种是基于xml的配置,一种是注解方式。</p>
<h4 id="依赖注入:"><a href="#依赖注入:" class="headerlink" title="依赖注入:"></a>依赖注入:</h4><p>借鉴<a href="http://blog.csdn.net/zhoudaxia/article/details/31763677" target="_blank" rel="noopener">http://blog.csdn.net/zhoudaxia/article/details/31763677</a></p>
<p>控制反转:把传统上由程序代码直接操控的对象的调用权交给外部容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”就是组件对象的控制权转移了,从程序代码本身转移到了外部容器。</p>
<p>实现控制反转的两种方式:依赖注入和依赖查找。</p>
<p>依赖注入有四种实现方式:</p>
<p><strong>1.基于接口</strong>:实现特定接口以供外部容器注入所依赖类型的对象,接口中定义要注入依赖对象的方法。</p>
<p><strong>2.基于setter方法</strong>:实现特定属性的public set方法,来让外部容器调用,以传入所依赖类型的对象。</p>
<p><strong>3.基于构造函数</strong>:实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。</p>
<p><strong>4.基于注解</strong>:基于Java的注解功能,在私有变量前加“@Autowired”等注解,不需要显式的定义以上三种代码,便可以让外部容器传入对应的对象。该方案相当于定义了public 的set方法,但是因为没有真正的set方法,从而不会为了实现依赖注入导致暴露了不该暴露的接口(因为set方法只想让容器访问来注入而不希望其他依赖此类的对象访问)。</p>
<h3 id="AOP"><a href="#AOP" class="headerlink" title="AOP"></a>AOP</h3><p>面向切面编程,</p>
]]></content>
</entry>
<entry>
<title>Linux服务端开发环境部署及管理(一)</title>
<url>/2018/04/28/Linux%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2%E5%8F%8A%E7%AE%A1%E7%90%86%EF%BC%88%E4%B8%80%EF%BC%89/</url>
<content><![CDATA[<h3 id="Linux服务端开发环境部署及管理(一)"><a href="#Linux服务端开发环境部署及管理(一)" class="headerlink" title="Linux服务端开发环境部署及管理(一)"></a>Linux服务端开发环境部署及管理(一)</h3><h5 id="Centos7-2-x64环境下Java-JDK、MySQL、Tomcat环境的搭建(基于腾讯云平台)"><a href="#Centos7-2-x64环境下Java-JDK、MySQL、Tomcat环境的搭建(基于腾讯云平台)" class="headerlink" title="Centos7.2 x64环境下Java JDK、MySQL、Tomcat环境的搭建(基于腾讯云平台)"></a>Centos7.2 x64环境下Java JDK、MySQL、Tomcat环境的搭建(基于腾讯云平台)</h5><p>腾讯云是个好东西,对于Linux平台不是很熟悉的人而言,开始学习时候很方便,提供各种方便的在线管理方式,如重装系统等。由于版本升级和系统兼容问题,开发中遇到的问题都很琐碎,大概是码农的日常了吧。</p>
<ul>
<li>官网下载JDK以后,上传至Linux下,安装并设置环境变量。</li>
<li>java -version</li>
<li>javac</li>
<li>MySQL安装,由于MariaDB的出现,经常会出现系统兼容问题,据说在Centos7.0以后的版本中MySQL都不太兼容,所以需要特别注意。</li>
<li>首先,需要先卸载系统预装的MariaDB,然后下载安装MySQL</li>
<li>在Linux环境下,基本都是命令行操作,所以为了方便起见,建议学习过程中多多动手,多多总结。</li>
<li>Tomcat,类似,安装完后,需要设置环境变量。</li>
<li>启动Tomcat后,可以通过访问外网IP:端口号的方式检验是否安装成功。</li>
</ul>
]]></content>
</entry>
<entry>
<title>String类相关知识点</title>
<url>/2020/08/14/String%E7%B1%BB%E7%9F%A5%E8%AF%86%E7%82%B9/</url>
<content><![CDATA[<h3 id="Java语言中String类是否可以被继承?"><a href="#Java语言中String类是否可以被继承?" class="headerlink" title="Java语言中String类是否可以被继承?"></a>Java语言中String类是否可以被继承?</h3><p>在Java中String类的定义是</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">String</span> <span class="keyword">implements</span> <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">Comparable</span><<span class="title">String</span>>, <span class="title">CharSequence</span> </span>{...}</span><br></pre></td></tr></table></figure>
<p>由此,可知String类是不可以被继承的,因为被final修饰的类是不可以被继承的</p>
<a id="more"></a>
<h3 id="final关键字"><a href="#final关键字" class="headerlink" title="final关键字"></a>final关键字</h3><p>可以用来修饰类、成员变量、方法</p>
<h4 id="修饰类"><a href="#修饰类" class="headerlink" title="修饰类"></a>修饰类</h4><p>被final修饰的类就不能被其他类继承了,设计类的时候如果不想这个类被其他类继承或者考虑一些安全因素,可以使用final修饰,否则尽量不要把类设计成final的。同时,类中所有的方法也被隐式的变为final方法。</p>
<h4 id="修饰变量"><a href="#修饰变量" class="headerlink" title="修饰变量"></a>修饰变量</h4><p>首先,变量分为基本数据类型和引用数据类型。被final修饰的基础类型和引用类型都是不能再次赋值的,这就说明被final修饰的变量是不可变的,相当于常量。因此,final修饰的变量必须被初始化,初始化可以在声明变量的时候,也可以在构造函数中初始化。</p>
<h5 id="final修饰的变量和普通变量有什么区别"><a href="#final修饰的变量和普通变量有什么区别" class="headerlink" title="final修饰的变量和普通变量有什么区别"></a>final修饰的变量和普通变量有什么区别</h5><ul>
<li><p>被final修饰的变量在使用的时候可以直接替换,因为其本身在编译期就可以确定下来是固定不可变的,对应值就会被放到字符串常量池中,而普通变量在编译阶段是一个变量,不能确定对应的值。</p>
</li>
<li><p>只有在编译阶段确定下来的字符串才会被放到字符串常量池中</p>
</li>
</ul>
<h4 id="修饰方法"><a href="#修饰方法" class="headerlink" title="修饰方法"></a>修饰方法</h4><ul>
<li>final修饰的方法,不能被子类覆盖</li>
<li>仍然可以正常被调用</li>
<li>可以实现重载</li>
</ul>
<h3 id="static关键字"><a href="#static关键字" class="headerlink" title="static关键字"></a>static关键字</h3><p>定义静态常量</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> String NAME = <span class="string">"hello java"</span>;</span><br></pre></td></tr></table></figure>
<p>static表示唯一,独此一份,表示静态;final用来表示不可变</p>
<p>二者结合就是静态常量,全局唯一,同时与final不同,只被static修饰的变量,其值可以被修改。</p>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Java</tag>
<tag>基础知识</tag>
</tags>
</entry>
<entry>
<title>Spring设计模式</title>
<url>/2019/10/23/Spring%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</url>
<content><![CDATA[<h3 id="Spring设计模式"><a href="#Spring设计模式" class="headerlink" title="Spring设计模式"></a>Spring设计模式</h3><h4 id="工厂模式"><a href="#工厂模式" class="headerlink" title="工厂模式"></a>工厂模式</h4><p>spring ioc的核心设计模式的思想体现,本身就是一个大的工厂,把所有的bean实例都放在了spring 容器里(大工厂),如果要使用bean就直接找spring容器就好了,自己不用创建对象。</p>
<a id="more"></a>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyController</span> </span>{</span><br><span class="line"> <span class="comment">// 原先每次都要自己new一个</span></span><br><span class="line"> <span class="keyword">private</span> MyService mySerice = <span class="keyword">new</span> MyService();</span><br><span class="line"> <span class="comment">// 使用spring @Autowire注解自动注入一个,实际底层是依靠的工厂模式去创建的</span></span><br><span class="line"> <span class="keyword">private</span> MyService mySerice = MyServiceFactory.getMyService();</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">MyServiceFactory</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> MyService <span class="title">getMyService</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> MyServiceImpl();</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>spring默认对每个bean都走的单例模式,确保一个类在系统运行期间只有一个实例对象,只有一个bean</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyService</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> Myservice myService; <span class="comment">// 禁止指令重排序</span></span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> stativ MyService <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (myService == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">synchronized</span>(MyService<span class="class">.<span class="keyword">class</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (myService == <span class="keyword">null</span>) {</span><br><span class="line"> myService = <span class="keyword">new</span> MyService();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> myService;</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>AOP的核心模式,如果要对一些类的方法切入一些增强的代码,会创建一些动态代理的对象,让你对那些目标对象的访问,先经过动态代理对象,动态代理对象先执行一些增强的代码,再调用你的目标对象。在设计模式里,就是代理模式的体现和运用,实现一些增强的访问。</p>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Spring</tag>
<tag>设计模式</tag>
</tags>
</entry>
<entry>
<title>Vue前端开发环境</title>
<url>/2019/07/20/Vue%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/</url>
<content><![CDATA[<table>
<thead>
<tr>
<th style="text-align:left">技术</th>
<th>版本</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">node</td>
<td>v10.16.0</td>
<td>node编译环境</td>
</tr>
<tr>
<td style="text-align:left">npm</td>
<td>6.9.0</td>
<td>npm包管理工具</td>
</tr>
<tr>
<td style="text-align:left">Vue</td>
<td>2.9.6</td>
<td>前端框架</td>
</tr>
<tr>
<td style="text-align:left">Vue-router</td>
<td>3.0.2</td>
<td>前端路由框架</td>
</tr>
<tr>
<td style="text-align:left">Vuex</td>
<td>3.1.0</td>
<td>vue状态管理组件</td>
</tr>
<tr>
<td style="text-align:left">Vue-cli</td>
<td>————</td>
<td>Vue脚手架</td>
</tr>
<tr>
<td style="text-align:left">Element-ui</td>
<td>2.7.0</td>
<td>前端UI框架</td>
</tr>
<tr>
<td style="text-align:left">Echarts</td>
<td>4.2.1</td>
<td>数据可视化框架</td>
</tr>
<tr>
<td style="text-align:left">Uni-app</td>
<td>————</td>
<td>跨平台前端框架</td>
</tr>
<tr>
<td style="text-align:left">Mockjs</td>
<td>1.0.1-beta3</td>
<td>模拟后端数据</td>
</tr>
<tr>
<td style="text-align:left">Axios</td>
<td>0.18.0</td>
<td>基于Promise的Http库</td>
</tr>
<tr>
<td style="text-align:left">Js-cookie</td>
<td>2.2.0</td>
<td>Cookie组件</td>
</tr>
<tr>
<td style="text-align:left">Jsonlint</td>
<td>1.6.3</td>
<td>Json解析组件</td>
</tr>
<tr>
<td style="text-align:left">screenfull</td>
<td>4.2.0</td>
<td>全屏组件</td>
</tr>
<tr>
<td style="text-align:left">Xlsx</td>
<td>0.14.1</td>
<td>Excel表导出组件</td>
</tr>
<tr>
<td style="text-align:left">Webpack</td>
<td>————</td>
<td>模板打包器</td>
</tr>
</tbody>
</table>
<a id="more"></a>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span> 安装vue</span><br><span class="line"><span class="meta">$</span> npm install [email protected]</span><br><span class="line"><span class="meta">#</span> 全局安装 vue-cli</span><br><span class="line"><span class="meta">$</span> npm install --global vue-cli</span><br><span class="line"><span class="meta">#</span> 创建一个基于 webpack 模板的新项目my-project</span><br><span class="line"><span class="meta">$</span> vue init webpack my-project</span><br><span class="line"><span class="meta">#</span> 进入项目目录</span><br><span class="line"><span class="meta">$</span> cd my-project</span><br><span class="line"><span class="meta">#</span> 安装依赖</span><br><span class="line"><span class="meta">$</span> npm install</span><br><span class="line"><span class="meta">#</span> 运行项目</span><br><span class="line"><span class="meta">$</span> npm run dev</span><br><span class="line"><span class="meta">#</span> 卸载旧版本,在安装新版本。</span><br><span class="line">npm uninstall vue-cli -g </span><br><span class="line">npm install --global vue-cli</span><br></pre></td></tr></table></figure>
]]></content>
<tags>
<tag>前端</tag>
</tags>
</entry>
<entry>
<title>Vuforia开发入门一准备工作</title>
<url>/2018/04/03/Vuforia%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E4%B8%80%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C/</url>
<content><![CDATA[<h2 id="Vuforia开发入门"><a href="#Vuforia开发入门" class="headerlink" title="Vuforia开发入门"></a>Vuforia开发入门</h2><h3 id="1、开发环境配置"><a href="#1、开发环境配置" class="headerlink" title="1、开发环境配置"></a>1、开发环境配置</h3><ul>
<li>a) Android 环境配置 </li>
<li>b) Unity3D 下载和安装 <h3 id="2、资源下载"><a href="#2、资源下载" class="headerlink" title="2、资源下载"></a>2、资源下载</h3></li>
<li>a) <a href="https://developer.vuforia.com/" target="_blank" rel="noopener">官网注册</a></li>
<li>b) <a href="https://developer.vuforia.com/downloads/sdk" target="_blank" rel="noopener">Samples资源下载</a></li>
</ul>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>AR</tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<url>/2017/07/14/hello-world/</url>
<content><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="noopener">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a><br><a id="more"></a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="noopener">Deployment</a></p>
]]></content>
</entry>
<entry>
<title>idea快捷键使用整理</title>
<url>/2019/07/23/idea%E5%BF%AB%E6%8D%B7%E9%94%AE%E4%BD%BF%E7%94%A8%E6%95%B4%E7%90%86/</url>
<content><![CDATA[<p>1、格式化编辑代码 Ctrl+Alt+L</p>
<p>2、sout 快速打印</p>
<hr>
<p>一键格式化代碼: <strong>Ctrl+Alt+L</strong></p>
<p><strong>全局搜索替换:</strong>ctrl+shift+r</p>
<p><strong>强大的搜索功能,shift+shift (无论您想要搜啥都能找到)</strong></p>
<p><strong>ctrl+shift+R==搜索类 CTRL+N:按照类名搜索类</strong></p>
<p>【常规】</p>
<ol>
<li>Ctrl+Shift + Enter,语句完成</li>
<li>“!”,否定完成,输入表达式时按 “!”键</li>
<li>Ctrl+E,最近的文件</li>
<li>Ctrl+Shift+E,最近更改的文件</li>
<li>Shift+Click,可以关闭文件</li>
<li>Ctrl+[ OR ],可以跑到大括号的开头与结尾</li>
<li>Ctrl+F12,可以显示当前文件的结构</li>
<li>Ctrl+F7,可以查询当前元素在当前文件中的引用,然后按 F3 可以选择</li>
<li>Ctrl+N,可以快速打开类</li>
</ol>
<a id="more"></a>
<ol>
<li>Ctrl+Shift+N,可以快速打开文件</li>
<li>Alt+Q,可以看到当前方法的声明</li>
<li>Ctrl+P,可以显示参数信息</li>
<li>Ctrl+Shift+Insert,可以选择剪贴板内容并插入</li>
<li>Alt+Insert,可以生成构造器/Getter/Setter等</li>
<li>Ctrl+Alt+V,可以引入变量。例如:new String(); 自动导入变量定义</li>
<li>Ctrl+Alt+T,可以把代码包在一个块内,例如:try/catch</li>
<li>Ctrl+Enter,导入包,自动修正</li>
<li>Ctrl+Alt+L,格式化代码</li>
<li>Ctrl+Alt+I,将选中的代码进行自动缩进编排,这个功能在编辑 JSP 文件时也可以工作</li>
<li>Ctrl+Alt+O,优化导入的类和包</li>
<li>Ctrl+R,替换文本</li>
<li>Ctrl+F,查找文本</li>
<li>Ctrl+Shift+Space,自动补全代码</li>
<li>Ctrl+空格,代码提示(与系统输入法快捷键冲突)</li>
<li>Ctrl+Shift+Alt+N,查找类中的方法或变量</li>
<li>Alt+Shift+C,最近的更改</li>
<li>Alt+Shift+Up/Down,上/下移一行</li>
<li>Shift+F6,重构 - 重命名</li>
<li>Ctrl+X,删除行</li>
<li>Ctrl+D,复制行</li>
<li>Ctrl+/或Ctrl+Shift+/,注释(//或者/**/)</li>
<li>Ctrl+J,自动代码(例如:serr)</li>
<li>Ctrl+Alt+J,用动态模板环绕</li>
<li>Ctrl+H,显示类结构图(类的继承层次)</li>
<li>Ctrl+Q,显示注释文档</li>
<li>Alt+F1,查找代码所在位置</li>
<li>Alt+1,快速打开或隐藏工程面板</li>
<li>Ctrl+Alt+left/right,返回至上次浏览的位置</li>
<li>Alt+left/right,切换代码视图</li>
<li>Alt+Up/Down,在方法间快速移动定位</li>
<li>Ctrl+Shift+Up/Down,向上/下移动语句</li>
<li>F2 或 Shift+F2,高亮错误或警告快速定位</li>
<li>Tab,代码标签输入完成后,按 Tab,生成代码</li>
<li>Ctrl+Shift+F7,高亮显示所有该文本,按 Esc 高亮消失</li>
<li>Alt+F3,逐个往下查找相同文本,并高亮显示</li>
<li>Ctrl+Up/Down,光标中转到第一行或最后一行下</li>
<li>Ctrl+B/Ctrl+Click,快速打开光标处的类或方法(跳转到定义处)</li>
<li>Ctrl+Alt+B,跳转到方法实现处</li>
<li>Ctrl+Shift+Backspace,跳转到上次编辑的地方</li>
<li>Ctrl+O,重写方法</li>
<li>Ctrl+Alt+Space,类名自动完成</li>
<li>Ctrl+Alt+Up/Down,快速跳转搜索结果</li>
<li>Ctrl+Shift+J,整合两行</li>
<li>Alt+F8,计算变量值</li>
<li>Ctrl+Shift+V,可以将最近使用的剪贴板内容选择插入到文本</li>
<li>Ctrl+Alt+Shift+V,简单粘贴</li>
<li>Shift+Esc,不仅可以把焦点移到编辑器上,而且还可以隐藏当前(或最后活动的)工具窗口</li>
<li>F12,把焦点从编辑器移到最近使用的工具窗口</li>
<li>Shift+F1,要打开编辑器光标字符处使用的类或者方法 Java 文档的浏览器</li>
<li>Ctrl+W,可以选择单词继而语句继而行继而函数</li>
<li>Ctrl+Shift+W,取消选择光标所在词</li>
<li>Alt+F7,查找整个工程中使用地某一个类、方法或者变量的位置</li>
<li>Ctrl+I,实现方法</li>
<li>Ctrl+Shift+U,大小写转化</li>
<li>Ctrl+Y,删除当前行</li>
<li>Shift+Enter,向下插入新行</li>
<li>psvm/sout,main/System.out.println(); Ctrl+J,查看更多</li>
<li>Ctrl+Shift+F,全局查找</li>
<li>Ctrl+F,查找/Shift+F3,向上查找/F3,向下查找</li>
<li>Ctrl+Shift+S,高级搜索</li>
<li>Ctrl+U,转到父类</li>
<li>Ctrl+Alt+S,打开设置对话框</li>
<li>Alt+Shift+Inert,开启/关闭列选择模式</li>
<li>Ctrl+Alt+Shift+S,打开当前项目/模块属性</li>
<li>Ctrl+G,定位行</li>
<li>Alt+Home,跳转到导航栏</li>
<li>Ctrl+Enter,上插一行</li>
<li>Ctrl+Backspace,按单词删除</li>
<li>Ctrl+”+/-“,当前方法展开、折叠</li>
<li>Ctrl+Shift+”+/-“,全部展开、折叠</li>
</ol>
<p>【调试部分、编译】</p>
<ol>
<li>Ctrl+F2,停止</li>
<li>Alt+Shift+F9,选择 Debug</li>
<li>Alt+Shift+F10,选择 Run</li>
<li>Ctrl+Shift+F9,编译</li>
<li>Ctrl+Shift+F10,运行</li>
<li>Ctrl+Shift+F8,查看断点</li>
<li>F8,步过</li>
<li>F7,步入</li>
<li>Shift+F7,智能步入</li>
<li>Shift+F8,步出</li>
<li>Alt+Shift+F8,强制步过</li>
<li>Alt+Shift+F7,强制步入</li>
<li>Alt+F9,运行至光标处</li>
<li>Ctrl+Alt+F9,强制运行至光标处</li>
<li>F9,恢复程序</li>
<li>Alt+F10,定位到断点</li>
<li>Ctrl+F8,切换行断点</li>
<li>Ctrl+F9,生成项目</li>
<li>Alt+1,项目</li>
<li>Alt+2,收藏</li>
<li>Alt+6,TODO</li>
<li>Alt+7,结构</li>
<li>Ctrl+Shift+C,复制路径</li>
<li>Ctrl+Alt+Shift+C,复制引用,必须选择类名</li>
<li>Ctrl+Alt+Y,同步</li>
<li>Ctrl+~,快速切换方案(界面外观、代码风格、快捷键映射等菜单)</li>
<li>Shift+F12,还原默认布局</li>
<li>Ctrl+Shift+F12,隐藏/恢复所有窗口</li>
<li>Ctrl+F4,关闭</li>
<li>Ctrl+Shift+F4,关闭活动选项卡</li>
<li>Ctrl+Tab,转到下一个拆分器</li>
<li>Ctrl+Shift+Tab,转到上一个拆分器</li>
</ol>
<p>【重构】</p>
<ol>
<li>Ctrl+Alt+Shift+T,弹出重构菜单</li>
<li>Shift+F6,重命名</li>
<li>F6,移动</li>
<li>F5,复制</li>
<li>Alt+Delete,安全删除</li>
<li>Ctrl+Alt+N,内联</li>
</ol>
<p>【查找】</p>
<ol>
<li>Ctrl+F,查找</li>
<li>Ctrl+R,替换</li>
<li>F3,查找下一个</li>
<li>Shift+F3,查找上一个</li>
<li>Ctrl+Shift+F,在路径中查找</li>
<li>Ctrl+Shift+R,在路径中替换</li>
<li>Ctrl+Shift+S,搜索结构</li>
<li>Ctrl+Shift+M,替换结构</li>
<li>Alt+F7,查找用法</li>
<li>Ctrl+Alt+F7,显示用法</li>
<li>Ctrl+F7,在文件中查找用法</li>
<li>Ctrl+Shift+F7,在文件中高亮显示用法</li>
</ol>
<p>【VCS】</p>
<ol>
<li>Alt+~,VCS 操作菜单</li>
<li>Ctrl+K,提交更改</li>
<li>Ctrl+T,更新项目</li>
<li>Ctrl+Alt+Shift+D,显示变化</li>
</ol>
<p><strong>以上皆由网络整理,不作商业用途,与本人无关</strong></p>
]]></content>
<tags>
<tag>工具</tag>
</tags>
</entry>
<entry>
<title>完美世界2018春招编程题</title>
<url>/2018/04/27/%E5%AE%8C%E7%BE%8E%E4%B8%96%E7%95%8C2018%E6%98%A5%E6%8B%9B%E7%BC%96%E7%A8%8B%E9%A2%98/</url>
<content><![CDATA[<ul>
<li><ol>
<li>题目描述:输入若干整数,以空格间隔,要求反转字符序列并打印输出。<br>如:</li>
</ol>
</li>
<li><p>Input: 12 3 456 6789</p>
</li>
<li><p>Output: 6789 456 2 12</p>
<a id="more"></a>
</li>
<li><p>源代码:<br>方法一、使用栈存储</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#include<iostream></span><br><span class="line">#include <cstdio></span><br><span class="line">#include <stack></span><br><span class="line">#include <vector></span><br><span class="line">using namespace std;</span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int a[20];</span><br><span class="line"> int i = 0;</span><br><span class="line"> string ss, st;</span><br><span class="line"> stack<string> s1;</span><br><span class="line"> char c;</span><br><span class="line"> do{</span><br><span class="line"> c = getchar();</span><br><span class="line"> if(c >= '0' && c <= '9'){</span><br><span class="line"> ss += c;</span><br><span class="line"> }else if(c == ' ' || c == '\n'){</span><br><span class="line"> </span><br><span class="line"> s1.push(ss);</span><br><span class="line"> ss = "";</span><br><span class="line"> }</span><br><span class="line"> }while(c != '\n');</span><br><span class="line"></span><br><span class="line"> while(!s1.empty()){</span><br><span class="line"> st = s1.top();</span><br><span class="line"> s1.pop();</span><br><span class="line"> cout << st;</span><br><span class="line"> if(!s1.empty()){</span><br><span class="line"> cout << " ";</span><br><span class="line"> }else{</span><br><span class="line"> cout << endl;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>方法一、使用数组变换存储</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#include<bits/stdc++.h> </span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int a[20];</span><br><span class="line"> int i = 0;</span><br><span class="line"> char c;</span><br><span class="line"> string str = "";</span><br><span class="line"> do{</span><br><span class="line"> c=getchar();</span><br><span class="line"> if(c>='0'&&c<='9'){</span><br><span class="line"> str += c;</span><br><span class="line"> }else if(c ==' ' || c == '\n')</span><br><span class="line"> {</span><br><span class="line"> a[i++] = atoi(str.c_str()); //atoi:将字符串转化为char*对象,再转换成一个整数值</span><br><span class="line"> str = "";</span><br><span class="line"> }</span><br><span class="line"> }while(c!='\n');</span><br><span class="line"></span><br><span class="line"> for(int j = 0; j < i; j++){</span><br><span class="line"> cout << a[i-j-1];</span><br><span class="line"> if(i-j-1 != 0){</span><br><span class="line"> cout << " ";</span><br><span class="line"> }else{</span><br><span class="line"> cout << endl;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>《深入理解Java虚拟机》之虚拟机类加载机制</title>
<url>/2020/10/01/%E3%80%8A%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Java%E8%99%9A%E6%8B%9F%E6%9C%BA%E3%80%8B%E4%B9%8B%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6/</url>
<content><![CDATA[<h3 id="类加载过程"><a href="#类加载过程" class="headerlink" title="类加载过程"></a>类加载过程</h3><p>当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。</p>
<p>JVM虚拟机执行class字节码的过程可以分为7个阶段:加载、验证、准备、解析、初始化、使用、卸载</p>
<p>(没事多看书,多总结,多动手。)</p>
<p><img src="https://img-blog.csdn.net/20180813115150336?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM4MDc1NDI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70" alt></p>
<a id="more"></a>
<h3 id="1-加载:"><a href="#1-加载:" class="headerlink" title="1.加载:"></a>1.加载:</h3><p>将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。</p>
<p>类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。</p>
<p> 通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源。</p>
<ul>
<li>从本地文件系统加载class文件,这是前面绝大部分示例程序的类加载方式。</li>
<li>从JAR包加载class文件,这种方式也是很常见的,前面介绍JDBC编程时用到的数据库驱动类就放在JAR文件中,JVM可以从JAR文件中直接加载该class文件。</li>
<li>通过网络加载class文件。</li>
<li><p>把一个Java源文件动态编译,并执行加载。</p>
<p>类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。</p>
</li>
</ul>
<h3 id="2-链接"><a href="#2-链接" class="headerlink" title="2.链接"></a>2.链接</h3><p> 当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类连接又可分为如下3个阶段。</p>
<p> <strong>1)验证:</strong>验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。Java是相对C++语言是安全的语言,例如它有C++不具有的数组越界的检查。这本身就是对自身安全的一种保护。验证阶段是Java非常重要的一个阶段,它会直接的保证应用是否会被恶意入侵的一道重要的防线,越是严谨的验证机制越安全。验证的目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。其主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。</p>
<p> 四种验证做进一步说明:</p>
<p> <strong>文件格式验证:</strong>主要验证字节流是否符合Class文件格式规范,并且能被当前的虚拟机加载处理。例如:主,次版本号是否在当前虚拟机处理的范围之内。常量池中是否有不被支持的常量类型。指向常量的中的索引值是否存在不存在的常量或不符合类型的常量。</p>
<p> <strong>元数据验证:</strong>对字节码描述的信息进行语义的分析,分析是否符合java的语言语法的规范。</p>
<p> <strong>字节码验证:</strong>最重要的验证环节,分析数据流和控制,确定语义是合法的,符合逻辑的。主要的针对元数据验证后对方法体的验证。保证类方法在运行时不会有危害出现。</p>
<p> <strong>符号引用验证:</strong>主要是针对符号引用转换为直接引用的时候,是会延伸到第三解析阶段,主要去确定访问类型等涉及到引用的情况,主要是要保证引用一定会被访问到,不会出现类等无法访问的问题。</p>
<p> 2)<strong>准备:</strong>类准备阶段负责为类的静态变量分配内存,并设置默认初始值。</p>
<p> 3)<strong>解析:</strong>将类的二进制数据中的符号引用替换成直接引用。说明一下:符号引用:符号引用是以一组符号来描述所引用的目标,符号可以是任何的字面形式的字面量,只要不会出现冲突能够定位到就行。布局和内存无关。直接引用:是指向目标的指针,偏移量或者能够直接定位的句柄。该引用是和内存中的布局有关的,并且一定加载进来的。</p>
<h3 id="3-初始化"><a href="#3-初始化" class="headerlink" title="3.初始化"></a>3.初始化</h3><p> 初始化是为类的静态变量赋予正确的初始值,准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析(后面在说),到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。</p>
<h2 id="类加载机制:"><a href="#类加载机制:" class="headerlink" title="类加载机制:"></a>类加载机制:</h2><p><strong>1.JVM的类加载机制</strong>主要有如下3种。</p>
<ul>
<li>全盘负责:所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。</li>
<li>双亲委派:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。</li>
<li>缓存机制。缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。</li>
</ul>
<p><strong>2.这里说明一下双亲委派机制:</strong></p>
<p><img src="https://img-blog.csdn.net/20180813145521896?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM4MDc1NDI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70" alt="img"></p>
<p> 双亲委派机制,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成。</p>
<p> 双亲委派机制的优势:采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。</p>
]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JVM</tag>
</tags>
</entry>
<entry>
<title>《深入理解Java虚拟机》之GC</title>
<url>/2019/12/05/%E3%80%8A%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Java%E8%99%9A%E6%8B%9F%E6%9C%BA%E3%80%8B%E4%B9%8BGC/</url>
<content><![CDATA[<h1 id="内存动态分配和垃圾收集技术"><a href="#内存动态分配和垃圾收集技术" class="headerlink" title="内存动态分配和垃圾收集技术"></a>内存动态分配和垃圾收集技术</h1><p>GC:哪些内存需要回收?什么时候回收?如何回收?</p>
<p>当需要排查各种内存溢出、内存泄露问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,就需要对内存动态分配和垃圾收集技术实施必要的监控和调节。</p>
<p>垃圾收集器关注的是Java堆和方法区中的动态分配和回收的内存。</p>
<p>判断对象存活与否?</p>
<p>1、引用计数算法:主流的Java虚拟机未采用,很难解决对象之间相互循环引用的问题</p>
<p>2、可达性分析算法:判定对象是否可回收</p>
<p>对象真正死亡:至少经历两次标记过程:finalize()最多执行一次</p>
<hr>
<h3 id="一、垃圾收集算法:"><a href="#一、垃圾收集算法:" class="headerlink" title="一、垃圾收集算法:"></a>一、垃圾收集算法:</h3><h5 id="1-标记-清除算法-Mark-and-Sweep"><a href="#1-标记-清除算法-Mark-and-Sweep" class="headerlink" title="1.标记-清除算法 Mark and Sweep"></a>1.标记-清除算法 Mark and Sweep</h5><p>分为标记和清除两个阶段,是最基础的收集算法,主要不足:1、效率问题;2、空间问题:标记清除之后会产生大量不连续的内存碎片,导致之后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次GC。</p>
<a id="more"></a>
<h5 id="2-复制算法-Copying"><a href="#2-复制算法-Copying" class="headerlink" title="2.复制算法 Copying"></a>2.复制算法 Copying</h5><p>一块内存平均划分为2块,一块空闲,一块存储,当回收的时候,把另一半中仍然存活的复制过来,并将其内存全部收回——解决了效率问题(每次都是对半个区域进行内存回收,内存分配时也不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单运行高效)。比较适合“朝生夕死”的新生代对象。</p>
<p>Eden:Survivor0:Survivor = 8:1:1</p>