forked from martin-chips/dimplefeng.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
3764 lines (3240 loc) · 642 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><![CDATA[TCP的三次握手和四次挥手]]></title>
<url>/2018/09/28/2018-9-28-16-43-30/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p><strong>TCP报文格式(标志位,确认号,序列号):</strong><br><strong>FIN</strong>:finish,结束</p>
<p><strong>PSH</strong>:push,传输<br><a id="more"></a><br><strong>SYN</strong>:synchronous,建立连接</p>
<p><strong>RST</strong>:reset,重置</p>
<p><strong>ACK</strong>:acknowledgement:确认</p>
<p><strong>seq</strong>:sequence number 序列号</p>
<p>需要注意的是序列列号不会从0或者1开始,而是在建立连接的时候由计算机生成一个随机数作为初始值,通过SYN包发送给主机,然后每次转发过去的字节数累加到初始值上表示数据的位置;</p>
<p><strong>ack</strong>:acknowledge number 确认号<br>表示下一次应该收到的是数据的序列号,发送端收到这个确认应答以后可以认为在这个序列号之前的数据都已经被正常接收;</p>
<h1 id="TCP的三次握手"><a href="#TCP的三次握手" class="headerlink" title="TCP的三次握手"></a>TCP的三次握手</h1><p><strong>三次握手的过程</strong></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/clipboard-2018928.png" alt="clipboard-2018928"></p>
<ul>
<li>第一次握手:Client将标志位SYN置为1,随机产生一个seq=J,并将该数据报发送给Server,Client进入到SYN_SENT状态,等待Server确认;</li>
<li>第二次握手:Server收到数据包后由SYN=1知道Client需要建立连接,Server将标志位SYN置为1,同时ACK置为1,ack=J+1,随机产生一个seq=K,并将该数据包发送给Client确认连接请求,同时Server进入到SYN_SCVD状态;</li>
<li>第三次握手:Client收到信息后,检查ack是否等于J+1,ACK是否为1,如果正确将标志位ACK置为1,ack=K+1,并将该数据报发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确就建立连接成功,Client和Server进入到ESTABLISHED状态,完成三次握手;随后进行数据的传输;<h1 id="TCP的四次挥手"><a href="#TCP的四次挥手" class="headerlink" title="TCP的四次挥手"></a>TCP的四次挥手</h1>所谓的四次挥手就是终止TCP的连接,需要客户端和服务端总共发送四个包确认连接的断开;</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/clipboard11-2018928.png" alt="clipboard11-2018928"></p>
<p>因为TCP的连接是<strong>全双工</strong>的,因此<strong>每个方向都需要单独的进行关闭</strong>,这个原则是当一方完成数据发送的任务后,发送一个FIN来终止在这一方向上的连接,收到FIN只是意味着这一方向上面没有数据流动了,不会再收到数据了,但是在这个TCP连接上海市可以发送数据的,直到这一方向上也发送了FIN;</p>
<p><strong>四次挥手过程:</strong></p>
<ul>
<li>第一次挥手:Client发送一个FIN,同时发送一个数据包M,用来关闭Client到Server的数据传送,Client进入到FIN_WAIT_1状态;</li>
<li>第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到的序号M+1,Server进入到CLOSE_WAIT状态;</li>
<li>第三次挥手:Server发送一个FIN,用来关闭从Server到Client的数据传送,Server进入到LAST_ACK状态;</li>
<li>第四次挥手:Client收到FIN后,Client进入到TIME_WAIT状态,接着发送一个ACK到Server,确认序号为收到的序号+1,Server进入到Close状态,完成四次挥手;</li>
</ul>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><h2 id="为什么连接的时候是三次,断开的时候需要四次?"><a href="#为什么连接的时候是三次,断开的时候需要四次?" class="headerlink" title="为什么连接的时候是三次,断开的时候需要四次?"></a>为什么连接的时候是三次,断开的时候需要四次?</h2><ul>
<li>服务端在Listen状态下,收到客户端的请求连接的SYN报文后,将ACK和SYN放在一个报文中发送给客户端;</li>
<li>在关闭连接的时候,<strong>TCP的连接是全双工的,可以两端同时发送数据</strong>,收到客户端传过来的FIN报文的时候,仅仅代表客户端不再发送数据了,当时还是可以接收到数据的;而且服务端也未必已经全部将数据发送到了客户端,这个时候可以再将未发送完全的数据继续发送,再发送FIN给客户端表示可以关闭连接。服务端的ACK和FIN一般是分开发送;</li>
</ul>
]]></content>
<categories>
<category> -Java基础 -计算机网络 </category>
</categories>
<tags>
<tag> TCP </tag>
<tag> 三次握手,四次挥手 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java集合(二)——LinkedList的源码解读]]></title>
<url>/2018/09/20/2018-9-20-10-38-49/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>本文为序列文章:</p>
<ul>
<li><p><a href="http://www.bianxiaofeng.com/2018/09/17/2018-9-17-20-16-54/">Java集合(一)——ArrayList的源码解读</a></p>
</li>
<li><p><a href="http://www.bianxiaofeng.com/2018/09/20/2018-9-20-10-38-49/">Java集合(二)——LinkedList的源码解读</a></p>
</li>
</ul>
<p>对于Java中的集合,大致可以分为Set、List、Queue和Map,其中Set是不重复且无序的集合,List是有序,可重复的集合,而Map则代表的是具有映射关系的集合,Java5后增加了Queue集合,代表一种队列集合的实现。<br><a id="more"></a><br>本文主要介绍总结List集合。List是一个有序(插入有序)的Collection(序列),可以包含重复的元素。</p>
<p>List是实现了Collection接口的,所以实现了Collection的方法:</p>
<p><strong>Collection的方法:</strong></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917203606-2018917.png" alt="QQ截图20180917203606-2018917"></p>
<p><strong>List中的方法</strong></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917203750-2018917.png" alt="QQ截图20180917203750-2018917"></p>
<p>操作总结:</p>
<ul>
<li>位置访问:基于元素的位置来操作元素:如get、set、add、remove等;</li>
<li>搜索:从List中搜索指定的位置,并且返回其位置的索引:如indexOf等;</li>
<li>迭代:Collection继承自Iterable,由于继承的传递性,可以通过Iterable来实现一些遍历操作。listIteratorf方法返回迭代器用于迭代;</li>
</ul>
<p>Java中的有两种常见的List的实现:<strong>ArrayList</strong>、<strong>LinkedList</strong>;</p>
<h1 id="LinkedList"><a href="#LinkedList" class="headerlink" title="LinkedList"></a>LinkedList</h1><p>我们知道ArrayList底层是以动态数组的方式实现的,在遍历的时候直接修改的是数组下标,没有其他额外的空间消耗,但是在插入,删除的时候,都需要进行移动,即数组的拷贝,效率略差。</p>
<p>当时LinkedList的底层是以链表的方式进行实现,插入和删除的时候只需要改变pre和next节点的指向,在插入和删除的时候效率较高。</p>
<h2 id="LinkedList实现"><a href="#LinkedList实现" class="headerlink" title="LinkedList实现"></a>LinkedList实现</h2><h3 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h3><p>LinkedList有两个构造函数:</p>
<p>默认的无参构造器:</p>
<ul>
<li>public LinkedList()</li>
</ul>
<p>以集合为参数的有参构造器:</p>
<ul>
<li>public LinkedList(Collection<? extends E> c)<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919151947-2018919.png" alt="QQ截图20180919151947-2018919"><br>调用addAll()方法进行初始化。<br>其中allALL方法如下:<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919155330-2018919.png" alt="QQ截图20180919155330-2018919"><br>这个 函数的解释如下:<br>首先检查index是否合法,如果是初始化的话,那么这个index=size=0,使用Collection接口的方法toArray将Collection转为数组。接下来的if判断,作用是保存pred和succ两个变量,你想呀,在进行插入的时候,肯定要得到具体的位置呀,具体的位置就是前后嘛。接下来一个for循环,将循环将数组的元素转为node结构,然后挂到链表上。</li>
</ul>
<h3 id="存储"><a href="#存储" class="headerlink" title="存储"></a>存储</h3><p>对于LinkedList,在底层是采用Node的方式进行存储,Node是定义在LinkedList内部的内部类:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919152453-2018919.png" alt="QQ截图20180919152453-2018919"></p>
<p>仅有一个有参构造器,其中第一个参数是前置节点,第二个参数是需要插入的元素,第三个是后置节点。</p>
<p>对于LinkedList来说,有以下几种插入数据的方式:</p>
<p>在链表的最后一个位置插入元素:</p>
<ul>
<li>public boolean add(E e)<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919152222-2018919.png" alt="QQ截图20180919152222-2018919"></li>
</ul>
<p>其中使用到了一个linkLast函数将该元素链接到链表的最后面:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919152759-2018919.png" alt="QQ截图20180919152759-2018919"></p>
<p>注意到是创建了一个Node实例,last是使用transient关键字修饰了的,保证了进程之间的可见性。然后是将新节点链接到原链表的最后一个节点上,size也是使用transient关键字修饰了的,size代表的是链表的长度。modCount的 作用如上,保证迭代的准确性,使用的是Fail-Fast机制。</p>
<p>在链表的指定位置插入元素</p>
<ul>
<li>public void add(int index, E element)</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919153434-2018919.png" alt="QQ截图20180919153434-2018919"></p>
<p>这里首先会对这个index进行合法性校验,如果这个index等于size,那么就证明是在链表的最后一个位置插入element(linklast方法见上),如果不是,就是在这个index之前插入element。</p>
<p>这里看下node(index)这个函数,如下:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919153804-2018919.png" alt="QQ截图20180919153804-2018919"></p>
<p>这个函数首先做了一个判断,(size>>1)是位运算,表示的是size/2。<br>如果是小于size/2的,表示在链表的前半截;然后使用x=x.next进行遍历。else方法同理,最终返回node;</p>
<p>对于LinkedBefore函数:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919151947-2018919.png" alt="QQ截图20180919151947-2018919"></p>
<p>首先找到我们刚才通过index查询到的node的前置节点保存起来,将这个node的前置节点改为新的element,这样就完成了新节点和其之后的节点链接。</p>
<p>然后需要将后面的链表和前面的链表链接起来。这个时候分为两种情况了,这个时候就体现了我们之前记录下node的前置节点的作用了。如果这个node本来就是头结点了,那么需要在LinkedList中修改first节点的值。如果不是,那么就直接将node的next和新节点连接起来,这样就完成了插入工作。</p>
<ul>
<li>public boolean addAll(Collection<? extends E> c)</li>
<li>public boolean addAll(int index, Collection<? extends E> c)<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919154932-2018919.png" alt="QQ截图20180919154932-2018919"></li>
</ul>
<p>这两个合在一起,public boolean addAll(Collection<? extends E> c)这个是调用的public boolean addAll(int index, Collection<? extends E> c)方法。而这个方法在有参构造器中有用到,在那里有讲解。</p>
<h3 id="读取"><a href="#读取" class="headerlink" title="读取"></a>读取</h3><p>对于链表的遍历的效率不高,尽管在遍历的时候会采用到除以二以判断从头开始遍历还是从尾开始遍历的方法。</p>
<p>LInkedList获取元素有以下几种方式</p>
<ul>
<li>public E get(int index)</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919160316-2018919.png" alt="QQ截图20180919160316-2018919"></p>
<p>获取链表的第一个元素</p>
<ul>
<li>public E getFirst()<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919160349-2018919.png" alt="QQ截图20180919160349-2018919"></li>
</ul>
<p>有获取第一个元素,那么也有获取最后一个元素</p>
<ul>
<li>public E getLast()<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919160637-2018919.png" alt="QQ截图20180919160637-2018919"></li>
</ul>
<p>获取元素在链表中的位置</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919161008-2018919.png" alt="QQ截图20180919161008-2018919"></p>
<h3 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h3><ul>
<li>public E remove()<br>删除第一个元素</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919161438-2018919.png" alt="QQ截图20180919161438-2018919"></p>
<ul>
<li><p>public E remove(int index)<br>删除index位置的元素</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919161627-2018919.png" alt="QQ截图20180919161627-2018919"></p>
</li>
<li><p>public boolean remove(Object o)<br>删除第一个出现o的位置的元素</p>
</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919161748-2018919.png" alt="QQ截图20180919161748-2018919"></p>
<ul>
<li>public boolean removeFirstOccurrence(Object o)</li>
<li>public boolean removeLastOccurrence(Object o)</li>
</ul>
<p>分别移除第一次或者最后一次出现在链表中的元素</p>
<h3 id="修改"><a href="#修改" class="headerlink" title="修改"></a>修改</h3><ul>
<li>public E set(int index, E element)</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180919162219-2018919.png" alt="QQ截图20180919162219-2018919"></p>
<p>将index位置的原element设置为新的element</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><h2 id="LinkedList-1"><a href="#LinkedList-1" class="headerlink" title="LinkedList"></a>LinkedList</h2><ul>
<li>基于双端链表,添加/删除元素只会影响周围的两个节点,开销很低;</li>
<li>只能顺序遍历,无法按照索引获得元素,因此查询效率不高;</li>
<li>没有固定容量,不需要扩容;</li>
<li>需要更多的内存,每个节点中需要多存储前后节点的信息,占用空间更多些。</li>
</ul>
]]></content>
<categories>
<category> Java基础 </category>
<category> 集合 </category>
</categories>
<tags>
<tag> List </tag>
<tag> Map </tag>
<tag> Set </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java集合(一)——ArrayList的源码解读]]></title>
<url>/2018/09/17/2018-9-17-20-16-54/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>本文为序列文章:</p>
<ul>
<li><p><a href="http://www.bianxiaofeng.com/2018/09/17/2018-9-17-20-16-54/">Java集合(一)——Java集合(一)——ArrayList的源码解读</a></p>
</li>
<li><p><a href="http://www.bianxiaofeng.com/2018/09/20/2018-9-20-10-38-49/">Java集合(二)——LinkedList的源码解读</a></p>
</li>
</ul>
<p>对于Java中的集合,大致可以分为Set、List、Queue和Map,其中Set是不重复且无序的集合,List是有序,可重复的集合,而Map则代表的是具有映射关系的集合,Java5后增加了Queue集合,代表一种队列集合的实现。<br><a id="more"></a><br>本文主要介绍总结List集合。List是一个有序(插入有序)的Collection(序列),可以包含重复的元素。</p>
<p>List是实现了Collection接口的,所以实现了Collection的方法:</p>
<p><strong>Collection的方法:</strong></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917203606-2018917.png" alt="QQ截图20180917203606-2018917"></p>
<p><strong>List中的方法</strong></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917203750-2018917.png" alt="QQ截图20180917203750-2018917"></p>
<p>操作总结:</p>
<ul>
<li>位置访问:基于元素的位置来操作元素:如get、set、add、remove等;</li>
<li>搜索:从List中搜索指定的位置,并且返回其位置的索引:如indexOf等;</li>
<li>迭代:Collection继承自Iterable,由于继承的传递性,可以通过Iterable来实现一些遍历操作。listIteratorf方法返回迭代器用于迭代;</li>
</ul>
<p>Java中的有两种常见的List的实现:<strong>ArrayList</strong>、<strong>LinkedList</strong>;</p>
<p>本文主要介绍ArrayList</p>
<h1 id="ArrayList"><a href="#ArrayList" class="headerlink" title="ArrayList"></a>ArrayList</h1><p>ArrayList是基于数组实现的,因为每次add的时候都会去检查容量,自动扩容,那么也可以说是动态扩容的。每个ArrayList实例都有一个变量,用来指向当前List的大小,这个变量就是size。</p>
<p>随着往ArrayList中添加数据的时候,其容量也会自动增加,自动增加会带来数组的拷贝,拷贝会带来额外的空间消耗,那么怎么增加就是一个值得思考的问题了,</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917205342-2018917.png" alt="QQ截图20180917205342-2018917"></p>
<p>如图所示,这里是增加为原来的1.5倍。>>是位操作,表示除以2;</p>
<h2 id="ArrayList的实现"><a href="#ArrayList的实现" class="headerlink" title="ArrayList的实现"></a>ArrayList的实现</h2><p>ArrayList内部是基于数组实现的:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917205541-2018917.png" alt="QQ截图20180917205541-2018917"></p>
<h3 id="构造方法"><a href="#构造方法" class="headerlink" title="构造方法"></a>构造方法</h3><ul>
<li>根据传入的initialCapacity构造一个空的list</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917205731-2018917.png" alt="QQ截图20180917205731-2018917"></p>
<ul>
<li>默认初始化容量为10的list</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917205738-2018917.png" alt="QQ截图20180917205738-2018917"></p>
<p>ps:这里看不到是默认初始化容量为10的,因为这里的DEFALUTCAPACITY_EMPTY_ELEMENTDATA是一个空的数组,如下:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917210431-2018917.png" alt="QQ截图20180917210431-2018917"></p>
<p>那么这个构造器的注释说的是初始化为10的容量的数组是在哪实现的呢?</p>
<p>对List的操作需要首先往里面填充数据,那么当填充数据的时候,也就是add方法中,首先会检查容量,ensureCapacityInternal,传入的值为当前的size+1,</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917210723-2018917.png" alt="QQ截图20180917210723-2018917"></p>
<p>随后是这个方法,在这个方法中,如果判断为当前ArrayList底层维护的数组为一个默认的空的数组,就会使用DEFAULT_CAPACITY初始化这个数组。</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917210749-2018917.png" alt="QQ截图20180917210749-2018917"><br>这就是默认初始化为10的出处。</p>
<ul>
<li>使用一个Collection集合进行初始化,实际上是调用了Arrays工具类的Copyof方法。</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917205745-2018917.png" alt="QQ截图20180917205745-2018917"></p>
<h3 id="存储"><a href="#存储" class="headerlink" title="存储"></a>存储</h3><p>ArrayList提供了如下方法来进行元素的添加:</p>
<ul>
<li>public E set(int index, E element);使用指定的元素替换掉目标位置的元素</li>
</ul>
<p>首先是边界检查,然后保存原来的位置元素,然后替换,最后返回原来位置的元素。</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917211508-2018917.png" alt="QQ截图20180917211508-2018917"></p>
<ul>
<li>public boolean add(E e);在底层维护的数组的最后添加一个元素e</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917211649-2018917.png" alt="QQ截图20180917211649-2018917"></p>
<ul>
<li>public void add(int index, E element); 在底层维护的数组的指定位置添加一个元素,如果该位置的后面还有元素,调用arrayCopy方法进行后移操作。</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917211733-2018917.png" alt="QQ截图20180917211733-2018917"></p>
<ul>
<li>public boolean addAll(Collection<? extends E> c);在Arraylist底层维护的数组的最后一个位置追加传入的集合。</li>
</ul>
<p>还是调用的System.arrayCopy方法进行数组的扩充。</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917212017-2018917.png" alt="QQ截图20180917212017-2018917"></p>
<ul>
<li>public boolean addAll(int index, Collection<? extends E> c);在数组的指定位置插入传入的集合,然后原集合index之后的数向后移动。</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917212155-2018917.png" alt="QQ截图20180917212155-2018917"></p>
<p>这里对System的arrayCopy说明一下:<br>语法如下:<br><figure class="highlight plain"><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">public static void arraycopy(Object src,</span><br><span class="line"> int srcPos,</span><br><span class="line"> Object dest,</span><br><span class="line"> int destPos,</span><br><span class="line"> int length)</span><br></pre></td></tr></table></figure></p>
<p>示例如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">System.arraycopy(a, 0, elementData, size, numNew);</span><br></pre></td></tr></table></figure>
<p>表示的是将a数组从下标为0开始的数复制到elementData的size位置,复制numNew个数。</p>
<h3 id="读取"><a href="#读取" class="headerlink" title="读取"></a>读取</h3><p>返回index位置的元素</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917213428-2018917.png" alt="QQ截图20180917213428-2018917"></p>
<h3 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h3><p>ArrayList提供了以下几种删除的方式</p>
<ul>
<li><p>public E remove(int index);<br>删除指定位置的元素<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917213739-2018917.png" alt="QQ截图20180917213739-2018917"></p>
</li>
<li><p>public boolean remove(Object o);<br>删除第一个出现o的位置的元素,如果ArrayList中没有这个元素o,那么什么都不会改变返回false</p>
</li>
</ul>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917213824-2018917.png" alt="QQ截图20180917213824-2018917"></p>
<p>这里的fastRemove的实现原理是直接进行数组的拷贝进行覆盖。</p>
<ul>
<li>public void clear()<br>直接清空数组,循环赋值为null,size=0<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917214012-2018917.png" alt="QQ截图20180917214012-2018917"></li>
</ul>
<h3 id="扩容"><a href="#扩容" class="headerlink" title="扩容"></a>扩容</h3><p>在进行数组的存储中,我们会遇到ensureCapacityInternal方法,该方法可以检查当前是否有足够的空间进行扩容,扩容是调用grow方法:<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917214528-2018917.png" alt="QQ截图20180917214528-2018917"><br>该方法会将当前的数组的大小扩大为原来的1.5倍,然后调用Arrays的copyOf方法进行扩容,这种操作消耗的空间是比较大的,为此,ArrayList还提供了一个public的方法ensureCapacit允许开发者进行手动的进行扩容。<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917214853-2018917.png" alt="QQ截图20180917214853-2018917"></p>
<p>总结:<br>对于数组的扩容来说,消耗的成本是比较大的,所以,我们在使用ArrayList的时候,建议根据实际情况调用构造进行初始化数组,或者根据实际情况调用ensureCapacity方法进行手动扩容操作,减少内存开销。</p>
<p>当开发者将数组进行扩容,当时并没有用到那么多的空间的时候,一般会采用trimToSize方法进行调整:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180917215235-2018917.png" alt="QQ截图20180917215235-2018917"></p>
<h3 id="Fail-Fast机制"><a href="#Fail-Fast机制" class="headerlink" title="Fail-Fast机制"></a>Fail-Fast机制</h3><p>ArrayList和HashMap一样是采用了Fail-Fast机制,通过记录modCount即操作次数,迭代器在进行操作的时候,如果发现,当前的modCount和自己保存的不一致的时候,那么就会ConcurrentModificationException,而不会冒在将来的不确定的时候出现的不确定行为的风险。</p>
<p>我们注意到<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">protected transient int modCount = 0;</span><br></pre></td></tr></table></figure></p>
<p>modCount是采用的transient修饰,保证不同进程之间的可见性;<br>迭代器的操作源码如下:</p>
<figure class="highlight plain"><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * An optimized version of AbstractList.Itr</span><br><span class="line"> 这是一个Arraylist 的内部类</span><br><span class="line"> */</span><br><span class="line"> private class Itr implements Iterator<E> {</span><br><span class="line"> int cursor; // index of next element to return</span><br><span class="line"> int lastRet = -1; // index of last element returned; -1 if no such</span><br><span class="line"> int expectedModCount = modCount;</span><br><span class="line"></span><br><span class="line"> Itr() {}</span><br><span class="line"></span><br><span class="line"> public boolean hasNext() {</span><br><span class="line"> return cursor != size;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @SuppressWarnings("unchecked")</span><br><span class="line"> public E next() {</span><br><span class="line"> checkForComodification();</span><br><span class="line"> int i = cursor;</span><br><span class="line"> if (i >= size)</span><br><span class="line"> throw new NoSuchElementException();</span><br><span class="line"> Object[] elementData = ArrayList.this.elementData;</span><br><span class="line"> if (i >= elementData.length)</span><br><span class="line"> throw new ConcurrentModificationException();</span><br><span class="line"> cursor = i + 1;</span><br><span class="line"> return (E) elementData[lastRet = i];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void remove() {</span><br><span class="line"> if (lastRet < 0)</span><br><span class="line"> throw new IllegalStateException();</span><br><span class="line"> checkForComodification();</span><br><span class="line"></span><br><span class="line"> try {</span><br><span class="line"> ArrayList.this.remove(lastRet);</span><br><span class="line"> cursor = lastRet;</span><br><span class="line"> lastRet = -1;</span><br><span class="line"> expectedModCount = modCount;</span><br><span class="line"> } catch (IndexOutOfBoundsException ex) {</span><br><span class="line"> throw new ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> @SuppressWarnings("unchecked")</span><br><span class="line"> public void forEachRemaining(Consumer<? super E> consumer) {</span><br><span class="line"> Objects.requireNonNull(consumer);</span><br><span class="line"> final int size = ArrayList.this.size;</span><br><span class="line"> int i = cursor;</span><br><span class="line"> if (i >= size) {</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"> final Object[] elementData = ArrayList.this.elementData;</span><br><span class="line"> if (i >= elementData.length) {</span><br><span class="line"> throw new ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line"> while (i != size && modCount == expectedModCount) {</span><br><span class="line"> consumer.accept((E) elementData[i++]);</span><br><span class="line"> }</span><br><span class="line"> // update once at end of iteration to reduce heap write traffic</span><br><span class="line"> cursor = i;</span><br><span class="line"> lastRet = i - 1;</span><br><span class="line"> checkForComodification();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> final void checkForComodification() {</span><br><span class="line"> if (modCount != expectedModCount)</span><br><span class="line"> throw new ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p> 注意,迭代器的快速失败行为不能得到保证,一般来说,存在非同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的做法是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><h2 id="ArrayList-1"><a href="#ArrayList-1" class="headerlink" title="ArrayList"></a>ArrayList</h2><ul>
<li>基于数组,在数组中搜索和读取数据是很快的。因此 ArrayList 获取数据的时间复杂度是O(1);</li>
<li>添加、删除时该元素后面的所有元素都要移动,所以添加/删除数据效率不高。</li>
</ul>
]]></content>
<categories>
<category> Java基础 </category>
<category> 集合 </category>
</categories>
<tags>
<tag> List </tag>
<tag> Map </tag>
<tag> Set </tag>
</tags>
</entry>
<entry>
<title><![CDATA[常见排序算法总结(归并排序)——Java语言(二)]]></title>
<url>/2018/09/13/2018-9-13-16-36-10/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><blockquote>
<p>归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为 O(NlogN)(大O符号)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。<br><a id="more"></a><br>归并排序的图示:</p>
</blockquote>
<p><img src="http://p2sj58chj.bkt.clouddn.com/Merge_sort_animation2-2018913.gif" alt="Merge_sort_animation2-2018913"></p>
<h1 id="算法讲解"><a href="#算法讲解" class="headerlink" title="算法讲解"></a>算法讲解</h1><p>归并排序算法是采用经典的分治策略,将问题divide成一些小问题,然后在conquer阶段将分的阶段得到的答案修补在一起,即为分而治之。</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180914111850-2018914.png" alt="QQ截图20180914111850-2018914"></p>
<p>任何的递归都可以采用迭代来实现,递归行为实质上是压栈和出栈的过程。</p>
<h1 id="算法实例"><a href="#算法实例" class="headerlink" title="算法实例"></a>算法实例</h1><p>算法流程:</p>
<ul>
<li>对待排序数组array进行拆分,即分治思想中的分。</li>
<li>将array分为两组之后进行排序,保证子序列有序。在保证子序列有序的过程中还会递归上一步骤,直到left==right的时候。</li>
</ul>
<figure class="highlight plain"><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 传入参数合法性校验,然后调用归并排序的方法</span><br><span class="line"> *</span><br><span class="line"> * @param array 目标数组</span><br><span class="line"> */</span><br><span class="line">public static void mergeSort(int array[]) {</span><br><span class="line"> if (array == null || array.length < 2) {</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"> sort(array, 0, array.length - 1);</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><br><span class="line"> * @param array</span><br><span class="line"> * @param left</span><br><span class="line"> * @param right</span><br><span class="line"> */</span><br><span class="line">private static void sort(int[] array, int left, int right) {</span><br><span class="line"> //递归终止条件</span><br><span class="line"> if (left == right) {</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"> int mid = left + ((right - left) >> 1);</span><br><span class="line"> sort(array, left, mid);</span><br><span class="line"> sort(array, mid + 1, right);</span><br><span class="line"> //归并</span><br><span class="line"> merge(array, left, right);</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><br><span class="line"> * @param array</span><br><span class="line"> * @param left</span><br><span class="line"> * @param right</span><br><span class="line"> */</span><br><span class="line">private static void merge(int[] array, int left, int right) {</span><br><span class="line"> int mid = left + ((right - left) >> 1);//防止因为left和right太大导致的integer越界,相当于left+(right-left)/2</span><br><span class="line"> int[] help = new int[right - left + 1];//建立辅助数组</span><br><span class="line"> int i = 0;</span><br><span class="line"> int p1 = left;//p1指向left的数组第一个</span><br><span class="line"> int p2 = mid + 1;//p2指向right数组的第一个</span><br><span class="line"> while (p1 <= mid && p2 <= right) {</span><br><span class="line"> //比较,谁小填入辅助数组</span><br><span class="line"> help[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];</span><br><span class="line"> }</span><br><span class="line"> //上面的while循环结束,当且只当p1和p2有一个越界,下面的两个while是将剩下的数组数据填到辅助数组</span><br><span class="line"> while (p1 <= mid) {</span><br><span class="line"> help[i++] = array[p1++];</span><br><span class="line"> }</span><br><span class="line"> while (p2 <= right) {</span><br><span class="line"> help[i++] = array[p2++];</span><br><span class="line"> }</span><br><span class="line"> //数据回填,将辅助数组的数据回填到原数组</span><br><span class="line"> for (i = 0; i < help.length; i++) {</span><br><span class="line"> array[left + i] = help[i];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>时间复杂度分析:</p>
<p>递归行为可以采用master公式:</p>
<p>T(N)=a*T(N/b)+O(N^d)</p>
<p>以上算法针对的是对于一个数据,可以分为b个部分进行处理。<br><figure class="highlight plain"><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><br><span class="line">1) log(b,a) > d -> 复杂度为O(N^log(b,a))</span><br><span class="line">2) log(b,a) = d -> 复杂度为O(N^d * logN)</span><br><span class="line">3) log(b,a) < d -> 复杂度为O(N^d)</span><br></pre></td></tr></table></figure></p>
<p>对于归并来说,可以看做是将一个数据分为两部分来进行处理。</p>
<p>这里的公式为:</p>
<figure class="highlight plain"><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><br><span class="line">```d=1,log(b,a)=1```,那么这个时间复杂度为</span><br><span class="line"></span><br><span class="line">```T(N)=NlogN</span><br></pre></td></tr></table></figure>
<p>关于master公式:www.gocalf.com/blog/algorithm-complexity-and-mastertheorem.html</p>
]]></content>
<categories>
<category> Java基础 </category>
</categories>
<tags>
<tag> 归并排序 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[MySQL复习(一)]]></title>
<url>/2018/09/07/2018-9-7-21-12-48/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近准备将自己所学的知识好好的复习一遍,看到了MySQL,对于MySQL,很多东西还是停留在知识点,实际应用还是差一大截,刚好是在网上看到一篇博文,本文主要是根据这篇博文,加上一些关于MySQL的知识点交叉串起来,方便自己复习。</p>
<h1 id="常见的MySQL操作的命令大全"><a href="#常见的MySQL操作的命令大全" class="headerlink" title="常见的MySQL操作的命令大全"></a>常见的MySQL操作的命令大全</h1><p>以下是一些比较常用的MySQL的操作命令,并非查询语句。当然可以使用一些可视化的工具来代替这些命令,比如比较好用的Navicat,这里使用的是IDEA自带的database工具。<br><a id="more"></a><br>命令如下:</p>
<figure class="highlight plain"><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"># 创建名为mysqlpractice的数据库</span><br><span class="line">create database mysqlpractice;</span><br><span class="line"></span><br><span class="line"># 显示所有的数据库</span><br><span class="line">show databases;</span><br><span class="line"></span><br><span class="line"># 删除数据库mysqlpractice</span><br><span class="line">drop database mysqlpractice;</span><br><span class="line"># 一般会在删除之前进行判断,判断是否存在该数据库,如果对不存在的数据库进行删除会报错,对表的删除同理。</span><br><span class="line">drop database if exists mysqlpractice;</span><br><span class="line"></span><br><span class="line"># 选择名为mysqlpractice的数据库,只有选择了某个数据库,才能对数据库中的表进行操作</span><br><span class="line">use mysqlpractice;</span><br><span class="line"></span><br><span class="line">#显示当前数据库下的course表的字段信息,以下两种方式均可</span><br><span class="line">show columns from course;</span><br><span class="line">describe course;</span><br><span class="line"></span><br><span class="line"># 显示创建数据库的mysql语句</span><br><span class="line">show create database mysqlpractice;</span><br><span class="line"></span><br><span class="line"># 显示创建表的sql语句</span><br><span class="line">show create table course;</span><br><span class="line"></span><br><span class="line"># 删除表</span><br><span class="line">drop table course;</span><br><span class="line">#一般会在删除数据库表之前进行判断,如果存在就进行删除</span><br><span class="line">drop table if exists course;</span><br><span class="line"></span><br><span class="line"># 删除表中的数据,不删除表delete方式</span><br><span class="line">delete</span><br><span class="line">from course;</span><br><span class="line"># 删除表中的数据,不删除表truncate方式</span><br><span class="line">truncate table course;</span><br><span class="line"></span><br><span class="line"># 以上两种方式都可以删除表中的数据,但是还是由区别的</span><br><span class="line"># 1、truncate是不可以rollback的,delete可以rollback。</span><br><span class="line"># 2、truncate删除后会重置索引(自增类型的id会从0开始),而delete不会删除索引。</span><br><span class="line"># 3、delete可以返回受影响的行数,且delete可以按照条件删除。</span><br><span class="line"># 4、truncate不会触发任何的delete触发器。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 表结构的修改</span><br><span class="line">## 增加一个字段int类型的test1</span><br><span class="line">alter table course</span><br><span class="line"> add column (test1 int);</span><br><span class="line"></span><br><span class="line">## 指定字段test1之后插入一个int类型的字段test2</span><br><span class="line">## 需要和上面一个命令区别开来,上面的命令是必须要带括号的,下面这个命令是不能带括号的</span><br><span class="line">alter table course</span><br><span class="line"> add column test2 int</span><br><span class="line"> after test1;</span><br><span class="line"></span><br><span class="line">## 删除一个test1字段</span><br><span class="line">alter table course</span><br><span class="line"> drop test1;</span><br><span class="line"></span><br><span class="line">## 修改字段的名称test1为newtest1,类型为char</span><br><span class="line"></span><br><span class="line">alter table course</span><br><span class="line"> change test1 newtest1 char(32);</span><br><span class="line"></span><br><span class="line">## 修改表的名字,将course表的名称修改为newCourse</span><br><span class="line"></span><br><span class="line">alter table course</span><br><span class="line">rename to newCourse;</span><br></pre></td></tr></table></figure>
<h1 id="学生-课程-教师-成绩SQL练习题"><a href="#学生-课程-教师-成绩SQL练习题" class="headerlink" title="学生-课程-教师-成绩SQL练习题"></a>学生-课程-教师-成绩SQL练习题</h1><h2 id="表的架构"><a href="#表的架构" class="headerlink" title="表的架构"></a>表的架构</h2><p>ps:</p>
<p>原文是采用的S#这种写法来表示id的,在navicat以及idea自带的一些插件中是不能识别的,所以以下全部改为sno这种形式。</p>
<h3 id="Student表"><a href="#Student表" class="headerlink" title="Student表"></a>Student表</h3><p>Student表具有学号sno,学生姓名sname,年龄sage以及性别ssex。</p>
<figure class="highlight plain"><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">-- auto-generated definition</span><br><span class="line">create table student</span><br><span class="line">(</span><br><span class="line"> sno int null,</span><br><span class="line"> sname varchar(32) null,</span><br><span class="line"> sage int null,</span><br><span class="line"> ssex varchar(8) null</span><br><span class="line">);</span><br></pre></td></tr></table></figure>
<p>对于Student表插入的测试数据如下:</p>
<figure class="highlight plain"><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">insert into Student</span><br><span class="line">select 1, N'刘一', 18, N'男'</span><br><span class="line">union all</span><br><span class="line">select 2, N'钱二', 19, N'女'</span><br><span class="line">union all</span><br><span class="line">select 3, N'张三', 17, N'男'</span><br><span class="line">union all</span><br><span class="line">select 4, N'李四', 18, N'女'</span><br><span class="line">union all</span><br><span class="line">select 5, N'王五', 17, N'男'</span><br><span class="line">union all</span><br><span class="line">select 6, N'赵六', 19, N'女';</span><br></pre></td></tr></table></figure>
<p>插入6条学生数据信息,数据显示如下: </p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908114254-201898.png" alt="QQ截图20180908114254-201898"></p>
<h3 id="course表"><a href="#course表" class="headerlink" title="course表"></a>course表</h3><p>course有三个属性,分别是课程的编号,课程的名称,以及该课程的老师id<br>创表语句:<br><figure class="highlight plain"><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">CREATE TABLE course</span><br><span class="line">(</span><br><span class="line"> cno INT,</span><br><span class="line"> cname nvarchar(32),</span><br><span class="line"> tno INT</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<p>插入数据如下:<br><figure class="highlight plain"><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">insert into Course</span><br><span class="line">select 1, N'语文', 1</span><br><span class="line">union all</span><br><span class="line">select 2, N'数学', 2</span><br><span class="line">union all</span><br><span class="line">select 3, N'英语', 3</span><br><span class="line">union all</span><br><span class="line">select 4, N'物理', 4;</span><br></pre></td></tr></table></figure></p>
<p>数据插入完成后的表如下:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908115655-201898.png" alt="QQ截图20180908115655-201898"></p>
<h3 id="Teacher表"><a href="#Teacher表" class="headerlink" title="Teacher表"></a>Teacher表</h3><p>创表语句如下:<br><figure class="highlight plain"><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">create table teacher</span><br><span class="line">(</span><br><span class="line"> tno int null,</span><br><span class="line"> tname varchar(16) null</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<p>向表中插入数据:<br><figure class="highlight plain"><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">insert into Teacher</span><br><span class="line">select 1, N'叶平'</span><br><span class="line">union all</span><br><span class="line">select 2, N'贺高'</span><br><span class="line">union all</span><br><span class="line">select 3, N'杨艳'</span><br><span class="line">union all</span><br><span class="line">select 4, N'周磊';</span><br></pre></td></tr></table></figure></p>
<p>教师表创建完成后的表如下:<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908115853-201898.png" alt="QQ截图20180908115853-201898"></p>
<h3 id="sc表-成绩、课程及学生的关联表"><a href="#sc表-成绩、课程及学生的关联表" class="headerlink" title="sc表-成绩、课程及学生的关联表"></a>sc表-成绩、课程及学生的关联表</h3><p>创建表的语句如下:<br><figure class="highlight plain"><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">-- auto-generated definition</span><br><span class="line">create table sc</span><br><span class="line">(</span><br><span class="line"> sno int null,</span><br><span class="line"> cno int null,</span><br><span class="line"> score int null</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<p>插入测试数据:<br><figure class="highlight plain"><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">insert into SC</span><br><span class="line">select 1, 1, 56</span><br><span class="line">union all</span><br><span class="line">select 1, 2, 78</span><br><span class="line">union all</span><br><span class="line">select 1, 3, 67</span><br><span class="line">union all</span><br><span class="line">select 1, 4, 58</span><br><span class="line">union all</span><br><span class="line">select 2, 1, 79</span><br><span class="line">union all</span><br><span class="line">select 2, 2, 81</span><br><span class="line">union all</span><br><span class="line">select 2, 3, 92</span><br><span class="line">union all</span><br><span class="line">select 2, 4, 68</span><br><span class="line">union all</span><br><span class="line">select 3, 1, 91</span><br><span class="line">union all</span><br><span class="line">select 3, 2, 47</span><br><span class="line">union all</span><br><span class="line">select 3, 3, 88</span><br><span class="line">union all</span><br><span class="line">select 3, 4, 56</span><br><span class="line">union all</span><br><span class="line">select 4, 2, 88</span><br><span class="line">union all</span><br><span class="line">select 4, 3, 90</span><br><span class="line">union all</span><br><span class="line">select 4, 4, 93</span><br><span class="line">union all</span><br><span class="line">select 5, 1, 46</span><br><span class="line">union all</span><br><span class="line">select 5, 3, 78</span><br><span class="line">union all</span><br><span class="line">select 5, 4, 53</span><br><span class="line">union all</span><br><span class="line">select 6, 1, 35</span><br><span class="line">union all</span><br><span class="line">select 6, 2, 68</span><br><span class="line">union all</span><br><span class="line">select 6, 4, 71;</span><br></pre></td></tr></table></figure></p>
<p>插入完成后的数据如下:<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908120101-201898.png" alt="QQ截图20180908120101-201898"></p>
<h2 id="SQL练习题"><a href="#SQL练习题" class="headerlink" title="SQL练习题"></a>SQL练习题</h2><p>1、查询课程号为1比课程号为2的成绩高的所有学生的学号:<br>解决思路:<br> 使用两个子表,一个字表装课程号为1的信息,一个表装课程号为2的信息。<br><figure class="highlight plain"><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">SELECT</span><br><span class="line"> a.sno </span><br><span class="line">FROM</span><br><span class="line"> ( SELECT sno, score FROM sc WHERE cno = '1' ) a,</span><br><span class="line"> ( SELECT sno, score FROM sc WHERE cno = '2' ) b </span><br><span class="line">WHERE</span><br><span class="line"> a.score > b.score </span><br><span class="line"> AND a.sno = b.sno;</span><br></pre></td></tr></table></figure></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908171025-201898.png" alt="QQ截图20180908171025-201898"><br>2、查询平均成绩大于60分的同学的学号和平均成绩:<br>解决思路:<br> 使用group by 将数据按照学号sno进行分组,这样就能和聚合函数avg一起,算出平均分,再使用having将得到的数据进行筛选。<br><figure class="highlight plain"><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">SELECT</span><br><span class="line"> sno,</span><br><span class="line"> avg( score ) </span><br><span class="line">FROM</span><br><span class="line"> sc </span><br><span class="line">GROUP BY</span><br><span class="line"> sno </span><br><span class="line">HAVING</span><br><span class="line"> avg( score ) > 60;</span><br></pre></td></tr></table></figure></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908170644-201898.png" alt="QQ截图20180908170644-201898"></p>
<p>3、查询所有同学的学号、姓名、选课数、总成绩:</p>
<p>解决思路:<br> 因为需要对每一个同学进行单独处理,所以一定要用到分组,所以group by 是必须的,选课数和总成绩这些就需要拥挤聚合函数。</p>
<figure class="highlight plain"><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">SELECT</span><br><span class="line"> student.sno,</span><br><span class="line"> student.sname,</span><br><span class="line"> count( sc.sno ),</span><br><span class="line"> sum( score ) </span><br><span class="line">FROM</span><br><span class="line"> student</span><br><span class="line"> LEFT JOIN sc ON student.sno = sc.sno </span><br><span class="line">GROUP BY</span><br><span class="line"> student.sno</span><br></pre></td></tr></table></figure>
<p>结果如图:<br><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908170614-201898.png" alt="QQ截图20180908170614-201898"></p>
<p>4、查询姓“李”的老师的个数:</p>
<p>解决思路:</p>
<p>使用聚合函数count,需要注意的是需要对结果进行distinct处理。</p>
<figure class="highlight plain"><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">SELECT</span><br><span class="line"> count( DISTINCT ( tname ) ) </span><br><span class="line">FROM</span><br><span class="line"> teacher </span><br><span class="line">WHERE</span><br><span class="line"> tname LIKE '李%'</span><br></pre></td></tr></table></figure>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908171738-201898.png" alt="QQ截图20180908171738-201898"></p>
<p>5、查询没有学过”叶平”老师课的同学学号,姓名:</p>
<p>解决思路:<br> 首先找出所有选修的叶平老师的学生的学号,这个可以通过sc表来进行查找。然后从student表中找出学号不在上面表中的学号。</p>
<figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">SELECT</span><br><span class="line"> student.sno,</span><br><span class="line"> student.sname </span><br><span class="line">FROM</span><br><span class="line"> student </span><br><span class="line">WHERE</span><br><span class="line"> student.sno NOT IN (</span><br><span class="line"> SELECT</span><br><span class="line"> sno </span><br><span class="line"> FROM</span><br><span class="line"> sc,</span><br><span class="line"> teacher,</span><br><span class="line"> course </span><br><span class="line"> WHERE</span><br><span class="line"> teacher.tname = "叶平" </span><br><span class="line"> AND teacher.tno = course.tno </span><br><span class="line"> AND course.cno = sc.cno </span><br><span class="line"> )</span><br></pre></td></tr></table></figure>
<p>结果如下:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180908175856-201898.png" alt="QQ截图20180908175856-201898"></p>
<p>6、查询学过课程号为1同时课程号为2的同学的学号、姓名:</p>
<p>关于exists的使用参看:<a href="https://www.cnblogs.com/V1haoge/p/6385312.html" target="_blank" rel="noopener">https://www.cnblogs.com/V1haoge/p/6385312.html</a><br><figure class="highlight plain"><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">SELECT</span><br><span class="line"> student.sno,</span><br><span class="line"> student.sname </span><br><span class="line">FROM</span><br><span class="line"> student,</span><br><span class="line"> sc </span><br><span class="line">WHERE</span><br><span class="line"> student.sno = sc.sno </span><br><span class="line"> AND sc.cno = "1" </span><br><span class="line"> AND EXISTS ( SELECT * FROM sc AS sc2 WHERE sc2.sno = sc.sno AND sc2.cno = "2" )</span><br></pre></td></tr></table></figure></p>
<p>7、查询学过“叶平”老师所教的课的同学的学号、姓名:</p>
<h1 id="鸣谢"><a href="#鸣谢" class="headerlink" title="鸣谢"></a>鸣谢</h1><p>本文主要是参考一些很优秀的博文,链接如下:</p>
<ul>
<li><a href="http://www.cnblogs.com/qixuejia/p/3637735.html" target="_blank" rel="noopener">sql面试题(学生表<em>课程表</em>成绩表_教师表)</a></li>
</ul>
<p><a href="https://www.cnblogs.com/shenqz/p/6962493.html" target="_blank" rel="noopener">https://www.cnblogs.com/shenqz/p/6962493.html</a></p>
]]></content>
</entry>
<entry>
<title><![CDATA[解决IDEA下的Terminal 乱码(unicode 编码)问题]]></title>
<url>/2018/09/05/2018-8-27-09-57-25/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在使用IDEA进行开发的时候,难免会用到Git,两个窗口切换来切换去的很不方便,为了简单,我将IDEA自带的Terminal设置为Git的,这样就能达到在IDEA上敲Git命令的效果。</p>
<p>这里简单的介绍下具体的配置流程以及使用Git会引起的Unicode的解决方案。</p>
<p>更多IDEA配置参看 <a href="http://www.bianxiaofeng.com/2018/07/23/2018-7-23-09-36-27/">Intellij IDEA 2018.02 最新版 优化配置</a><br><a id="more"></a></p>
<h1 id="配置IDEA使用Git的Terminal"><a href="#配置IDEA使用Git的Terminal" class="headerlink" title="配置IDEA使用Git的Terminal"></a>配置IDEA使用Git的Terminal</h1><p><img src="http://p2sj58chj.bkt.clouddn.com/QQ%E6%88%AA%E5%9B%BE20180827094225.png" alt="enter description here" title="IDEA配置Git Terminal"></p>
<h1 id="解决使用IDEA-Terminal引起的中文-Unicode编码问题"><a href="#解决使用IDEA-Terminal引起的中文-Unicode编码问题" class="headerlink" title="解决使用IDEA Terminal引起的中文 Unicode编码问题"></a>解决使用IDEA Terminal引起的中文 Unicode编码问题</h1><p> 乱码现象如下:</p>
<p> <img src="http://p2sj58chj.bkt.clouddn.com/QQ%E6%88%AA%E5%9B%BE20180827093139.png" alt="enter description here" title="乱码现象"></p>
<p>解决方案:</p>
<p>在Git的安装目录下的etc目录下bash.bashrc文件,在最后一行添加:</p>
<figure class="highlight stylus"><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"># 解决IDEA下的terminal中文Unicode编码问题</span><br><span class="line">export LANG=<span class="string">"zh_CN.UTF-8"</span></span><br><span class="line">export LC_ALL=<span class="string">"zh_CN.UTF-8"</span></span><br></pre></td></tr></table></figure>
<p>重启IDEA就可以了。</p>
]]></content>
<categories>
<category> Java基础 </category>
</categories>
<tags>
<tag> IDEA </tag>
<tag> Terminal </tag>
<tag> 乱码 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Git常用个人备份笔记]]></title>
<url>/2018/08/24/2018-8-24-10-00-54/</url>
<content type="html"><![CDATA[<h1 id="一、新建代码库"><a href="#一、新建代码库" class="headerlink" title="一、新建代码库"></a>一、新建代码库</h1><p>1、在当前目录下创建一个Git代码库<br><a id="more"></a><br><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git init</span></span><br></pre></td></tr></table></figure></p>
<p>创建的.git默认是隐藏的,使用命令ls -ah显示出来。</p>
<p>2、新建一个目录,并初始化为Git的代码库</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git init [<span class="keyword">dir</span>-name]</span><br></pre></td></tr></table></figure>
<p>3、克隆一个项目包括其提交历史</p>
<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">clone</span> <span class="title">[url</span>] [local-dir-name]</span><br></pre></td></tr></table></figure>
<h1 id="二、配置"><a href="#二、配置" class="headerlink" title="二、配置"></a>二、配置</h1><p>1、显示当前Git配置</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">config</span> <span class="comment">--list</span></span><br></pre></td></tr></table></figure>
<p>2、设置提交的时候的用户信息</p>
<figure class="highlight verilog"><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">git <span class="keyword">config</span> [--<span class="keyword">global</span>] user<span class="variable">.name</span> <span class="string">"username"</span></span><br><span class="line">git <span class="keyword">config</span> [--<span class="keyword">global</span>] user<span class="variable">.email</span> <span class="string">"email address"</span></span><br></pre></td></tr></table></figure>
<h1 id="三、增加删除文件"><a href="#三、增加删除文件" class="headerlink" title="三、增加删除文件"></a>三、增加删除文件</h1><p>1、添加指定文件到暂存区</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add <span class="comment">[file1]</span> <span class="comment">[file2]</span> ···</span><br></pre></td></tr></table></figure>
<p>2、添加指定目录到暂存区,包括子目录</p>
<figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">add </span>[<span class="keyword">dir </span>name]</span><br></pre></td></tr></table></figure>
<p>3、将当前目录下的所有文件到暂存区(包括当前目录下的已经修改的文件夹)</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">add</span> .</span><br></pre></td></tr></table></figure>
<p>4、删除工作区文件,并且将这次删除放入到暂存区</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rm <span class="comment">[file1]</span> <span class="comment">[file2]</span></span><br></pre></td></tr></table></figure>
<p>从版本库中找回rm的文件</p>
<figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout --[<span class="keyword">file</span>]</span><br></pre></td></tr></table></figure>
<p>5、停止追踪指定文件,但该文件会保留到工作区,文件内容不变。</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">rm</span> --cached [<span class="keyword">file</span>]</span><br></pre></td></tr></table></figure>
<h1 id="四、代码提交"><a href="#四、代码提交" class="headerlink" title="四、代码提交"></a>四、代码提交</h1><p>1、提交暂存区到版本库</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="comment">[message]</span></span><br></pre></td></tr></table></figure>
<p>2、提交暂存区的指定文件到仓库</p>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit [<span class="string">file1</span>][<span class="symbol">file2</span>]··· -m [message]</span><br></pre></td></tr></table></figure>
<p>3、提交工作区自上次commit之后的变化,直接到仓库区</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -a</span><br></pre></td></tr></table></figure>
<p>4、提交时显示所有的diff信息</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git commit -v</span></span><br></pre></td></tr></table></figure>
<p>5、使用一次新的commit,代替上一次提交;如果代码没有变化,就用来改写上一次的commit提交信息。commit的SHA1会发生改变,上一次的提交的内容不会发生改变。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">commit</span> <span class="comment">--amend -m [meesage]</span></span><br></pre></td></tr></table></figure>
<p>6、重做上一次的commit,并包括指定文件的新变化(此时不需要讲file1和file2添加到暂存区)</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit --amend <span class="comment">[file1]</span> <span class="comment">[file2]</span></span><br></pre></td></tr></table></figure>
<h1 id="五、分支"><a href="#五、分支" class="headerlink" title="五、分支"></a>五、分支</h1><p>1、列出所有的分支</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git branch</span></span><br></pre></td></tr></table></figure>
<p>2、列出所有的远程分支</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch -<span class="built_in">r</span></span><br></pre></td></tr></table></figure>
<p>3、新建一个新的分支,但还是停留在当前的分支。工作区会复用,即在master上面修改的内容还没有提交,那么如果新建了一个分支,并切换过去,master的未提交的内容也会跟着带到新的分支。</p>
<figure class="highlight irpf90"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch [branch-<span class="keyword">name</span>]</span><br></pre></td></tr></table></figure>
<p>4、新建一个分支,并切换到该分支</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -<span class="selector-tag">b</span> [branch-name]</span><br></pre></td></tr></table></figure>
<p>5、新建一个分支,并指定指向的commit,此时如果工作区不干净,切换可能会出现失败,需要使用git stash 将当前工作区的修改给隐藏掉。</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch <span class="comment">[branch-name]</span> <span class="comment">[commit id]</span></span><br></pre></td></tr></table></figure>
<p>6、切换到上一个分支</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git</span> branch -</span><br></pre></td></tr></table></figure>
<p>7、在当前的分支和指定的远程分支之间建立追踪关系</p>
<figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch --<span class="keyword">set</span>-upstream <span class="comment">[branch] [remote-branch]</span></span><br></pre></td></tr></table></figure>
<p>8、合并指定分支到当前分支</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">merge</span> [branch]</span><br></pre></td></tr></table></figure>
<p>9、删除分支</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch -d [branch-name]</span><br></pre></td></tr></table></figure>
<p>10、删除一个没有被合并过的分支需要使用-D参数:</p>
<figure class="highlight irpf90"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch -D [branch-<span class="keyword">name</span>]</span><br></pre></td></tr></table></figure>
<p>11、删除远程分支</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">push</span> [<span class="built_in">origin</span>-name] --d [branch-name]</span><br></pre></td></tr></table></figure>
<p>12、新建一个分支,指向某个tag</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b <span class="comment">[branch]</span> <span class="comment">[tag]</span></span><br></pre></td></tr></table></figure>
<p>13、显示分支图</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">log</span> --<span class="keyword">graph</span></span><br></pre></td></tr></table></figure>
<p>14、修改分支名称</p>
<figure class="highlight irpf90"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git banch -m [old-<span class="keyword">name</span>] [new-<span class="keyword">name</span>]</span><br></pre></td></tr></table></figure>
<p>15、合并多次commit</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rebase -i [commit]</span><br></pre></td></tr></table></figure>
<p>上面的命令表示的是head分支到commit上一个commit的合并,注意不包括该commit。</p>
<p>在弹出的Vim编辑页面输入命令: </p>
<p> Commands:<br> <figure class="highlight plain"><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"># p, pick <commit> = use commit</span><br><span class="line"># r, reword <commit> = use commit, but edit the commit message</span><br><span class="line"># e, edit <commit> = use commit, but stop for amending</span><br><span class="line"># s, squash <commit> = use commit, but meld into previous commit</span><br><span class="line"># f, fixup <commit> = like "squash", but discard this commit's log message</span><br><span class="line"># x, exec <command> = run command (the rest of the line) using shell</span><br><span class="line"># d, drop <commit> = remove commit</span><br><span class="line"># l, label <label> = label current HEAD with a name</span><br><span class="line"># t, reset <label> = reset HEAD to a label</span><br><span class="line"># m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]</span><br></pre></td></tr></table></figure></p>
<p> 然后wq保存,再弹出一个Vim编辑框,修改commit信息。</p>
<p>16、恢复删除的分支<br><figure class="highlight plain"><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">git reflog 查看之前的这个已经删除的分支的提交历史</span><br><span class="line">git branch <之前提交的那个分支的名字> <上一步操作查询到sha1></span><br></pre></td></tr></table></figure></p>
<h1 id="六、标签"><a href="#六、标签" class="headerlink" title="六、标签"></a>六、标签</h1><p>1、列出所有标签</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git tag</span></span><br></pre></td></tr></table></figure>
<p>2、新建一个指向当前commit的tag</p>
<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">tag</span> <span class="title">[tag-name</span>]</span><br></pre></td></tr></table></figure>
<p>3、新建一个tag在指定的commit</p>
<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">tag</span> <span class="title">[tag-nam</span>] [commit]</span><br></pre></td></tr></table></figure>
<p>4、删除本地tag</p>
<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">tag</span> <span class="title">-d</span> [<span class="keyword">tag</span>-name]</span><br></pre></td></tr></table></figure>
<p>5、删除远程tag</p>
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push [origin-name]<span class="symbol">:refs/tags/</span>[tag-name]</span><br></pre></td></tr></table></figure>
<p>6、查看tag信息</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">show</span> tag</span><br></pre></td></tr></table></figure>
<p>7、提交本地所有tag</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">push</span> [<span class="built_in">origin</span>-name] --tags</span><br></pre></td></tr></table></figure>
<p>8、提交指定tag</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">push</span> [<span class="built_in">origin</span>-name] [tag]</span><br></pre></td></tr></table></figure>
<h1 id="七、查看信息"><a href="#七、查看信息" class="headerlink" title="七、查看信息"></a>七、查看信息</h1><p>1、查看有变更的文件</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">status</span></span><br></pre></td></tr></table></figure>
<p>2、显示当前分支的版本历史</p>
<figure class="highlight vbscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span></span><br></pre></td></tr></table></figure>
<p>3、显示commit历史,以及每次commit发生变更的文件</p>
<figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">log</span> --<span class="keyword">stat</span></span><br></pre></td></tr></table></figure>
<p>4、显示代码差异</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">diff</span></span><br></pre></td></tr></table></figure>
<p>暂存区没有文件:比较的是当前工作区和上一次的commit的差别。</p>
<p>暂存区有文件:比较的是当前工作区和暂存区的差别。</p>
<p>5、显示暂存区和上一次commit的差异</p>
<figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">diff </span>--<span class="keyword">cached </span>[file]</span><br></pre></td></tr></table></figure>
<p>6、显示工作区和当前分支的最新commit的差异</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">diff</span> head</span><br></pre></td></tr></table></figure>
<p>7、显示两次提交之间的差异(commit1 和 commit的顺序需要注意,不一样会导致新增和删除错位)</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git diff <span class="comment">[commit1]</span> <span class="comment">[commit2]</span></span><br></pre></td></tr></table></figure>
<p>8、显示某次提交的元数据的和内容变化</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">show</span> [<span class="keyword">commit</span>]</span><br></pre></td></tr></table></figure>
<h1 id="八、远程同步"><a href="#八、远程同步" class="headerlink" title="八、远程同步"></a>八、远程同步</h1><p>配置远程仓库:</p>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote <span class="keyword">add</span><span class="bash"> <span class="built_in">test</span> http://[email protected]/scm/wbqa/xxxx.git</span></span><br></pre></td></tr></table></figure>
<p>test为远程仓库的别名,后面的htpp为远程仓库地址。<br>删除远程仓库:</p>
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote <span class="keyword">rm</span> <span class="keyword">test</span></span><br></pre></td></tr></table></figure>
<p>test为别名</p>
<p>1、下载远程仓库的所有变动</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git fetch <span class="comment">[remote]</span></span><br></pre></td></tr></table></figure>
<p>2、显示所有的远程仓库</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git remote -v</span></span><br></pre></td></tr></table></figure>
<p>和git remote的差别</p>
<figure class="highlight gams"><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="symbol">$</span> git remote</span><br><span class="line">origin</span><br><span class="line"><span class="symbol">$</span> git remote -v</span><br><span class="line">origin https:<span class="comment">//github.com/DimpleFeng/GitTest.git (fetch)</span></span><br><span class="line">origin https:<span class="comment">//github.com/DimpleFeng/GitTest.git (push)</span></span><br></pre></td></tr></table></figure>
<p>3、取回远程仓库的变化,并和本地分支合并</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git pull <span class="comment">[remote]</span> <span class="comment">[branch]</span></span><br></pre></td></tr></table></figure>
<p>4、上传本地指定分支到远程仓库</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push <span class="comment">[remote]</span> <span class="comment">[branch]</span></span><br></pre></td></tr></table></figure>
<p>5、强行推送当前分支到远程仓库即使有冲突</p>
<figure class="highlight avrasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">push</span> [remote] --force</span><br></pre></td></tr></table></figure>
<p>6、git remote 通常用于查看别人的进行,因为取回的代码对本地没有影响。</p>
<figure class="highlight xml"><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">git remote add <span class="tag"><<span class="name">主机名</span>></span> <span class="tag"><<span class="name">网址</span>></span> 添加远程主机</span><br><span class="line">git remote rm <span class="tag"><<span class="name">主机名</span>></span> 删除远程主机</span><br><span class="line">git remote rename <span class="tag"><<span class="name">原主机名</span>></span><span class="tag"><<span class="name">新主机名</span>></span></span><br></pre></td></tr></table></figure>
<p>7、git pull 取回远程主机某个分支的更新,再和本地的分支进行合并。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git pull <span class="tag"><<span class="name">远程主机名</span>></span> <span class="tag"><<span class="name">远程分支名</span>></span>:<span class="tag"><<span class="name">本地分支名</span>></span></span><br></pre></td></tr></table></figure>
<p>取回origin主机的next分支,与本地的master合并</p>
<figure class="highlight vbscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git pulll origin <span class="keyword">next</span>:master</span><br></pre></td></tr></table></figure>
<p>如果远程分支是和当前的分支进行合并,则冒号后面可以省略。</p>
<p>在某些场合,Git会自动在远程分支和本地分支之间创建一个追踪关系,如果当前分支和远程分支存在着追踪关系,就可以省略远程分支名称。</p>
<p>如果当前分支只有一个追踪分支,远程主机名也可以省略。</p>
<p>8、git push 将本地分支的更新,推送到远程主机</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push <span class="tag"><<span class="name">远程主机名</span>></span><span class="tag"><<span class="name">本地分支名</span>></span>:<span class="tag"><<span class="name">远程分支名</span>></span></span><br></pre></td></tr></table></figure>
<p>如果省略远程分支名,表示将本地分支推送给与之存在追踪关系的远程分支,如果该分支不存在会被新建。</p>
<p>如果省略本地分支名,则表示删除指定的远程分支:git push origin :master<br>如果当前分支和远程分支存在追踪关系,则本地分支和远程分支都可以省略。<br>如果只存在一个追踪分支,那么主机名可以省略.</p>
<p>如果远程主机的版本比本地的新,那么推送到Git的时候会报错,这个时候可以采用git push –force origin强制覆盖远程主机的版本。</p>
<h1 id="九、撤销"><a href="#九、撤销" class="headerlink" title="九、撤销"></a>九、撤销</h1><p>1、恢复暂存区的指定文件到工作区。会丢失提交到暂存区后对该文件的所有操作。</p>
<figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout [<span class="keyword">file</span>]</span><br></pre></td></tr></table></figure>
<p>2、恢复某次commit的指定文件到暂存区和工作区(git处于等待commit状态,同时会丢失在这之前对工作区的修改的内容)</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout <span class="comment">[commit]</span> <span class="comment">[file]</span></span><br></pre></td></tr></table></figure>
<p>3、恢复暂存区所有文件到工作区。会丢失在提交到暂存区之后的对文件的所有修改。</p>
<figure class="highlight erlang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout .</span><br></pre></td></tr></table></figure>
<p>4、重置暂存区和工作区,与上一次commit一致</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">reset</span> <span class="comment">--hard</span></span><br></pre></td></tr></table></figure>
<p>5、重置当前分支的head为指定的commit,同时重置暂存区和工作区,与指定commit一致。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">reset</span> <span class="comment">--hard [commit]</span></span><br></pre></td></tr></table></figure>
<p>git reset [file] 将file从暂存区回退到工作区(修改内容不会丢失)</p>
<p>6、将未保存的变化隐藏</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git stash</span></span><br></pre></td></tr></table></figure>
<p>弹出</p>
<figure class="highlight avrasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git stash <span class="keyword">pop</span></span><br></pre></td></tr></table></figure>
<p>7、查看历史命令</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git reflog</span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category> Java基础 </category>
</categories>
<tags>
<tag> Git </tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaEE中的过滤器和拦截器]]></title>
<url>/2018/08/23/2018-8-23-14-51-13/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>对于Interceptor和Filter,在很多时候都可以混淆使用,都是可以拦截用户请求,然后做一些事情。为了不混淆两者关系,在此整理了关于拦截器和过滤器的相关知识和区别。<br><a id="more"></a></p>
<h1 id="过滤器Filter"><a href="#过滤器Filter" class="headerlink" title="过滤器Filter"></a>过滤器Filter</h1><h2 id="Filter说明"><a href="#Filter说明" class="headerlink" title="Filter说明"></a>Filter说明</h2><p>过滤器是处于客户端和服务器资源文件之间的一道过滤网,在访问资源之前,通过一系列的拦截器,即构成的拦截器链FilterChain,对响应进行过滤拦截和修改。</p>
<p>Filter是JavaEE规范中的,是Servlet最实用的技术,通过Filter,就可以对Web服务器管理的所有Web资源如JSP、Servlet等等进行拦截,</p>
<p>具体的应用场景应该有URL级别的权限访问控制,过滤敏感词汇,压缩响应信息等等。</p>
<p>主要用作对用户请求进行预处理,也可以对response进行后处理。Filter的处理流程:Filter对用户请求进行预处理,接着讲请求交给Servlet进行处理并生成响应,最后Filter对服务器响应进行后处理。自定义的Filter还需要实现Filter接口。</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/TIM截图20180823151130-2018823.png" alt="TIM截图20180823151130-2018823"></p>
<h2 id="Filter工作原理"><a href="#Filter工作原理" class="headerlink" title="Filter工作原理"></a>Filter工作原理</h2><p>可以从上图看到,Filter接口中有三个方法,分别为init、doFilter、destroy,分别对应着初始化,过滤、销毁。</p>
<p>当我们写好了Filter的时候,还需要配置该Filter是要对哪些资源进行过滤。</p>
<p>当每次用户请求到达服务器后,在未到达具体请求的资源之前,Web服务器都会先调用Filter的doFilter方法进行处理,然后该方法传入的参数有一个FilterChain,如果处理完成放行会继续执行该FilterChain的doFilter方法,如果不放行就不继续执行该FilterChain的doFilter方法。</p>
<h2 id="Filter的编写流程"><a href="#Filter的编写流程" class="headerlink" title="Filter的编写流程"></a>Filter的编写流程</h2><p>1、编写一个类实现Filter接口,并实现其带的init、doFilter、destroy方法。</p>
<p>2、在doFilter方法中编写具体的逻辑,根据逻辑需要选择放行FilterChain。</p>
<p>3、在web.xml文件中配置过滤器(注册和映射),需要使用标签<filter>以及<filter-mapping></filter-mapping></filter></p>
<h2 id="Filter的生命周期"><a href="#Filter的生命周期" class="headerlink" title="Filter的生命周期"></a>Filter的生命周期</h2><h3 id="Filter创建"><a href="#Filter创建" class="headerlink" title="Filter创建"></a>Filter创建</h3><p>Filter的创建和销毁由Web容器负责,在Web应用启动的时候,Web服务器将创建Filter的实例对象,并调用init方法完成对象的初始化。</p>
<p>Filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数FilterConfig可以获得代表当前Filter的Config。</p>
<p>而这些参数,一般来源于web.xml中的init-param。在web.xml文件中配置的时候可以通过<init-param>来为Filter配置一些启动参数。</init-param></p>
<p>FilterConfig常用方法示例:<br><figure class="highlight plain"><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"> @Override</span><br><span class="line">public void init(FilterConfig filterConfig) throws ServletException {</span><br><span class="line"> String filterName = filterConfig.getFilterName();//获取Filter的Name</span><br><span class="line"> String initParam = filterConfig.getInitParameter("initParam");//获取名称为initParam的初始参数的值</span><br><span class="line"> Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();//获取所有的初始化参数的美聚集和while (initParameterNames.hasMoreElements()) {</span><br><span class="line"> System.out.println(initParameterNames.nextElement());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h3 id="Filter的销毁"><a href="#Filter的销毁" class="headerlink" title="Filter的销毁"></a>Filter的销毁</h3><p>在Web容器关闭之前,会调用Filter的destroy方法来销毁Filter,在此方法中,可以释放掉过滤器使用的资源。</p>
<h1 id="拦截器Interceptor"><a href="#拦截器Interceptor" class="headerlink" title="拦截器Interceptor"></a>拦截器Interceptor</h1><p>拦截器在开源框架中很常见,依赖的技术就是JavaJDK的动态代理,当然还有基于CGLIB的动态代理,关于这两种的代理区别,JDK的动态代理是需要用到接口Interface的,没有接口就不能实现动态代理,而CGLIB就可以不需要接口。</p>
<p>在这里呢,说下Spring中的Interceptor,依赖于Web框架,也是一种AOP的运用。由于拦截器是Web框架的调用,因此可以使用Spring的DI依赖注入,同时一个Controller可以在一个Controller的生命周期中多次被调用。</p>
<p>Interceptor只能拦截Controller,对于一些静态资源则不能拦截处理。</p>
<h2 id="实现一个自定义的Interceptor"><a href="#实现一个自定义的Interceptor" class="headerlink" title="实现一个自定义的Interceptor"></a>实现一个自定义的Interceptor</h2><p>1、需要实现HandlerInterceptor接口,并实现以下的三个方法,关于多个Interceptor执行,在preHandler执行完毕后的返回值会影响接下来执行的Interceptor,这里不做说明。</p>
<p>2、在Spring的配置文件中配置Interceptor。注意拦截器的执行顺序和配置文件的顺序有关。</p>
<figure class="highlight plain"><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">public class MyInterceptor implements HandlerInterceptor {</span><br><span class="line"> /**</span><br><span class="line"> * 在Dispatcher之前执行</span><br><span class="line"> *</span><br><span class="line"> * @param request</span><br><span class="line"> * @param response</span><br><span class="line"> * @param handler</span><br><span class="line"> * @return true:表示继续执行拦截器链,如果返回为false,就不会继续执行Controller</span><br><span class="line"> * @throws Exception</span><br><span class="line"> */</span><br><span class="line"> @Override</span><br><span class="line"> public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {</span><br><span class="line"> return false;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> /**</span><br><span class="line"> * 在Controller执行完毕之后,在视图解析器之前被执行</span><br><span class="line"> * @param request</span><br><span class="line"> * @param response</span><br><span class="line"> * @param handler</span><br><span class="line"> * @param modelAndView</span><br><span class="line"> * @throws Exception</span><br><span class="line"> */</span><br><span class="line"> @Override</span><br><span class="line"> public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}</span><br><span class="line"></span><br><span class="line"> /**</span><br><span class="line"> * 在视图解析器执行完毕后,在返回给客户端之前执行</span><br><span class="line"> * @param request</span><br><span class="line"> * @param response</span><br><span class="line"> * @param handler</span><br><span class="line"> * @param ex</span><br><span class="line"> * @throws Exception</span><br><span class="line"> */</span><br><span class="line"> @Override</span><br><span class="line"> public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category> JavaEE </category>
</categories>
<tags>
<tag> 过滤器,拦截器 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java读取Properties文件的几种方式]]></title>
<url>/2018/08/16/2018-08-16-03-58-02/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在Spring的时候,通过XML配置文件的方式进行配置数据库连接池的时候,就会使用==context:property-placeholder==标签进行读取,在这里呢,也是通过Java几种比较基础的方式来读取Properties文件。</p>
<p>在开始之前,说下目前比价常用的几种方式:</p>
<pre><code>1. 使用java.util.Properties类,可以使用它的load方法加载inputStream字节流。
2. 使用java.util.ResourceBundle类来读取。
</code></pre><a id="more"></a>
<h1 id="使用Properties类"><a href="#使用Properties类" class="headerlink" title="使用Properties类"></a>使用Properties类</h1><p>Properties类继承自Hashtable,而Hashtable是实现了Map接口的,所以对Properties类的操作和Map有些相似。</p>
<p>使用Properties来加载.properties文件的主要关键是在于load方法。而load方法需要的是InputStream流。</p>
<p>这里比较常用的流的获取有以下几种:</p>
<ol>
<li>使用当前类的ClassLoader()的getResourceAsStream(),getResourcesAsStream返回一个InputStream。</li>
<li>使用ClassLoader类的getSystemResourceAsStream(),该方法也返回一个InputStream。</li>
<li>使用文件输入流的方式。</li>
</ol>
<p>具体示例如下,为了方便,我直接使用的log4j.properties。文件位置如下:<br><img src="http://p2sj58chj.bkt.clouddn.com/blog/QQ截图20180816161804.png" alt="位置图"></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><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 单独抽取的方法,用户检测能否正确操纵Properties</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> inputStream</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException 为了排版美观,直接抛出异常</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">printKeyValue</span><span class="params">(InputStream inputStream)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> Properties properties = <span class="keyword">new</span> Properties();</span><br><span class="line"> properties.load(inputStream);</span><br><span class="line"> Set<Object> keys = properties.keySet();</span><br><span class="line"> <span class="keyword">for</span> (Object key : keys) {</span><br><span class="line"> System.out.println(key + <span class="string">" = "</span> + properties.get(key));</span><br><span class="line"> }</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="comment"> * 从当前的类加载器的getResourcesAsStream来获取.</span></span><br><span class="line"><span class="comment"> * 使用Class.class.getClassLoader().getResourcesAsStream()进行获取的时候,所填写的路径只能为项目的绝对路径</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getPropertiesFromResourceAsStream</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> InputStream resourceAsStream = PropertiesUtils.class.getClassLoader().getResourceAsStream(<span class="string">"com/dimple/getproperityfile/mylog4j.properties"</span>);</span><br><span class="line"> printKeyValue(resourceAsStream);</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="comment"> * 从文件中获取,使用InputStream字节</span></span><br><span class="line"><span class="comment"> * 主要是需要加上src这个文件夹名。。。路径配置需要精确到绝对地址级别</span></span><br><span class="line"><span class="comment"> * 什么意思,就是如果这个mylog4j文件在com/dimple/getproperityfile/mylog4j.properties下,而这个com文件夹</span></span><br><span class="line"><span class="comment"> * 又在src目录下,那么写的时候需要加上这个src,这样的相对路径+项目地址能够构成一个完整的访问地址即可</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getPropertiesFromFile</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> InputStream inputStream = <span class="keyword">new</span> FileInputStream(<span class="keyword">new</span> File(<span class="string">"src/com/dimple/getproperityfile/mylog4j.properties"</span>));</span><br><span class="line"> printKeyValue(inputStream);</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="comment"> * 使用Class类的getSystemResourceAsStream方法</span></span><br><span class="line"><span class="comment"> * 和使用当前类的ClassLoader是一样的</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getPropertiesFromClassLoader</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> InputStream systemResourceAsStream = ClassLoader.getSystemResourceAsStream(<span class="string">"com/dimple/getproperityfile/mylog4j.properties"</span>);</span><br><span class="line"> printKeyValue(systemResourceAsStream);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h1 id="使用ResourceBundle类"><a href="#使用ResourceBundle类" class="headerlink" title="使用ResourceBundle类"></a>使用ResourceBundle类</h1><p>使用ResourcesBundle类也两种方法可以读取到配置文件</p>
<ol>
<li>使用类ResourcesBundle的getBundle方法加载properties文件。</li>
<li>使用其派生类PropertyResourceBundle(),通过传入一个InputStream来读取数据。</li>
</ol>
<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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/***</span></span><br><span class="line"><span class="comment"> * 使用java.util.ResourceBundle类来加载properties文件,注意不需要带上后缀名。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getPropertiesFromResourceBundle</span><span class="params">()</span> </span>{</span><br><span class="line"> ResourceBundle resourceBundle = ResourceBundle.getBundle(<span class="string">"com/dimple/getproperityfile/mylog4j"</span>);</span><br><span class="line"> Enumeration<String> keys = resourceBundle.getKeys();</span><br><span class="line"> <span class="keyword">while</span> (keys.hasMoreElements()) {</span><br><span class="line"> String s = keys.nextElement();</span><br><span class="line"> System.out.println(s + <span class="string">" = "</span> + resourceBundle.getString(s));</span><br><span class="line"> }</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="comment"> * 使用InputStream流来进行操作ResourceBundle,获取流的方式由以上几种。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getPropertiesFromResourceBundleInputStream</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> InputStream systemResourceAsStream = ClassLoader.getSystemResourceAsStream(<span class="string">"com/dimple/getproperityfile/mylog4j.properties"</span>);</span><br><span class="line"> ResourceBundle resourceBundle = <span class="keyword">new</span> PropertyResourceBundle(systemResourceAsStream);</span><br><span class="line"> Enumeration<String> keys = resourceBundle.getKeys();</span><br><span class="line"> <span class="keyword">while</span> (keys.hasMoreElements()) {</span><br><span class="line"> String s = keys.nextElement();</span><br><span class="line"> System.out.println(s + <span class="string">" = "</span> + resourceBundle.getString(s));</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上代码的的方法具体有什么用已经表明了,遇到的问题已经不是代码问题了。而是路径。对于这个路径,相对路径,绝对路径,项目路径,这个路径确实让我有些头痛,在File的Test代码哪里,文件路径近乎是我试出来的。当然读者可能会说,直接拿鼠标去点,能点进去的就是对的,但是,在File那里,我没有加src,是可以点击去的,但是项目报错提示FileNotFound,加上src就能正常访问,但是点不进去。这个原因是因为IDEA这里,有一个工程路径的说法,工程路径并不包含src,而代码是写在src下的,所以导致最后的绝对路径不可达,所以报错。</p>
]]></content>
<categories>
<category> Java基础 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> properties </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java中的前置++和后置++的理解]]></title>
<url>/2018/08/14/2018-08-14-04-38-57/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在C、C++等编程语言中都会存在i++,++i,在实际运用中我们总能记住一句话==i++(后置++)是先使用在+1,而++i(前置++)是先自增再使用==。但是在一些很烧脑的场合,这种规律就会“失效”。</p>
<p>本文会首先简单的介绍下前置和后置++在一些场合的实际应用,可以看到的是合理的使用++会使得代码简洁不少。<br><a id="more"></a></p>
<h1 id="前置后置的实际使用"><a href="#前置后置的实际使用" class="headerlink" title="++前置后置的实际使用"></a>++前置后置的实际使用</h1><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.dimple.javabase;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@program</span>: JavaSEProject</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span>: 测试++运算符</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: Dimple</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span>: 2018-08-14 16:46</span></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">AddOpt</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"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> String[] people = {<span class="string">"Dennis Ritchie"</span>, <span class="string">"Bjarne Stroustrup"</span>, <span class="string">"James Gosling"</span>};</span><br><span class="line"> System.out.println(Arrays.asList(people).toString());</span><br><span class="line"> System.out.println(<span class="string">"preposition ++"</span>);</span><br><span class="line"> System.out.println(<span class="string">" before operation···"</span>);</span><br><span class="line"> System.out.println(<span class="string">" i= "</span>+i);</span><br><span class="line"> System.out.println(<span class="string">" "</span>+people[i++]);</span><br><span class="line"> System.out.println(<span class="string">" after operation···"</span>);</span><br><span class="line"> System.out.println(<span class="string">" i= "</span>+i);</span><br><span class="line"> System.out.println(<span class="string">"postposition ++"</span>);</span><br><span class="line"> i = <span class="number">0</span>;</span><br><span class="line"> System.out.println(<span class="string">" before operation···"</span>);</span><br><span class="line"> System.out.println(<span class="string">" i= "</span>+i);</span><br><span class="line"> System.out.println(<span class="string">" "</span>+people[++i]);</span><br><span class="line"> System.out.println(<span class="string">" after operation···"</span>);</span><br><span class="line"> System.out.println(<span class="string">" 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>运行结果如下:</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">[Dennis Ritchie, Bjarne Stroustrup, James Gosling]</span><br><span class="line">preposition ++</span><br><span class="line"> before operation···</span><br><span class="line"> i= <span class="number">0</span></span><br><span class="line"> Dennis Ritchie</span><br><span class="line"> after operation···</span><br><span class="line"> i= <span class="number">1</span></span><br><span class="line">postposition ++</span><br><span class="line"> before operation···</span><br><span class="line"> i= <span class="number">0</span></span><br><span class="line"> Bjarne Stroustrup</span><br><span class="line"> after operation···</span><br><span class="line"> i= <span class="number">1</span></span><br><span class="line"></span><br><span class="line">Process finished with exit code <span class="number">0</span></span><br></pre></td></tr></table></figure>
<p>上面的都是很基础的,只是单纯的为了回忆一下,所有需要记住的是:</p>
<p>==前置++(++i)是先进行++操作后再赋值==<br>==后置++(i++)是先进行赋值再进行++操作==</p>
<p>最近在网上看到这样一个题,本文的主要目的是这道题。</p>
<h1 id="一道很烧脑的题"><a href="#一道很烧脑的题" class="headerlink" title="一道很烧脑的题"></a>一道很烧脑的题</h1><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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.dimple.javabase;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@program</span>: JavaSEProject</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span>: 面试题中的一道烧脑题</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: Dimple</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span>: 2018-08-14 17:00</span></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">Increment</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> k = <span class="number">0</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[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> j=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> n=<span class="number">0</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">100</span> ;i++){</span><br><span class="line"> j=j++;</span><br><span class="line"> k=k++;</span><br><span class="line"> n=++n;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> System.out.println(j);</span><br><span class="line"> System.out.println(k);</span><br><span class="line"> System.out.println(n);</span><br><span class="line"></span><br><span class="line"> }</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></pre></td><td class="code"><pre><span class="line"><span class="number">0</span></span><br><span class="line"><span class="number">0</span></span><br><span class="line"><span class="number">100</span></span><br></pre></td></tr></table></figure>
<p>不需要去看编译后的字节码,其实很简单的就可以看出来:</p>
<p>分析:<br>在分析之前我们还是先看一个这样的代码:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.dimple.javabase;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@program</span>: JavaSEProject</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span>: 测试++运算符</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: Dimple</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span>: 2018-08-14 16:46</span></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">AddOpt</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"> <span class="keyword">int</span> j=<span class="number">0</span>;</span><br><span class="line"> j = j++;</span><br><span class="line"> System.out.println(j);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>以上代码如果我们使用的是IDEA编译器的话,在j下面有一个小波浪线提示以下话:</p>
<blockquote>
<p>The value changed at ‘j++’ is never used less… (Ctrl+F1)<br>Inspection info: This inspection points out the cases where a variable value is never used after its assignment, i.e.: - the variable never gets read after assignment OR - the value is always overwritten with another assignment before the next variable read OR - the variable initializer is redundant (for one of the above two reasons)</p>
</blockquote>
<p>以上提示说的是:该j变量并没有被使用。emmmmm不是让它=j了吗?以上只是一个小的插曲,接下来开始我们的分析。</p>
<p>首先我们看到==j=j++;==这样的一句话,本身是有问题的(为了说明,我们把表达式左边的j叫做j1,右边的j叫做j2(注意,只是叫做!)):</p>
<pre><code>1. 执行时,首先是会执行等号右边的话,也就是==j1=j2==这一句话,那么这样的一句话,得到的结果是j1=0,对吧。
2. 这个时候如果按照正常的逻辑,那么应该是执行j++这句话了对吧。是这样没错,肯定是会执行j++这一句话的。注意:执行这个j2++的时候,并不和j1在同一个工作区,j2++完了之后,并没有任何的变量去接收它。导致j2++废弃。所以j一直都是0.
</code></pre><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>–操作符同理,其实细致点这个问题是可以看出来的,还是需要修炼基本功呀···</p>
]]></content>
<categories>
<category> Java基础 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> 前置++ </tag>
<tag> 后置++ </tag>
</tags>
</entry>
<entry>
<title><![CDATA[对HashMap的思考]]></title>
<url>/2018/08/09/2018-08-09-09-29-20/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>HashMap是一个散列表,它存储的内容是==Key-Value==键值对的映射。</p>
<p>类原型如下:</p>
<p>继承自抽象类AbstractMap<k,v>,实现Map接口,Cloneable主要是用于clone方法,以及序列化接口。</k,v></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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HashMap</span><<span class="title">K</span>,<span class="title">V</span>> <span class="keyword">extends</span> <span class="title">AbstractMap</span><<span class="title">K</span>,<span class="title">V</span>></span></span><br><span class="line"><span class="class"> <span class="keyword">implements</span> <span class="title">Map</span><<span class="title">K</span>,<span class="title">V</span>>, <span class="title">Cloneable</span>, <span class="title">Serializable</span> </span>{</span><br></pre></td></tr></table></figure>
<a id="more"></a>
<h1 id="Map的常用类型"><a href="#Map的常用类型" class="headerlink" title="Map的常用类型"></a>Map的常用类型</h1><p><img src="http://p2sj58chj.bkt.clouddn.com/blog/java.util.map类图.png" alt="enter description here"><br>继承Map接口的有以下几种:</p>
<ul>
<li>HashMap:根据键的HashCode值进行数据的存储,可以直接根据键获取值,访问速度很快。是非同步的,即线程不安全。==key和value都可以为null,但是只能有一个为null的key,value无限制。==</li>
<li>TreeMap:能够根据底层的红黑二叉树来对插入的数据按照==key==进行从小到大的排序。且其key不能为null,value可以为null。==key为null时,在代码编写阶段不会报错,但运行时报NullPointerException。==同时TreeMap非同步的,线程不安全。</li>
<li>HashTable:HashTable的key与value是不能为null,且和HashMap最大的区别是HashTable是线程安全的,其方法都是有==synchronized==关键字修饰的,其继承自==Dictionary==。但是不建议使用,因为并发不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。</li>
<li>LinkHashMap:采用的是链表的方式存储数据,使用Iterator进行遍历的时候,先得到的是最先插入的,即==保留了记录的插入顺序==,和HashMap的底层实现不同,导致使用LinkHashMap的时候的遍历效率比HashMap慢。同时key和value都可以为null,非同步,线程不安全。</li>
</ul>
<h1 id="HashMap的JDK1-6-1-7实现"><a href="#HashMap的JDK1-6-1-7实现" class="headerlink" title="HashMap的JDK1.6\1.7实现"></a>HashMap的JDK1.6\1.7实现</h1><p>在JDK1.6,1.7中,HashMap采用的是数组+链表的方式,即使用数组存放链表。同一个HashCode值的元素都是存储在一个链表里面,但是如果位于同一个链表的元素(就是HashCode值相等的元素)增多的时候,查找元素的时候就不能很好的发挥HashMap的功效了。</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/blog/QQ截图20180809101056.png" alt="enter description here"></p>
<p>如图:</p>
<p>当调用map的put方法放入key-value键值对,那么首先会根据key的hashCode值,计算出在给定的key在数组中的位置,然后放在其后的单链表中。</p>
<p>这样的设计的好处是减少了Hash碰撞,即HashCode值相同并不一定意味着对象是相同的。那么这些HashCode怎么转化为数组空间的呢?一般是hash(key)%length来得到的。</p>
<h2 id="疑问"><a href="#疑问" class="headerlink" title="疑问"></a>疑问</h2><p>1、如果多个key通过hashCode%length这样的算法得到的index都是相同的,会不会被覆盖?</p>
<p>不会。当A通过计算得到index=1,放在链表中,如果接下来来了一个B,B通过计算得到的index也=1,那么做的事情就是使用头插法将新来的元素插入到链表的头结点。为什么使用头插法呢?可能是觉得新来的元素被查找的概率要高一点吧,毕竟查找是从头开始。</p>
<p>2、HashMap是允许存入key-value为null的Entry的,那么他们在什么位置呢?</p>
<p>null key总是放在entry的第一个元素。</p>
<p>3、get操作原理</p>
<p>get的函数原型如下:<code>public V get(Object key)</code>,先根据key的HashCode定位到数组的index,然后在这个index位置的链表进行遍历。</p>
<h1 id="HashMap在JDK1-8的实现"><a href="#HashMap在JDK1-8的实现" class="headerlink" title="HashMap在JDK1.8的实现"></a>HashMap在JDK1.8的实现</h1><p>在JDK1.8之后,也许是意识到了当链表长度过长带来的遍历效率的问题,因此,在JDK1.8中最重要的变化之一就是引入了红黑树,当同一个hash值的节点数不小于8时,不再采用单链表形式存储,而是采用红黑树。</p>
<p>Node是HashMap的一个内部类,实现了Map.Entry接口,本质是就是一个映射(键值对)。</p>
<p>有时两个key会定位到相同的位置,表示发生了Hash碰撞。当然Hash算法计算结果越分散均匀,Hash碰撞的概率就越小,map的存取效率就会越高。</p>
<p>HashMap类中有一个非常重要的字段,就是 Node[] table,即哈希桶数组,明显它是一个Node的数组。</p>
<p>如果哈希桶数组很大,即使较差的Hash算法也会比较分散,如果哈希桶数组数组很小,即使好的Hash算法也会出现较多碰撞,所以就需要在空间成本和时间成本之间权衡,其实就是在根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。那么通过什么方式来控制map使得Hash碰撞的概率又小,哈希桶数组(Node[] table)占用空间又少呢?答案就是好的Hash算法和扩容机制。</p>
<h1 id="常用API"><a href="#常用API" class="headerlink" title="常用API"></a>常用API</h1><table>
<thead>
<tr>
<th>clear()</th>
<th>从 Map 中删除所有映射</th>
</tr>
</thead>
<tbody>
<tr>
<td>remove(Object key)</td>
<td>从 Map 中删除键和关联的值</td>
</tr>
<tr>
<td>put(Object key, Object value)</td>
<td>将指定值与指定键相关联</td>
</tr>
<tr>
<td>putAll(Map t)</td>
<td>将指定 Map 中的所有映射复制到此 map</td>
</tr>
<tr>
<td>entrySet()</td>
<td>返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素</td>
</tr>
<tr>
<td>keySet()</td>
<td>返回 Map 中所包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值)</td>
</tr>
<tr>
<td>values()</td>
<td>返回 map 中所包含值的 Collection 视图。删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)</td>
</tr>
<tr>
<td>get(Object key)</td>
<td>返回与指定键关联的值</td>
</tr>
<tr>
<td>containsKey(Object key)</td>
<td>如果 Map 包含指定键的映射,则返回 true</td>
</tr>
<tr>
<td>containsValue(Object value)</td>
<td>如果此 Map 将一个或多个键映射到指定值,则返回 true</td>
</tr>
<tr>
<td>isEmpty()</td>
<td>如果 Map 不包含键-值映射,则返回 true</td>
</tr>
<tr>
<td>size()</td>
<td>返回 Map 中的键-值映射的数目</td>
</tr>
</tbody>
</table>
]]></content>
<categories>
<category> Java基础 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> HashMap </tag>
</tags>
</entry>
<entry>
<title><![CDATA[SpringMVC文件AJAX上传+JQuery文件进度条]]></title>
<url>/2018/08/08/2018-08-08-05-56-11/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>文件上传是一个很常用的功能,比如头像上传,视频上传等等,本文主要使用SpringMVC+Ajax实现文件上传,下载,删除等操作,同时重写CommonsMultipartResolver添加监听器ProgressListener,通过客户端轮询的方式来获取上传文件的进度。本文会首先介绍文件AJAX上传并获取进度的操作。<br><a id="more"></a></p>
<ul>
<li><a href="#前言">前言</a></li>
<li><a href="#文件上传">文件上传</a><ul>
<li><a href="#前端设计">前端设计</a></li>
<li><a href="#java后端设计">Java后端设计</a></li>
<li><a href="#commonsmultipartresolver文件上传解析器">CommonsMultipartResolver文件上传解析器</a></li>
<li><a href="#监听器">监听器</a></li>
<li><a href="#progress-bean">Progress Bean</a></li>
<li><a href="#controller">controller</a></li>
</ul>
</li>
<li><a href="#误区">误区</a><ul>
<li><a href="#在spring的配置文件中的commonmutipartresolver配置的id名称">在Spring的配置文件中的CommonMutipartResolver配置的id名称</a></li>
<li><a href="#轮询的方式">轮询的方式</a></li>
<li><a href="#demo文件下载地址">Demo文件下载地址</a></li>
</ul>
</li>
</ul>
<h1 id="文件上传"><a href="#文件上传" class="headerlink" title="文件上传"></a>文件上传</h1><p>一般就文件上传的方式来说,有两种:</p>
<ul>
<li>第一种:使用FORM表单提交的方式,在这种提交的方式中,需要将FORM表单的==method==设置为POST方式,同时需要将==enctype==设置为multipart/form-data</li>
<li>第二种:使用AJAX的方式,使用这种方式来获取form表单中的二进制流也有两种实现策略:<ul>
<li>1、使用FormData对象:FormData对象是HTML5 的一个对象,目前的很多浏览器已经兼容。</li>
<li>2、使用Jquery.form.js插件:它提供了大量的操作表单的方法。<a href="http://jquery.malsup.com/form/" target="_blank" rel="noopener">详情可以点击这里查看官方文档</a></li>
</ul>
</li>
</ul>
<p>在开始之前需要添加以下依赖:</p>
<figure class="highlight xml"><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="comment"><!-- https://mvnrepository.com/artifact/commons-io/commons-io --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>commons-io<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>commons-io<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.6<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>commons-fileupload<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>commons-fileupload<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.3.3<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure>
<h2 id="前端设计"><a href="#前端设计" class="headerlink" title="前端设计"></a>前端设计</h2><p>效果如图:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/blog/20180808205344.png" alt=""></p>
<figure class="highlight"><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><%@ page contentType=<span class="string">"text/html;charset=UTF-8"</span> language=<span class="string">"java"</span> %></span><br><span class="line"><!DOCTYPE html PUBLIC <span class="string">"-//W3C//DTD XHTML 1.0 Transitional//EN"</span></span><br><span class="line"><span class="string">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span>></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <title>文件上传下载</title></span><br><span class="line"> <script src="jquery/jquery-3.3.1.js"></script></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"><style></span><br><span class="line"> #progressbar {</span><br><span class="line"> width: <span class="number">200</span>px;</span><br><span class="line"> border: <span class="number">1</span>px solid darkgray;</span><br><span class="line"> height: <span class="number">15</span>px;</span><br><span class="line"> border-radius: <span class="number">1</span>rem;</span><br><span class="line"> margin-top: -<span class="number">10</span>px;</span><br><span class="line"> display: none;</span><br><span class="line"> }</span><br><span class="line"> #fill {</span><br><span class="line"> height: <span class="number">15</span>px;</span><br><span class="line"> text-align: center;</span><br><span class="line"> line-height: <span class="number">15</span>px;</span><br><span class="line"> border-radius: <span class="number">1</span>rem;</span><br><span class="line"> background-color: mediumturquoise;</span><br><span class="line"> }</span><br><span class="line"></style></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><div id=<span class="string">"progressbar"</span>></span><br><span class="line"> <div id="fill"></div></span><br><span class="line"></div></span><br><span class="line"><form action=<span class="string">"#"</span> id=<span class="string">"form"</span>></span><br><span class="line"> <input type=<span class="string">"file"</span> name=<span class="string">"file"</span>/></span><br><span class="line"> <input type=<span class="string">"button"</span> value=<span class="string">"上传"</span> onclick=<span class="string">"upload()"</span>/></span><br><span class="line"></form></span><br><span class="line"></body></span><br><span class="line"></html></span><br><span class="line"><script type=<span class="string">"text/javascript"</span>></span><br><span class="line"> var interval;</span><br><span class="line"> <span class="function">function <span class="title">upload</span><span class="params">()</span> </span>{</span><br><span class="line"> var formData = <span class="keyword">new</span> FormData($(<span class="string">"form"</span>)[<span class="number">0</span>]);</span><br><span class="line"> interval = setInterval(getProgress, <span class="number">100</span>);<span class="comment">//开启定时器(间歇调用)</span></span><br><span class="line"> $.ajax({</span><br><span class="line"> url: <span class="string">"/upload"</span>,</span><br><span class="line"> type: <span class="string">"POST"</span>,</span><br><span class="line"> data: formData,</span><br><span class="line"> cache: <span class="keyword">false</span>,</span><br><span class="line"> processData: <span class="keyword">false</span>,<span class="comment">//此处需要设置为false</span></span><br><span class="line"> contentType: <span class="keyword">false</span>,<span class="comment">//此处需要设置为false</span></span><br><span class="line"> success: function (data) {</span><br><span class="line"> console.log(data);</span><br><span class="line"> }</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">function <span class="title">getProgress</span><span class="params">()</span> </span>{</span><br><span class="line"> $(<span class="string">"#progressbar"</span>).show()</span><br><span class="line"> $.ajax({</span><br><span class="line"> url: <span class="string">"getInfo"</span>,</span><br><span class="line"> type: <span class="string">"get"</span>,</span><br><span class="line"> success: function (progressdata) {</span><br><span class="line"> <span class="keyword">if</span> (progressdata == <span class="string">"stop"</span>) {</span><br><span class="line"> clearInterval(interval);</span><br><span class="line"> }</span><br><span class="line"> $(<span class="string">"#fill"</span>).css(<span class="string">"width"</span>, progressdata+<span class="string">"%"</span>);</span><br><span class="line"> $(<span class="string">"#fill"</span>).text(progressdata+<span class="string">"%"</span>);</span><br><span class="line"> console.log(progressdata);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></script></span><br><span class="line"></html></span><br></pre></td></tr></table></figure>
<p>这里解释下:</p>
<p>使用的是刚才说到的第一种方式,即使用FormData对象的方式来进行ajax上传。</p>
<h2 id="Java后端设计"><a href="#Java后端设计" class="headerlink" title="Java后端设计"></a>Java后端设计</h2><p>刚才说到了我们的核心思想分为下面几步:</p>
<h2 id="CommonsMultipartResolver文件上传解析器"><a href="#CommonsMultipartResolver文件上传解析器" class="headerlink" title="CommonsMultipartResolver文件上传解析器"></a>CommonsMultipartResolver文件上传解析器</h2><p>1、重写CommonsMultipartResolver文件上传解析器,如果只是文件上传是不需要重写的,这里需要用到重写是因为需要设置文件上传的监听器。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*CustomMultipartResolver.java*/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomMultipartResolver</span> <span class="keyword">extends</span> <span class="title">CommonsMultipartResolver</span> </span>{</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> FileUploadProgressListener progressListener;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> MultipartParsingResult <span class="title">parseRequest</span><span class="params">(HttpServletRequest request)</span> <span class="keyword">throws</span> MultipartException </span>{</span><br><span class="line"> String encoding = determineEncoding(request);<span class="comment">//获取字符编码,这个很重要</span></span><br><span class="line"> FileUpload fileUpload = prepareFileUpload(encoding);<span class="comment">//获取FileUpload对象</span></span><br><span class="line"> progressListener.setSession(request.getSession());<span class="comment">//保存数据到session</span></span><br><span class="line"> fileUpload.setProgressListener(progressListener);<span class="comment">//设置监听器</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);<span class="comment">//解析数据</span></span><br><span class="line"> <span class="keyword">return</span> parseFileItems(fileItems, encoding);</span><br><span class="line"> } <span class="keyword">catch</span> (FileUploadBase.SizeLimitExceededException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);</span><br><span class="line"> } <span class="keyword">catch</span> (FileUploadException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> MultipartException(<span class="string">"Could not parse multipart servlet request"</span>, ex);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>当然了以上的代码除了需要自己添加设置监听器的代码,其他的可以参考源码实现:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/blog/20180808211423.png" alt="enter description here"></p>
<p>为了让Spring知道这个multipartResolver的存在,还需要在springMVC.xml中配置:</p>
<figure class="highlight xml"><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="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"multipartResolver"</span> <span class="attr">class</span>=<span class="string">"com.dimple.resolver.CustomMultipartResolver"</span>></span></span><br><span class="line"> <span class="comment"><!--<property name="defaultEncoding" value="UTF-8"/>--></span></span><br><span class="line"> <span class="comment"><!--<property name="maxUploadSize" value="102400000 "/> &lt;!&ndash; 最大文件大小限制 &ndash;&gt;--></span></span><br><span class="line"><span class="tag"></<span class="name">bean</span>></span></span><br></pre></td></tr></table></figure>
<h2 id="监听器"><a href="#监听器" class="headerlink" title="监听器"></a>监听器</h2><p>2、既然说到了要监听,那么就需要设置一个监听器,此监听器是实现了ProgressListener接口,重写了update方法。</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><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/*FileUploadProgressListener.java*/</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileUploadProgressListener</span> <span class="keyword">implements</span> <span class="title">ProgressListener</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> HttpSession session;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 设置Session,这样能够将状态保存在session域中</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> session</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">setSession</span><span class="params">(HttpSession session)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.session = session;</span><br><span class="line"> Progress status = <span class="keyword">new</span> Progress();</span><br><span class="line"> session.setAttribute(<span class="string">"status"</span>, status);</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="comment"> * 文件上传会回调的update方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> bytesRead 已经读取到的字节数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> contentLength 该上传文件的总字节数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> items 当前是上传第几个文件,默认为1</span></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">update</span><span class="params">(<span class="keyword">long</span> bytesRead, <span class="keyword">long</span> contentLength, <span class="keyword">int</span> items)</span> </span>{</span><br><span class="line"> Progress status = (Progress) session.getAttribute(<span class="string">"status"</span>);</span><br><span class="line"> status.setBytesRead(bytesRead);</span><br><span class="line"> status.setContentLength(contentLength);</span><br><span class="line"> status.setItems(items);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Progress-Bean"><a href="#Progress-Bean" class="headerlink" title="Progress Bean"></a>Progress Bean</h2><p>3、以上可以看到有一个Progress类,此类为JavaBean,方便数据传递。</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"><span class="comment">/*Progress.java*/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Progress</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> bytesRead;<span class="comment">//已经上传的字节数</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> contentLength;<span class="comment">//所有文件的总长度</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> startTime = System.currentTimeMillis();<span class="comment">//开始上传的时间</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> items;<span class="comment">//正在上传第几个文件</span></span><br><span class="line"> <span class="comment">/*Geter and Seter*/</span></span><br><span class="line"> <span class="comment">/*toString*/</span></span><br></pre></td></tr></table></figure>
<h2 id="controller"><a href="#controller" class="headerlink" title="controller"></a>controller</h2><p>4、以上所有都是为了Controller服务的,在Controller中,需要实现两个目标:</p>
<pre><code>- 实现文件上传
- 实现进度查询
</code></pre><p>文件上传的方式很简单:通过File类来设置文件上传的路径的问题,比如这个要放到哪个文件夹中,判断文件夹是否存在等等,还有文件的删除也需要用到File类。创建好文件夹后,便需要将它上传到刚才创建好的文件夹中。</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><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><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*FileUploadController.java*/</span></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileUploadController</span> </span>{</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="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request request用于获取Session,方便向session存值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> file 文件上传类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 文件上传状态字符串:ok,error</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@ResponseBody</span></span><br><span class="line"> <span class="meta">@RequestMapping</span>(value = <span class="string">"/upload"</span>, method = RequestMethod.POST)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">upload</span><span class="params">(HttpServletRequest request, @RequestParam(<span class="string">"file"</span>)</span> CommonsMultipartFile[] file) </span>{</span><br><span class="line"> String path = request.getSession().getServletContext().getRealPath(<span class="string">"upload"</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < file.length; i++) {</span><br><span class="line"> String fileName = file[i].getOriginalFilename();<span class="comment">//获取原始的文件名称</span></span><br><span class="line"> System.out.println(path);</span><br><span class="line"> File targetFile = <span class="keyword">new</span> File(path, fileName);</span><br><span class="line"> <span class="keyword">if</span> (!targetFile.exists()) {</span><br><span class="line"> targetFile.mkdirs();<span class="comment">//创建文件夹</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> file[i].transferTo(targetFile);<span class="comment">//将文件转移到指定的文件夹中</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 class="keyword">return</span> <span class="string">"error"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"ok"</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="comment"> * 用于处理客户端轮询获取文件上传进度</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request 用于从session中取出值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 如果文件上传完毕返回stop,告诉客户端停止轮询;如果还没有上传完,返回当前进度。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@RequestMapping</span>(<span class="string">"getInfo"</span>)</span><br><span class="line"> <span class="meta">@ResponseBody</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getProgress</span><span class="params">(HttpServletRequest request)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> Progress progress = (Progress) request.getSession().getAttribute(<span class="string">"status"</span>);</span><br><span class="line"> System.out.println(progress);</span><br><span class="line"> DecimalFormat decimalFormat = <span class="keyword">new</span> DecimalFormat(<span class="string">"0"</span>);</span><br><span class="line"> String result = decimalFormat.format((<span class="keyword">float</span>) progress.getBytesRead() / (<span class="keyword">float</span>) progress.getContentLength() * <span class="number">100</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"100"</span>.equals(result)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"stop"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在getProgress方法中,就很简单了,由于监听器是将数据放在session域里面的,只需要将数据取出来进行处理传递到客户端即可。</p>
<h1 id="误区"><a href="#误区" class="headerlink" title="误区"></a>误区</h1><h2 id="在Spring的配置文件中的CommonMutipartResolver配置的id名称"><a href="#在Spring的配置文件中的CommonMutipartResolver配置的id名称" class="headerlink" title="在Spring的配置文件中的CommonMutipartResolver配置的id名称"></a>在Spring的配置文件中的CommonMutipartResolver配置的id名称</h2><p>此处的id必须要为multipartResolver,因为在SpringMV的DispatcherServlet中有一个==initMultipartResolver==方法,方法源码如下:</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Initialize the MultipartResolver used by this class.</span></span><br><span class="line"><span class="comment"> * <p>If no bean is defined with the given name in the BeanFactory for this namespace,</span></span><br><span class="line"><span class="comment"> * no multipart handling is provided.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initMultipartResolver</span><span class="params">(ApplicationContext context)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);</span><br><span class="line"> <span class="keyword">if</span> (logger.isDebugEnabled()) {</span><br><span class="line"> logger.debug(<span class="string">"Using MultipartResolver ["</span> + <span class="keyword">this</span>.multipartResolver + <span class="string">"]"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> (NoSuchBeanDefinitionException ex) {</span><br><span class="line"> <span class="comment">// Default is no multipart resolver.</span></span><br><span class="line"> <span class="keyword">this</span>.multipartResolver = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (logger.isDebugEnabled()) {</span><br><span class="line"> logger.debug(<span class="string">"Unable to locate MultipartResolver with name '"</span> + MULTIPART_RESOLVER_BEAN_NAME +</span><br><span class="line"> <span class="string">"': no multipart request handling provided"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>在注释上就说明了如果不按照这个名字进行配置的话,就不会有multipart处理。</p>
<h2 id="轮询的方式"><a href="#轮询的方式" class="headerlink" title="轮询的方式"></a>轮询的方式</h2><p>在这个例子中,使用的是普通的轮询方法,就是隔一段时间就向客户端发送请求,服务器收到请求后马上返回响应消息并马上关闭连接。这种写法很简单,但是带来的问题也是显而易见的,因为这样的请求中,就拿我们的文件上传的进度来说,如果文件足够大,500ms去请求服务器,可能很多次都是获取的同样的数据,这样的方式占用带宽比较严重,比较浪费服务器的资源。</p>
<h2 id="Demo文件下载地址"><a href="#Demo文件下载地址" class="headerlink" title="Demo文件下载地址"></a>Demo文件下载地址</h2><p><a href="https://github.com/DimpleFeng/FileUploadSSM" target="_blank" rel="noopener">Click Me</a></p>
]]></content>
<categories>
<category> JavaEE </category>
</categories>
<tags>
<tag> SpringMVC </tag>
<tag> 文件上传 </tag>
<tag> 进度条 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Error running 'Tomcat'Unable to open debugger port (127.0.0.1:2148)的解决办法]]></title>
<url>/2018/08/03/2018-8-3-20-36-12/</url>
<content type="html"><![CDATA[<p>在Web项目运行的时候,IDEA可能会报Error running ‘Tomcat’: Unable to open debugger port (127.0.0.1:2148): java.net.SocketException “socket closed”错误,启动不了Tomcat,在这种时候,网上的解决办法大多都是修改端口的这种方式,但是这种方式治标不治本。</p>
<a id="more"></a>
<p>错误截图如下:</p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180803144001.png" alt="QQ截图20180803144001"></p>
<p>解决办法:</p>
<p>打开CMD命令行界面:</p>
<p>输入以下命令,查看1099端口号的占用。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -ano | find "1099"</span><br></pre></td></tr></table></figure></p>
<p>这里看到的是PID为5440的进程占用1099端口,所以输入以下命令终止进程:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">taskkill -f -pid 5440</span><br></pre></td></tr></table></figure></p>
<p><img src="http://p2sj58chj.bkt.clouddn.com/QQ截图20180803210031.png" alt="QQ截图20180803210031"></p>
<p>重新启动Web项目就不会报错了</p>
]]></content>
<categories>
<category> JavaEE </category>
</categories>
<tags>
<tag> Tomcat </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java中接口和抽象类]]></title>
<url>/2018/08/01/2018-8-1-20-35-28/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>经常看到关于Java中的接口和抽象类的比较,看着这两难兄难弟确实还是有些像,又有些不想,借此,想好好总结下他们两。</p>
<h1 id="关于抽象类"><a href="#关于抽象类" class="headerlink" title="关于抽象类"></a>关于抽象类</h1><p>在Java中,抽象类是以abstract关键字修饰的。有抽象方法的一定是抽象类,反之,抽象类不一定有抽象方法,这句话是《Java编程思想》这本书中提到的,说的是只要是被关键字abstract修饰的类都叫抽象类,而不管这个类中是否含有抽象方法。抽象类的定义格式为:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abstaract class ClassName{}</span><br></pre></td></tr></table></figure>
<a id="more"></a>
<p>抽象方法: 抽象方法是一种特殊的方法,只有方法的声明,但是没有方法的实现。抽象方法的声明格式为:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abstract void function();</span><br></pre></td></tr></table></figure></p>
<p>抽象类是为了继承而存在的,抽象出子类共有的一些特点,然后交给其具体的实现。</p>
<p>抽象类并不一定包含抽象方法,它和普通的类一样,也是可以拥有成员变量和普通的成员方法。</p>
<p>抽象类和普通的类的三点区别:</p>
<ul>
<li><p>抽象方法必须为public或者protected,缺省默认为public。</p>
</li>
<li><p>抽象方法不能用来创建对象。</p>
</li>
<li><p>如果一个类继承自一个抽象类,那么需要实现这个类的所有方法,如果没有实现这个类的所有方法,那么该类也需要被定义为abstract。<br><img src="http://p2sj58chj.bkt.clouddn.com/TIM截图20180801205707.png" alt="TIM截图20180801205707"></p>
</li>
</ul>
<p><strong>另外抽象类是可以有构造器的。</strong></p>
<h1 id="关于接口"><a href="#关于接口" class="headerlink" title="关于接口"></a>关于接口</h1><p>接口(interface)是对行为的抽象。在java 中定义一个接口的方式如下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">interface InterfaceName{}</span><br></pre></td></tr></table></figure></p>
<p>接口中可以含有方法和变量。其中变量会被隐式的指定为public final static 类型。其中的方法会被隐式的指定为public abstract,且不能有方法的实现(“Interface abstract methods cannot have body”)。</p>
<p>实现一个接口需要用到implements关键字<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">class ClassName implements InterfaceA,InterfaceB{}</span><br></pre></td></tr></table></figure></p>
<p>一个类可以实现多个接口。如果一个抽象类implements某个接口,可以不实现这个接口中的方法。非抽象类implements某个结构就必须要实现该接口中的所有方法。</p>
<h1 id="抽象类和接口的区别"><a href="#抽象类和接口的区别" class="headerlink" title="抽象类和接口的区别"></a>抽象类和接口的区别</h1><p>区别之处:</p>
<p>1、接口中的所有方法都是隐含的abstract的,而抽象类亦可以同时包含抽象和非抽象的方法。</p>
<p>2、一个类可以实现很多接口,但是只能继承自一个抽象类。</p>
<p>3、类可以不实现抽象类和接口中的所有方法,这种情况下的类需要被声明为abstract。</p>
<p>4、接口中的变量都是被默认声明为public static final的,而抽象类中的成员变量可以是各种类型的。</p>
<p>5、Java接口中的成员函数默认都是public的,抽象类中的成员函数可以是private、protected、public的。</p>
<p>其他:</p>
<p>1、接口是可以被接口继承的,通过extends关键字声明一个接口是一个接口的子接口,由于接口中的方法和常量都是public的,子接口将继承胡接口的全部方法和常量。</p>
<p>2、抽象类可以继承自实体类。</p>
]]></content>
<categories>