-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
524 lines (252 loc) · 307 KB
/
search.xml
File metadata and controls
524 lines (252 loc) · 307 KB
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>设计模式(1)工厂模式</title>
<link href="/2020/01/11/she-ji-mo-shi-1-gong-han-mo-shi/"/>
<url>/2020/01/11/she-ji-mo-shi-1-gong-han-mo-shi/</url>
<content type="html"><![CDATA[<h1 id="工厂模式"><a href="#工厂模式" class="headerlink" title="工厂模式"></a>工厂模式</h1><blockquote><p>定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行</p></blockquote><p><strong>主要解决</strong>:主要解决接口选择的问题。</p><p><strong>优点</strong>: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。</p><p><strong>缺点</strong>:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。</p><p><strong>实现方式</strong>:让工厂类根据名称创建对象,并返回该对象的抽象类</p><h1 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h1><p>场景:大家可能不知道,本人是从一个大山深处的一户果农家走出的孩子,最近家那边修了马路,有不少批发商去采购水果,什么桃啊、李啊、橘啊、西瓜啊等各种水果。他们根本不关心你是怎么种出来的,只要知道这里能收到某种水果,能以低价收购就成。</p><p>所以这里以批发商收购水果进行模拟。</p><h2 id="步骤1"><a href="#步骤1" class="headerlink" title="步骤1"></a>步骤1</h2><p>我们想卖出自己的农产品,就得让人家知道你的价格,我们先创建一个水果的接口类</p><p>Fruit.java</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Fruit</span> <span class="token punctuation">{</span> <span class="token keyword">void</span> <span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="步骤2"><a href="#步骤2" class="headerlink" title="步骤2"></a>步骤2</h2><p>既然卖农产品,就得有产品是吧,所以这里创建接口的实现类,这里就演示 2 种水果桃子、橘子</p><p>Peach.java</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Peach</span> <span class="token keyword">implements</span> <span class="token class-name">Fruit</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"桃子11.9"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>Orange.java</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Orange</span> <span class="token keyword">implements</span> <span class="token class-name">Fruit</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"橘子5.8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="步骤3"><a href="#步骤3" class="headerlink" title="步骤3"></a>步骤3</h2><p>交易市场,怎么理解呢?批发商来收购水果,不可能自己一家家进行拜访吧,所以会有有个地方进行组织,就是交易市场的意思。批发商只要来到这个地方,报出你要进购的水果可以了,避免了自己一家家上门收购。</p><p>FruitFactor.java</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FruitFactory</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">/** * 通过名称获取水果对象 * @param name * @return */</span> <span class="token keyword">public</span> Fruit <span class="token function">buyFruit</span><span class="token punctuation">(</span>FruitEnum name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>name <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> null<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>FruitEnum<span class="token punctuation">.</span>PEACH <span class="token operator">==</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Peach</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>FruitEnum<span class="token punctuation">.</span>ORANGE <span class="token operator">==</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Orange</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> null<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>这里增加了枚举类作为常量值</p><h2 id="步骤4"><a href="#步骤4" class="headerlink" title="步骤4"></a>步骤4</h2><p>通过交易市进购取水果,获取水果实现类的对象</p><p>Main.java</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Main</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> FruitFactory factory <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FruitFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 获取桃子对象</span> Fruit peach <span class="token operator">=</span> factory<span class="token punctuation">.</span><span class="token function">buyFruit</span><span class="token punctuation">(</span>FruitEnum<span class="token punctuation">.</span>PEACH<span class="token punctuation">)</span><span class="token punctuation">;</span> peach<span class="token punctuation">.</span><span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 获取橘子对象</span> Fruit orange <span class="token operator">=</span> factory<span class="token punctuation">.</span><span class="token function">buyFruit</span><span class="token punctuation">(</span>FruitEnum<span class="token punctuation">.</span>ORANGE<span class="token punctuation">)</span><span class="token punctuation">;</span> orange<span class="token punctuation">.</span><span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p><a href="https://github.com/HusyCoding/java-design-pattern.git" target="_blank" rel="noopener">GitHub 源码</a></p>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> 实战经验 </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>设计模式之简介</title>
<link href="/2020/01/11/she-ji-mo-shi-zhi-jian-jie/"/>
<url>/2020/01/11/she-ji-mo-shi-zhi-jian-jie/</url>
<content type="html"><![CDATA[<p>在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。</p><p>该书中总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。当然,后面又诞生了一类设计模式:J2EE 设计模式。</p><h1 id="三大类型"><a href="#三大类型" class="headerlink" title="三大类型"></a>三大类型</h1><p><strong>创建型模式共五种</strong>:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式。</p><p><strong>结构型模式共七种</strong>:适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式、代理模式、。</p><p><strong>行为型模式共十一种</strong>:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。</p><p>在<a href="https://www.runoob.com/design-pattern/design-pattern-intro.html" target="_blank" rel="noopener">菜鸟教程</a>中,结构型模式多了个过滤器模式(Filter、Criteria Pattern);行为型模式也多个了空对象模式(Null Object Pattern)</p><h1 id="六大原则"><a href="#六大原则" class="headerlink" title="六大原则"></a>六大原则</h1><p><strong>1、开闭原则(Open Close Principle)</strong></p><p>开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。</p><p><strong>2、里氏代换原则(Liskov Substitution Principle)</strong></p><p>里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。</p><p><strong>3、依赖倒转原则(Dependence Inversion Principle)</strong></p><p>这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。</p><p><strong>4、接口隔离原则(Interface Segregation Principle)</strong></p><p>这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。</p><p><strong>5、迪米特法则,又称最少知道原则(Demeter Principle)</strong></p><p>最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。</p><p><strong>6、合成复用原则(Composite Reuse Principle)</strong></p><p>合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。</p><h1 id="模式详解"><a href="#模式详解" class="headerlink" title="模式详解"></a>模式详解</h1><h2 id="工厂模式"><a href="#工厂模式" class="headerlink" title="工厂模式"></a>工厂模式</h2><blockquote><p>定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行</p></blockquote><p><strong>主要解决</strong>:主要解决接口选择的问题。</p><p><strong>优点</strong>: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。</p><p><strong>缺点</strong>:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。</p><h2 id="抽象工厂模式"><a href="#抽象工厂模式" class="headerlink" title="抽象工厂模式"></a>抽象工厂模式</h2><h2 id="单例模式"><a href="#单例模式" class="headerlink" title="单例模式"></a>单例模式</h2><h2 id="建造者模式"><a href="#建造者模式" class="headerlink" title="建造者模式"></a>建造者模式</h2><h2 id="原型模式"><a href="#原型模式" class="headerlink" title="原型模式"></a>原型模式</h2><h2 id="适配器模式"><a href="#适配器模式" class="headerlink" title="适配器模式"></a>适配器模式</h2><h2 id="装饰器模式"><a href="#装饰器模式" class="headerlink" title="装饰器模式"></a>装饰器模式</h2><h2 id="代理模式"><a href="#代理模式" class="headerlink" title="代理模式"></a>代理模式</h2><h2 id="外观模式"><a href="#外观模式" class="headerlink" title="外观模式"></a>外观模式</h2><h2 id="桥接模式"><a href="#桥接模式" class="headerlink" title="桥接模式"></a>桥接模式</h2><h2 id="组合模式"><a href="#组合模式" class="headerlink" title="组合模式"></a>组合模式</h2><h2 id="享元模式"><a href="#享元模式" class="headerlink" title="享元模式"></a>享元模式</h2><h2 id="策略模式"><a href="#策略模式" class="headerlink" title="策略模式"></a>策略模式</h2><h2 id="模板方法模式"><a href="#模板方法模式" class="headerlink" title="模板方法模式"></a>模板方法模式</h2><h2 id="观察者模式"><a href="#观察者模式" class="headerlink" title="观察者模式"></a>观察者模式</h2><h2 id="迭代子模式"><a href="#迭代子模式" class="headerlink" title="迭代子模式"></a>迭代子模式</h2><h2 id="责任链模式"><a href="#责任链模式" class="headerlink" title="责任链模式"></a>责任链模式</h2><h2 id="命令模式"><a href="#命令模式" class="headerlink" title="命令模式"></a>命令模式</h2><h2 id="备忘录模式"><a href="#备忘录模式" class="headerlink" title="备忘录模式"></a>备忘录模式</h2><h2 id="状态模式"><a href="#状态模式" class="headerlink" title="状态模式"></a>状态模式</h2><h2 id="访问者模式"><a href="#访问者模式" class="headerlink" title="访问者模式"></a>访问者模式</h2><h2 id="中介者模式"><a href="#中介者模式" class="headerlink" title="中介者模式"></a>中介者模式</h2><h2 id="解释器模式"><a href="#解释器模式" class="headerlink" title="解释器模式"></a>解释器模式</h2><h1 id="源码实现"><a href="#源码实现" class="headerlink" title="源码实现"></a>源码实现</h1><ul><li><a href="https://github.com/HusyCoding/java-design-pattern.git" target="_blank" rel="noopener">GitHub 源码</a></li></ul><h1 id="资料参考"><a href="#资料参考" class="headerlink" title="资料参考"></a>资料参考</h1><ul><li><a href="https://www.runoob.com/design-pattern/design-pattern-intro.html" target="_blank" rel="noopener">设计模式 | 菜鸟教程</a></li><li>Head First设计模式</li></ul>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>性能优化(1)MySQL查询脚本优化</title>
<link href="/2020/01/10/xing-neng-you-hua-1-mysql-cha-xun-jiao-ben-you-hua/"/>
<url>/2020/01/10/xing-neng-you-hua-1-mysql-cha-xun-jiao-ben-you-hua/</url>
<content type="html"><![CDATA[<h1 id="SQL-的执行顺序"><a href="#SQL-的执行顺序" class="headerlink" title="SQL 的执行顺序"></a>SQL 的执行顺序</h1><p>要想优化MySQL的查询语句,必须先了解查询 SQL 的执行顺序</p><p>一个完整的Query SQL,如下:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">select</span> <span class="token keyword">distinct</span> <span class="token operator"><</span>select_list<span class="token operator">></span><span class="token keyword">from</span> <span class="token operator"><</span>left_table<span class="token operator">></span><span class="token operator"><</span>join_type<span class="token operator">></span> <span class="token keyword">join</span> <span class="token operator"><</span>right_table<span class="token operator">></span> <span class="token keyword">on</span> <span class="token operator"><</span>join_condition<span class="token operator">></span><span class="token keyword">where</span> <span class="token operator"><</span>where_condition<span class="token operator">></span><span class="token keyword">group</span> <span class="token keyword">by</span> <span class="token operator"><</span>group_by_list<span class="token operator">></span><span class="token keyword">having</span> <span class="token operator"><</span>having_condition<span class="token operator">></span><span class="token keyword">order</span> <span class="token keyword">by</span> <span class="token operator"><</span>order_by_condition<span class="token operator">></span><span class="token keyword">limit</span> <span class="token operator"><</span><span class="token keyword">limit</span> number<span class="token operator">></span></code></pre><p>SQL执行顺序如下:</p><blockquote><p> 1、from <left_table><join_type></p><p> 2、on <join_condition></p><p> 3、<join_type> join <right_table></p><p> 4、where <where_condition></p><p> 5、group by <group_by_list></p><p> 6、having <having_condition></p><p> 7、select</p><p> 8、distinct <select_list></p><p> 9、order by <order_by_condition></p><p> 10、limit <limit_number></p></blockquote><h1 id="常见优化方案"><a href="#常见优化方案" class="headerlink" title="常见优化方案"></a>常见优化方案</h1><p>在遵循 MySQL 数据库表结构设计规约和MySQL 索引设计规约的情况下,对慢查询进行优化</p><h2 id="脚本规范优化"><a href="#脚本规范优化" class="headerlink" title="脚本规范优化"></a>脚本规范优化</h2><blockquote><p> 禁止使用 select * 方式,必须使用SELECT <字段列表> 查询</p><p> 禁止使用不含字段列表的INSERT语句,如:insert into values (‘a’,’b’,’c’);</p><p> 禁止使用order by rand() 进行随机排序</p><p> 只需要查询一行数据时使用 LIMIT 1</p><p> 充分利用表上已经存在的索引,并遵循最左前缀原则</p><p> 避免使用 join 关联太多的表</p><p> 对应同一列进行or判断时,使用in代替 or</p><p> 在明显不会有重复值时使用 union all 而不是 union</p><p> 拆分复杂的大SQL为多个小SQL</p></blockquote><p><strong>避免使用JOIN关联太多的表</strong></p><p>在Mysql中,对于同一个SQL多关联(join)一个表,就会多分配一个关联缓存,如果在一个SQL中关联的表越多,所占用的内存也就越大。容易造成服务器内存溢出的情况;Mysql最多允许关联61个表,建议不超过5个。</p><p><strong>对应同一列进行or判断时,使用in代替or</strong></p><p>in的值不要超过500个in操作可以更有效的利用索引,or大多数情况下很少能利用到索引。</p><p>建议控制 in 的个数在200内</p><p>建议改为 inner join 查询,或者使用 union 使用连接(join)来代替子查询,或者尽量少用JOIN 查询,尽量单表查询</p><p>因为执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表。</p><h2 id="索引失效情况"><a href="#索引失效情况" class="headerlink" title="索引失效情况"></a>索引失效情况</h2><blockquote><p> 最左前缀原则导致失效</p><p> 模糊查询导致失效</p><p> 隐式转换导致失效</p><p> OR 或 IN 导致失效</p><p> 函数运算导致失效</p><p> NULL 值判断导致失效</p><p> 不等号、大于小于号导致失效</p><p> 全表查比索引查效率高</p><p> 连接查询中,按照优化器顺序的第一张表不会走索引</p></blockquote><p>下面我们便使用 explain 分析一下</p><p>当前环境,MySQL 版本 8.0,引擎 InnoDB</p><p> 这里创建 2 个表 user 和 job ,具体数据表结构如下:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">DROP</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token keyword">EXISTS</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span><span class="token punctuation">;</span><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span> <span class="token punctuation">(</span> <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">INT</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>name<span class="token punctuation">`</span> <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>sex<span class="token punctuation">`</span> <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>age<span class="token punctuation">`</span> <span class="token keyword">INT</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>address<span class="token punctuation">`</span> <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span> <span class="token keyword">USING</span> <span class="token keyword">BTREE</span><span class="token punctuation">,</span> <span class="token keyword">INDEX</span> <span class="token punctuation">`</span>idx_sex<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>sex<span class="token punctuation">`</span><span class="token punctuation">)</span> <span class="token keyword">USING</span> <span class="token keyword">BTREE</span><span class="token punctuation">,</span> <span class="token keyword">INDEX</span> <span class="token punctuation">`</span>idx_age<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>age<span class="token punctuation">`</span><span class="token punctuation">)</span> <span class="token keyword">USING</span> <span class="token keyword">BTREE</span><span class="token punctuation">,</span> <span class="token keyword">INDEX</span> <span class="token punctuation">`</span>idx_name_age_address<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>name<span class="token punctuation">`</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>age<span class="token punctuation">`</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>address<span class="token punctuation">`</span><span class="token punctuation">)</span> <span class="token keyword">USING</span> <span class="token keyword">BTREE</span><span class="token punctuation">)</span><span class="token keyword">COLLATE</span><span class="token operator">=</span><span class="token string">'utf8mb4_0900_ai_ci'</span><span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span></code></pre><h3 id="最左前缀原则导致失效"><a href="#最左前缀原则导致失效" class="headerlink" title="最左前缀原则导致失效"></a><strong>最左前缀原则导致失效</strong></h3><p>这里测试 <code>user</code> 表的 <code>idx_name_age_sex</code> 索引</p><p><img src="clipboard.png" alt=""></p><p><img src="clipboard-1578661516953.png" alt=""></p><p><img src="clipboard-1578661521717.png" alt=""></p><p><img src="clipboard-1578661527077.png" alt=""></p><p>有上图可以看出,<strong>最左前缀原则是指在联合索引中,第一个索引列,必须存在</strong>,否则无法使用该联合索引</p><p><strong>为什么是这种规则呢?</strong></p><p>因为 B+ 树的结构是复合型数据结构,必须按照从左到右的顺序建立树,如果没有第一列,就不知道该怎么找到节点。</p><h3 id="模糊查询导致失效"><a href="#模糊查询导致失效" class="headerlink" title="模糊查询导致失效"></a>模糊查询导致失效</h3><p><img src="clipboard-1578661567723.png" alt=""></p><p>由上图可知在 where 子查询条件中,模糊查询 like 在使用 ‘%’ 时,出现的位置不同,索引效果不同,很明显:模糊查询中,使用后缀查询会是索引失效,但可以使用前缀查询。</p><p>不过,在实际开发中前缀模糊查询的方式往往不能满足需求</p><h3 id="隐式转换导致失效"><a href="#隐式转换导致失效" class="headerlink" title="隐式转换导致失效"></a>隐式转换导致失效</h3><p>隐式转换是指查询条件中的索引列的类型和查询条件值得类型不一致,而发生了隐式转换。</p><p>一般指,数字转换为字符串的情况</p><p><img src="clipboard-1578661602653.png" alt=""></p><p><img src="clipboard-1578661607014.png" alt=""></p><p>有上图可以看出,在 <code>name = 111</code> 的条件中,虽然找到了 <code>idx_name_age_sex</code> 索引,但key 列为空,索引并没有被使用</p><h3 id="OR-或-IN-导致失效"><a href="#OR-或-IN-导致失效" class="headerlink" title="OR 或 IN 导致失效"></a>OR 或 IN 导致失效</h3><p><img src="clipboard-1578661626158.png" alt=""></p><p><img src="clipboard-1578661634793.png" alt=""></p><p>通过上图我们可以非常诧异!! 为什么?网络上不是说 IN 或 NOT IN 会导致索引失效吗?</p><p>不要惊慌,以上测试,我们的 <code>idx_name_age_address</code> 采用的BTREE 算法,</p><p>如果我们换成 HASH 算法呢?</p><p>结果还是一下…</p><p>所以,总结一下:在 MySQL 8.0 ,引擎为 InnoDB 的条件下,IN 或者 NOT IN 在使用索引才行时,无论采用 BTREE 还是 HASH 算法,索引都不会失效</p><p>那其他版本了,我从 5.6.43-log 、5.7.27 版本中又测试了一下,发现在MySQL 5.6 版本中,IN 和 NOT IN 是无法使用索引的</p><p><strong>个人认为,在在MySQL 5.6 版本和其以下版本中,IN 和 NOT IN 才会无法使用索引的</strong></p><p><strong>对应 OR 的情况:</strong></p><p><img src="clipboard-1578661662739.png" alt=""></p><p><img src="clipboard-1578661669184.png" alt=""></p><p><img src="clipboard-1578661674389.png" alt=""></p><p>由上图可以看出, <strong>or 是使索引失效,指的是 or 两边不同列的情况。</strong></p><p>对于这种失效情况,我们可以使用覆盖索引进行优化,如下:</p><p><img src="clipboard-1578661687904.png" alt=""></p><p>所查出的列全都属于 <code>idx_name_age_address</code> 索引的列。</p><p>建议:使用 IN 代替 OR 查询</p><h3 id="函数运算导致失效"><a href="#函数运算导致失效" class="headerlink" title="函数运算导致失效"></a>函数运算导致失效</h3><p>在where子句中,索引列参与到函数计算时索引会失效</p><p><img src="clipboard-1578661709607.png" alt=""></p><p><img src="clipboard-1578661714205.png" alt=""></p><p><img src="clipboard-1578661719118.png" alt=""></p><p>由上图可见,当我们将索引列 进行函数运算时,索引将会失效;</p><p>在实际开发中,我们最常见的就是对日期、时间字段进行转换了,千万不要在这类字段上使用函数,否则会索引失效,如下:</p><p>反例:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">where</span> <span class="token keyword">date</span><span class="token punctuation">(</span>create_time<span class="token punctuation">)</span><span class="token operator">=</span><span class="token string">'2019-01-01'</span></code></pre><p>推荐:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">where</span> create_time <span class="token operator">></span> date_format<span class="token punctuation">(</span><span class="token string">'2019-01-01 12:12:12'</span><span class="token punctuation">,</span><span class="token string">'%Y-%m-%d'</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">--或者</span><span class="token keyword">where</span> create_time <span class="token operator"><=</span> <span class="token string">'2019-01-01 00:00:00'</span> <span class="token operator">and</span> create_time <span class="token operator">></span> <span class="token string">'2019-01-01 23:59:59'</span> </code></pre><h3 id="NULL-值判断导致失效"><a href="#NULL-值判断导致失效" class="headerlink" title="NULL 值判断导致失效"></a>NULL 值判断导致失效</h3><p><img src="clipboard-1578661784240.png" alt=""></p><p><img src="clipboard-1578661789470.png" alt=""></p><p>通过上图我们可以发现 IS NULL 或 IS NOT NULL 不会导致索引失效</p><p>这里我们可以思考一下,这是不是也如同 IN 的效果一样呢?是与版本有关</p><p>在 5.6.46-log 版本中, IS NULL 是会走索引的,但是 IS NOT NULL 出现了特别的结果</p><p>当 name 字段为 NULL 数据条数在2条内,索引依然有效,超过2条索引会失效, NOT NULL 也存在相同的规则,</p><p>如下,数据条数在2条内:</p><p><img src="clipboard-1578661804578.png" alt=""></p><p><img src="clipboard-1578661808662.png" alt=""></p><p><img src="clipboard-1578661815292.png" alt=""></p><p><img src="clipboard-1578661822200.png" alt=""></p><p> MySQL 5.7 同样存在此问题。但 5.8 不会出现这情况。不过这是为什么呢?下面有篇文章解释的非常不错</p><p><a href="https://mp.weixin.qq.com/s/CEJFsDBizdl0SvugGX7UmQ" target="_blank" rel="noopener">https://mp.weixin.qq.com/s/CEJFsDBizdl0SvugGX7UmQ</a></p><p><strong>总结:在MySQL 5.8 版本中,IS NULL 和 IS NOT NULL 不会使索引失效,但 MySQL 5.6,5.7 索引不一定会失效,因为可能全表查比索引查效率更高</strong></p><h3 id="不等号、大于小于号导致失效"><a href="#不等号、大于小于号导致失效" class="headerlink" title="不等号、大于小于号导致失效"></a>不等号、大于小于号导致失效</h3><p><img src="clipboard-1578661866149.png" alt=""></p><p>在MySQL 5.8 版本 ,不等号、大于小于号不会导致索引失效,但是在5.6,5.7 版本中 “!=” ,也会因为数据量不同,效果不同,如下:</p><p><img src="clipboard-1578661878814.png" alt=""></p><p><img src="clipboard-1578661887905.png" alt=""></p><p><strong>总结:</strong></p><p><strong>在MySQL 5.8 版本中,不等号 、大于小于号不会使索引失效,</strong></p><p><strong>但 MySQL 5.6,5.7 中 大于小于号不会使索引失效 ,但不等号索引不一定会失效,因为可能全表查比索引查效率更高</strong></p>]]></content>
<categories>
<category> SQL </category>
</categories>
<tags>
<tag> 实战经验 </tag>
<tag> 性能优化 </tag>
<tag> MySQL </tag>
</tags>
</entry>
<entry>
<title>MySQL-进阶之Explain详解</title>
<link href="/2020/01/10/mysql-jin-jie-zhi-explain-xiang-jie/"/>
<url>/2020/01/10/mysql-jin-jie-zhi-explain-xiang-jie/</url>
<content type="html"><![CDATA[<p>在 MySQL 性能优化中,慢查询优化是我们经常需要解决的问题。通常我们可以使用 Explain 命令来了解 SQL 语句的执行计划,仅对select语句有效</p><h1 id="Explain"><a href="#Explain" class="headerlink" title="Explain"></a><strong>Explain</strong></h1><p>代码演示如下</p><p><img src="clipboard.png" alt=""></p><p>explain 查询会输出 12 列,如:id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、extra</p><p>以下分别介绍一下,其中type 和 key 是我们看一个SQL 性能好坏的重点。</p><h2 id="select-type"><a href="#select-type" class="headerlink" title="select_type"></a>select_type</h2><p>表示查询类型,主要用于区别普通查询,联合查询,子查询等的复杂查询</p><blockquote><p> <strong>SIMPLE</strong>:简单SELECT(不使用UNION或子查询)<br> <strong>PRIMARY</strong>:最外面的SELECT<br> <strong>UNION</strong>:UNION中的第二个或后面的SELECT语句<br> <strong>DEPENDENT UNION</strong>:UNION中的第二个或后面的SELECT语句,取决于外面的查询<br> <strong>UNION RESULT</strong>:UNION 的结果<br> <strong>SUBQUERY</strong>:子查询中的第一个SELECT<br> <strong>DEPENDENT SUBQUERY</strong>:子查询中的第一个SELECT,取决于外面的查询<br> <strong>DERIVED</strong>:导出表的SELECT(FROM子句的子查询)</p></blockquote><p><strong>table</strong>数据库中表名称或别名</p><h2 id="type"><a href="#type" class="headerlink" title="type"></a>type</h2><p>表示对表访问方式;常用的类型有: <strong>ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)</strong></p><p><strong>注意:一般保证查询至少达到range级别,最好能达到ref</strong></p><blockquote><p> <strong>ALL</strong>:Full Table Scan, MySQL将遍历全表以找到匹配的行<br> <strong>index</strong>:Full Index Scan,index与ALL区别为index类型只遍历索引树<br> <strong>range</strong>:只检索给定范围的行,如: between/in、> 、< 、in 等方式<br> <strong>ref</strong>:表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值<br> <strong>eq_ref</strong>: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件<br> <strong>const/system</strong>: 当MySQL对查询最多有一个匹配行,在这行的列值可被优化器剩余部分认为是常数。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system<br> <strong>NULL</strong>:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。</p></blockquote><h2 id="possible-keys"><a href="#possible-keys" class="headerlink" title="possible_keys"></a>possible_keys</h2><p>指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)</p><h2 id="key"><a href="#key" class="headerlink" title="key"></a>key</h2><p><strong>显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。</strong></p><p><strong>key_len:</strong>表示索引中使用的字节数</p><p><strong>ref:</strong>列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值</p><p><strong>rows:</strong>估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数</p><h2 id="Extra"><a href="#Extra" class="headerlink" title="Extra"></a>Extra</h2><blockquote><p> Using index:表示相应的select操作用使用覆盖索引,避免访问了表的数据行。如果同时出现using where,表名索引被用来执行索引键值的查找;如果没有同时出现using where,表名索引用来读取数据而非执行查询动作。</p><p> Using where:表明使用where过滤,当有where子句时,extra都会有说明。</p><p> Using temporary:表示需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by</p><p> Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”</p><p> Distinct:发现第1个匹配行后,停止为当前的行组合搜索更多的行</p><p> Not exists:表示MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。</p><p> Range checked for each record:mysql没有发现好的索引可用,速度比没有索引要快得多。</p><p> Using sort_union(…)/Using union(…)/Using intersect(…):表明 index_merge 联接类型合并索引扫描。</p><p> Using index for group-by:表明可以在索引中找到GROUP BY或DISTINCT所需的所有数据,不需要查询实际的表。</p></blockquote><p><strong>资料参考</strong></p><ul><li>高性能MySQL(第3版).pdf</li></ul>]]></content>
<categories>
<category> SQL </category>
</categories>
<tags>
<tag> 实战经验 </tag>
<tag> 性能优化 </tag>
<tag> MySQL </tag>
</tags>
</entry>
<entry>
<title>性能优化(2)MySQL模糊查询</title>
<link href="/2020/01/09/xing-neng-you-hua-2-mysql-mo-hu-cha-xun/"/>
<url>/2020/01/09/xing-neng-you-hua-2-mysql-mo-hu-cha-xun/</url>
<content type="html"><![CDATA[<p>关于MySQL模糊查询有优化问题,网络上如下几种方案:</p><ul><li>模糊查询修改为后缀模糊查询</li><li>使用LOCATE(substr,str,pos)方法</li><li>使用POSITION(substr IN field)方法</li><li>使用INSTR(str,substr)方法</li></ul><p>这里测试一下真假 </p><h1 id="LOCATE、POSITION、INSTR"><a href="#LOCATE、POSITION、INSTR" class="headerlink" title="LOCATE、POSITION、INSTR"></a>LOCATE、POSITION、INSTR</h1><p><strong>环境准备</strong></p><p>MySQL 版本:8.0.16</p><p>搜索引擎:InnoDB</p><p>数据库表结构 :</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span> <span class="token punctuation">(</span> <span class="token punctuation">`</span>id<span class="token punctuation">`</span> <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token comment" spellcheck="true"># 考虑特殊情况使用 UUID 主键</span> <span class="token punctuation">`</span>name<span class="token punctuation">`</span> <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token punctuation">`</span>create_time<span class="token punctuation">`</span> <span class="token keyword">TIMESTAMP</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>id<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">INDEX</span> <span class="token punctuation">`</span>idx_name<span class="token punctuation">`</span> <span class="token punctuation">(</span><span class="token punctuation">`</span>name<span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">COLLATE</span><span class="token operator">=</span><span class="token string">'utf8mb4_0900_ai_ci'</span><span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span><span class="token punctuation">;</span></code></pre><p>数据量大小:4900002</p><p><img src="%E6%95%B0%E6%8D%AE%E9%87%8F%E5%A4%A7%E5%B0%8F.png" alt=""></p><p>当前系统CPU 、磁盘IO状态:</p><p><img src="/1578033488870.png" alt=""></p><p>模糊查询SQL执行3次的结果:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span> <span class="token keyword">WHERE</span> <span class="token punctuation">`</span>name<span class="token punctuation">`</span> <span class="token operator">LIKE</span> <span class="token string">'%躬%'</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">/* 影响到的行: 0 Found rows: 9,525 查询: 0.328 sec*/</span><span class="token comment" spellcheck="true">/* 影响到的行: 0 Found rows: 9,525 查询: 0.281 sec*/</span><span class="token comment" spellcheck="true">/* 影响到的行: 0 Found rows: 9,525 查询: 0.282 sec*/</span></code></pre><p>可以看出平均需要 3 s</p><p>使用后缀模糊查询</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> <span class="token punctuation">`</span><span class="token keyword">user</span><span class="token punctuation">`</span> <span class="token keyword">WHERE</span> <span class="token punctuation">`</span>name<span class="token punctuation">`</span> <span class="token operator">LIKE</span> <span class="token string">'躬%'</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">/* 影响到的行: 0 Found rows: 1,453 查询: 0.094 sec. */</span><span class="token comment" spellcheck="true">/* 影响到的行: 0 Found rows: 1,453 查询: 0.078 sec. */</span><span class="token comment" spellcheck="true">/* 影响到的行: 0 Found rows: 1,453 查询: 0.079 sec. */</span></code></pre><p>以上可以看出 SQL语句可以使用了索引,搜索的效率大大的提高了!</p><p>但是,我们在做模糊查询的时候,非特定情况,这种前缀查询并不能满足需求,所以,并不合适所有的模糊查询</p><p>而使用其他函数呢?</p><p><img src="1578035852164.png" alt="1578035852164"></p><p>可以看出 LOCATE、POSITION、INSTR并不能有效的提高查询效率。</p><p>具体怎么优化模糊查询的SQL,小编至今还没找到良好的处理方式,如果你知道,麻烦留言指点:pray::pray::pray:</p>]]></content>
<categories>
<category> SQL </category>
</categories>
<tags>
<tag> 实战经验 </tag>
<tag> 性能优化 </tag>
<tag> MySQL </tag>
</tags>
</entry>
<entry>
<title>规范之MySQL表设计规约</title>
<link href="/2020/01/09/gui-fan-zhi-mysql-biao-she-ji-gui-yue/"/>
<url>/2020/01/09/gui-fan-zhi-mysql-biao-she-ji-gui-yue/</url>
<content type="html"><![CDATA[<h1 id="基本规范"><a href="#基本规范" class="headerlink" title="基本规范"></a>基本规范</h1><p>基本要求如下:</p><blockquote><p> 1、所有表必须使用Innodb存储引擎</p><p> 2、数据库和表的字符集统一使用UTF8</p><p> 3、所有表和字段都需要添加注释</p><p> 4、尽量控制单表数据量的大小,建议控制在500万以内</p><p> 5、谨慎使用MySQL分区表</p><p> 6、尽量做到冷热数据分离,减小表的宽度</p><p> 7、禁止在表中建立预留字段</p><p> 8、禁止在数据库中存储图片,文件等大的二进制数据</p></blockquote><p>以下便一一进行分析</p><p><strong>1、所有表必须使用Innodb存储引擎</strong></p><p>没有特殊要求(即Innodb无法满足的功能如:列存储,存储空间数据等)的情况下,所有表必须使用Innodb存储引擎(mysql5.5之前默认使用Myisam,5.6以后默认的为Innodb)Innodb 支持事务,支持行级锁,更好的恢复性,高并发下性能更好</p><p><strong>2、数据库和表的字符集统一使用UTF8</strong></p><p>兼容性更好,统一字符集可以避免由于字符集转换产生的乱码,不同的字符集进行比较前需要进行转换会造成索引失效</p><p><strong>3、所有表和字段都需要添加注释</strong></p><p>使用comment从句添加表和列的备注 从一开始就进行数据字典的维护</p><p><strong>4、尽量控制单表数据量的大小,建议控制在500万以内</strong></p><p>500万并不是MySQL数据库的限制,过大会造成修改表结构,备份,恢复都会有很大的问题可以用历史数据归档(应用于日志数据),分库分表(应用于业务数据)等手段来控制数据量大小</p><p><strong>5、谨慎使用MySQL分区表</strong></p><p>分区表在物理上表现为多个文件,在逻辑上表现为一个表zai选择分区键,跨分区查询效率可能更低,建议采用物理分表的方式管理大数据</p><p><strong>6、尽量做到冷热数据分离,减小表的宽度</strong></p><p>MySQL限制每个表最多存储4096列,并且每一行数据的大小不能超过65535字节</p><p>表越宽,把表装载进内存缓冲池时所占用的内存也就越大,也会消耗更多的IO</p><p>减少磁盘IO,保证热数据的内存缓存命中率;</p><p>更有效的利用缓存,避免读入无用的冷数据 经常一起使用的列放到一个表中(避免更多的关联操作)</p><p><strong>7、禁止在表中建立预留字段</strong></p><p>预留字段的命名很难做到见名识义 预留字段无法确认存储的数据类型,所以无法选择合适的类型 对预留字段类型的修改,会对表进行锁定</p><p><strong>8、禁止在数据库中存储图片,文件等大的二进制数据</strong></p><p>通常文件很大,会短时间内造成数据量快速增长,数据库进行数据库读取时,通常会进行大量的随机IO操作,文件很大时,IO操作很耗时 通常存储于文件服务器,数据库只存储文件地址信息</p><h1 id="数据库字段设计"><a href="#数据库字段设计" class="headerlink" title="数据库字段设计"></a>数据库字段设计</h1><p>基本要求如下:</p><blockquote><p> 1、优先选择符合存储需要的最小的数据类型</p><p> 2、主键列最好定义为自增主键</p><p> 3、同财务相关的金额类数据必须使用DECIMAL类型</p><p> 4、使用TIMESTAMP(4个字节)而非DATETIME (8个字节)</p><p> 5、尽可能把所有列定义为NOT NULL</p><p> 6、避免使用TEXT、BLOB数据类型</p><p> 7、避免使用ENUM类型</p><p> 尽可能单表不要有太多字段,建议在20以内</p></blockquote><p>下面一一进行分析:</p><p><strong>1、最小数据类型</strong></p><p>因为列的字段越大,建立索引时所需要的空间也就越大,这样一页中所能存储的索引节点的数量也就越少也越少,在遍历时所需要的IO次数也就越多, 索引的性能也就越差</p><p><strong>优化方案</strong></p><ul><li><strong>尽量使用最小数字类型,如果非负则加上UNSIGNED,</strong>特别对于非负型的数据(如自增ID、整型IP)因为:无符号相对于有符号可以多出一倍的存储空间。TINYINT< SMALLINT< MEDIUM_INT< INT < BIGINT</li><li><strong>尽可能使用 varchar代替 char,</strong>因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。当然列值确定为固定长度,这优先使用char类型</li><li><strong>尽可能使用整数代替字符串类型</strong>,如1,性别:可以使用 tinyint,它比 char 更合适;如2:将IP地址转换成整形数据,IP处理函数inet_aton()和inet_ntoa();插入数据前,先用inet_aton把ip地址转为整型,可以节省空间。显示数据时,使用inet_ntoa把整型的ip地址转为地址显示即可。</li></ul><p><strong>char和varchar区别:</strong></p><p>char是属于固定长度的字符类型,而varchar是属于可变长度的字符类型,</p><p>因为其长度固定,方便程序的存储与查找,char的存取数度还是要比varchar要快得多,但是char也为此付出的是空间的代价,这属于时间换空间的做法,varchar 则相反,属于空间换时间</p><p><strong>2、主键列最好定义为自增主键</strong></p><blockquote><p> InnoDB使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。</p><p> 这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)。</p></blockquote><p>使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页,使用UUID、MD5、HASH、字符串列作为主键无法保证数据的顺序增长.</p><p><strong>自增主键优缺点</strong></p><blockquote><p> 优点:</p><ol><li><p>数据库自动编号,速度快,而且是增量增长,按顺序存放,对于检索非常有利;</p></li><li><p>数字型,占用空间小,易排序,在程序中传递也方便;</p><p>缺点:</p></li><li><p>因为自动增长,导入数据时很难保证原系统的ID不发生主键冲突</p></li><li><p>自增主键插入式顺序插入,存在并发插入时导致间隙锁竞争</p></li></ol></blockquote><p><strong>UUID主键优缺点</strong></p><blockquote><p> 优点:</p><ol><li><p>能够保证独立性,程序可以在不同的数据库间迁移,效果不受影响。 </p></li><li><p>全局的唯一性,不仅是表独立的,而且是库独立的,这点在你想切分数据库的时候尤为重要。</p><p>缺点:</p></li><li><p>UUID占空间大, 如果你建的索引越多, 影响越严重,且会有页分裂和碎片存在导致。</p></li><li><p>UUID之间比较大小相对数字慢不少, 影响查询速度</p></li><li><p>影响插入速度, 并且造成硬盘使用率低</p></li></ol></blockquote><p><strong>3、同财务相关的金额类数据必须使用decimal类型</strong></p><p>float,double 是非精准浮点类型,要想精准需要使用 decimal</p><p><strong>4、使用TIMESTAMP(4个字节)而非DATETIME (8个字节)</strong></p><p>TIMESTAMP 只使用DATETIME一半的存储空间、并且会根据时区变化,缺点TIMESTAMP的时间范围要小</p><p>TIMESTAMP 存储的时间范围 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07。</p><p>TIMESTAMP 占用4字节和INT相同,但比INT可读性高;超出TIMESTAMP取值范围的使用DATETIME类型存储。</p><p>经常会有人用字符串存储日期型的数据(不正确的做法),</p><p>缺点1:无法用日期函数进行计算和比较;</p><p>缺点2:用字符串存储日期要占用更多的空间</p><p><strong>5、尽可能把所有列定义为NOT NULL</strong></p><p>注意:把 NULL 改成 NOT NULL 对索引的性能并没有明显的提升。避免使用 NULL 的目的,是便于代码的可读性和可维护性。同时也便于避免下文即将出现的一些稀奇古怪的错误,如:</p><ul><li>NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回非空行的结果集</li><li>使用 concat 函数拼接时,首先要对各个字段进行非 NULL 判断,否则只要任何一个字段为空都会造成拼接的结果为 NULL</li><li>当用count函数进行统计时,NULL 列不会计入统计</li><li>查询空行数据,用 is NULL</li><li>NULL 列需要更多的存储空间,一般需要一个额外的字节作为判断是否为 NULL 的标志位。</li><li>IS NULL 或者 IS NOT NULL 索引会失效</li></ul><p><strong>6、TEXT、BLOB数据类型</strong></p><p>Mysql内存临时表不支持TEXT、BLOB这样的大数据类型,如果查询中包含这样的数据,在排序等操作时,就不能使用内存临时表,必须使用磁盘临时表进行。</p><p>对于这种数据,Mysql还是要进行二次查询,会使sql性能变得很差,但是不是说一定不能使用这样的数据类型。</p><p>因为MySQL对索引字段长度是有限制的,所以TEXT类型只能使用前缀索引,并且TEXT列上是不能有默认值的。</p><p><strong>7、避免使用ENUM类型</strong></p><p>修改ENUM值需要使用ALTER语句;<strong>ENUM类型的ORDER BY操作效率低,需要额外操作</strong>;禁止使用数值作为ENUM的枚举值</p><h1 id="索引设计规范"><a href="#索引设计规范" class="headerlink" title="索引设计规范"></a>索引设计规范</h1><p>基本要求如下:</p><blockquote><p> 限制每张表上的索引数量,建议单张表索引不超过5个</p><p> 禁止给表中的每一列都建立单独的索引</p><p> 每个Innodb表必须有个主键</p><p> 如何选择索引列的顺序</p><p> 优先考虑覆盖索引</p><p> 避免使用外键约束</p></blockquote><p><strong>1、限制每张表上的索引数量</strong></p><p>索引并不是越多越好!索引可以提高效率同样可以降低效率。</p><p>因为mysql优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,就会增加mysql优化器生成执行计划的时间,同样会降低查询性能。</p><p><strong>2、禁止给表中的每一列都建立单独的索引</strong></p><p>mysql5.6版本以后,虽然有了合并索引的优化方式,但是还是远远没有使用一个联合索引的查询方式好。</p><p>推荐:MySQL 索引B+树原理,以及建索引的几大原则。</p><p><strong>3、每个Innodb表必须有个主键</strong></p><p>Innodb是一种索引组织表:数据的存储的逻辑顺序和索引的顺序是相同的;表的存储顺序只能有一种 Innodb是按照主键索引的顺序来组织表的。</p><p>建议1:不要使用更新频繁的列作为主键,不适用多列主键(相当于联合索引) </p><p>建议2:不要使用UUID、MD5、HASH、字符串列作为主键(无法保证数据的顺序增长)。</p><p>建议3:主键使用自增ID值。</p><p><strong>4、如何选择索引列的顺序</strong></p><p>区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数)</p><p>尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO性能也就越好);</p><p>使用最频繁的列放到联合索引的左侧(这样可以比较少的建立一些索引)。</p><p>避免建立冗余索引和重复索引;因为这样会增加查询优化器生成执行计划的时间。</p><p><strong>5、优先考虑覆盖索引</strong></p><p>对于频繁的查询优先考虑使用覆盖索引;好处在于避免进行索引的二次查询,不必通过二级索引查到主键之后再去查询数据,减少了IO操作,提升了查询效率。</p><p>覆盖索引特点如下:</p><p>1、索引包含了(或覆盖)(或覆盖)查询语句中字段与条件的数据,即只需扫描索引而无须回表,包含了所有查询字段(select,where,join,ordery by,group by包含的字段</p><p>2、只能使用B-Tree索引做覆盖索引</p><p>3、EXPLAIN的Extra列可以看到“Using index”的信息</p><p><strong>6、避免使用外键约束</strong></p><p>外键会影响父表和子表的写操作从而降低性能。可在表与表之间的关联键上建立索引代替</p><h1 id="SQL脚本规范"><a href="#SQL脚本规范" class="headerlink" title="SQL脚本规范"></a>SQL脚本规范</h1><p>基本规范</p><blockquote><p> 禁止使用SELECT * 必须使用SELECT <字段列表> 查询</p><p> 禁止使用不含字段列表的INSERT语句,如:insert into values (‘a’,’b’,’c’);</p><p> 禁止使用order by rand() 进行随机排序</p><p> 避免数据类型的隐式转换</p><p> 避免使用JOIN关联太多的表</p><p> 对应同一列进行or判断时,使用in代替or</p><p> 充分利用表上已经存在的索引</p><p> WHERE从句中禁止对列进行函数转换和计算</p><p> 在明显不会有重复值时使用UNION ALL而不是UNION</p><p> 拆分复杂的大SQL为多个小SQL</p></blockquote><p><strong>避免使用JOIN关联太多的表</strong></p><p>在Mysql中,对于同一个SQL多关联(join)一个表,就会多分配一个关联缓存,如果在一个SQL中关联的表越多,所占用的内存也就越大。容易造成服务器内存溢出的情况</p><p>Mysql最多允许关联61个表,建议不超过5个。</p><p><strong>对应同一列进行or判断时,使用in代替or</strong></p><p>in的值不要超过500个in操作可以更有效的利用索引,or大多数情况下很少能利用到索引。</p><p><strong>WHERE从句中禁止对列进行函数转换和计算</strong></p><p>对列进行函数转换或计算时会导致无法使用索引。</p><p>不推荐:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">where</span> <span class="token keyword">date</span><span class="token punctuation">(</span>create_time<span class="token punctuation">)</span><span class="token operator">=</span><span class="token string">'20190101'</span></code></pre><p>推荐:</p><pre class=" language-sql"><code class="language-sql"><span class="token keyword">where</span> create_time <span class="token operator">>=</span> <span class="token string">'20190101'</span> <span class="token operator">and</span> create_time <span class="token operator"><</span> <span class="token string">'20190102'</span></code></pre><p><strong>在明显不会有重复值时使用UNION ALL而不是UNION</strong></p><p>1、UNION会把两个结果集的所有数据放到临时表中后再进行去重操作</p><p>2、UNION ALL不会再对结果集进行去重操作</p><p><strong>拆分复杂的大SQL为多个小SQL</strong></p><p>大SQL:逻辑上比较复杂,需要占用大量CPU进行计算的SQL</p><h1 id="资料参考"><a href="#资料参考" class="headerlink" title="资料参考"></a>资料参考</h1><ul><li>高性能 MySQL.pdf</li><li>阿里巴巴Java开发手册(详尽版).pdf</li><li><a href="https://www.toutiao.com/i6734868794180649485/" target="_blank" rel="noopener">https://www.toutiao.com/i6734868794180649485/</a></li></ul>]]></content>
<categories>
<category> SQL </category>
</categories>
<tags>
<tag> 实战经验 </tag>
<tag> MySQL </tag>
<tag> 开发规范 </tag>
</tags>
</entry>
<entry>
<title>Java-规范之命名规约</title>
<link href="/2020/01/08/gui-fan-zhi-java-ming-ming-gui-yue/"/>
<url>/2020/01/08/gui-fan-zhi-java-ming-ming-gui-yue/</url>
<content type="html"><![CDATA[<p>每个公司都有不同的标准,目的是为了保持统一,减少沟通成本,提升团队研发效能。</p><p>但,在实际开发中,我们阅读代码时,常说别人写的代码惨目忍睹,总认为自己的最好的,所以本文为自我总结,仅供参考</p><h1 id="规约律令"><a href="#规约律令" class="headerlink" title="规约律令"></a>规约律令</h1><p><strong>通用</strong></p><ul><li>强制:类使用大驼峰命名,方法和局部变量使用小驼峰命名</li><li>强制:不能使用以下划线或美元符号开始,也不能以下划线或美元符号结束</li><li>强制:严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式,杜绝完全不规范的缩写,避免望文不知义</li></ul><p><strong>特定对象</strong></p><ul><li>项目名:全部小写,多个单词以中划线 ‘-‘ 分隔,统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。</li><li>包名:统一使用小写,使用单数形式,仅有小写字母和数组组成,以英文点分隔,取对应的形容词为接口名</li><li>类名:类命通常时名词或名词短语;接口名还可以使用形容词或形容词短语(通常是–able 的形容词)。如Cloneable等,抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。</li><li>方法名:小驼峰命名,杜绝完全不规范的缩写、拼音等</li><li>变量名:POJO 类中布尔类型变量都不要加 is 前缀,否则部分框架解析会引起序列化错误。</li><li>常量名:命名应该全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长 </li></ul><h1 id="包名规约"><a href="#包名规约" class="headerlink" title="包名规约"></a>包名规约</h1><p>一个单词或者多个单词自然连接到一块(如 springframework,deepspace不需要使用任何分割);统一使用单数形式,如果类命有复数含义,则可以使用复数形式。</p><p>包名构成可以分为以下几四部分【前缀】 【发起者名】【项目名】【模块名】。</p><p>前缀:常见的可以分为以下几种:</p><blockquote><p> indi:多人完成,版权属于发起者</p><p> pers :独自完成,公开,版权主要属于个人。</p><p> priv : 独自完成,非公开,版权属于个人。</p><p> team:团队项目指由团队发起,并由该团队开发的项目,版权属于该团队所有。</p></blockquote><p>顶级域名:如:com,cn,org,edu,gov,net 等</p><blockquote><p> com:由公司发起,版权由项目发起的公司所有。</p><p> org:标志这是个开源的包</p></blockquote><p>以下是自己常用来进行区分的模块名,仅供参考:</p><blockquote><p> api:存放对外提供接口服务类</p><p> common:放工具类</p><p> config:放配置类</p><p> constants:放常量类</p><p> domain:放领域对象类</p><p> service:放接口类类</p><p> tasks:放定时器类类</p></blockquote><h1 id="类名规约"><a href="#类名规约" class="headerlink" title="类名规约"></a>类名规约</h1><p>特殊特有名词缩写也可以使用全大写命名,比如XMLHttpRequest;</p><p>建议:三个字母以内都大写,超过三个字母则按照要给单词算</p><p>常见类名规则:</p><ul><li>抽象类:以 Abstract 或者 Base 为前缀;</li><li>接口:取对应的形容词为接口名(通常是–able 的形容词)。</li><li>接口实现类:以接口名称 + Impl </li><li>工具类:以 Utils 或 Tool 为后缀,Utils 是通用业务无关可供其他程序使用的,Tool 是通用的部分业务相关的,只能在本系统使用,Helper 也有帮助类的意思,单其一般用于功能辅助,如:SqlHelper 封装数据库连接操作,提供数据库操作对象</li><li>枚举类:以 Enum 为后缀,枚举成员名称需要全大写,单词间用下划线隔开</li><li>异常类:以 Exception 为后缀</li><li>领域模型类:以 DO/DOT/VO/DAO 为后缀,切记别 Do,Vo 此类错误写法</li><li>测试类:以 Test 为后缀</li><li>MVC 分层:分别以 Controller、Service、ServiceImpl、Mapper 为后缀</li><li>设计模式相关类:以 Builder 、Factory 等为后缀</li><li>特殊功能类:以 Hander、Validate 等为后缀</li></ul><p><strong>分层领域模型规约:</strong></p><ul><li><strong>DO</strong>(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。一般放置在 entity 包下</li><li><strong>DTO</strong>(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。</li><li>BO(Business Object):业务对象,由 Service 层输出的封装业务逻辑的对象。</li><li>AO(Application Object):应用对象,在 Web 层与 Service 层之间抽象的复用对象模型,极为贴近展示层,复用度不高。</li><li><strong>VO</strong>(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。</li><li><strong>Query</strong>:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,<strong>禁止使用 Map 类来传输。</strong>实际开发中我们可能直接我们也不会每层都这么新增这种对象,所以一般用于接收 web 发起的查询封装</li><li>POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO</li></ul><p>以上一般放置于 domain 包下,domain 国外很多项目经常用到,字面意思是域;model 是模型的意思,当用model当包名的时候,其内部的实体类一般是用来给前端用的;小公司也不会分的那么细,一般定义目录结构如下:</p><blockquote><p> domain</p><p> ├─entity</p><p> │ ├─xxxDO,xxx 即为数据表名</p><p> ├─dto</p><p> │ ├─xxxDTO,xxx 为业务领域相关的名称。</p><p> ├─model</p><p> │ ├─vo,xxxVO,xxx 一般为网页名称。</p><p> │ ├─query,xxxQuery,xxx 一般为查询对象的名字,经常用于封装前端的表单的查询条件。</p></blockquote><h1 id="方法名规约"><a href="#方法名规约" class="headerlink" title="方法名规约"></a>方法名规约</h1><p>首字小写,往后的每个单词首字母都要大写,禁止拼音或简写(常见的除外)</p><p><strong>DAO 层方法命名规约(阿里规约)</strong></p><ul><li>获取单个对象的方法用 get 做前缀。</li><li>获取多个对象的方法用 list 做前缀,复数形式结尾如:listObjects。</li><li>获取统计值的方法用 count 做前缀。</li><li>插入的方法用 save/insert 做前缀。</li><li>删除的方法用 remove/delete 做前缀。</li><li>修改的方法用 update 做前缀</li></ul><p>以下是常用 Mybatis 的Mapper类命名,仅供参考</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">BaseMapper</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">//======= 新增</span> <span class="token keyword">int</span> <span class="token function">insert</span><span class="token punctuation">(</span>T entity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> <span class="token function">insertBatch</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"entityList"</span><span class="token punctuation">)</span> Collection<span class="token operator"><</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Serializable</span><span class="token operator">></span> entityList<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> <span class="token function">insertSelective</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//======= 修改</span> <span class="token keyword">int</span> <span class="token function">updateById</span><span class="token punctuation">(</span>T entity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> <span class="token function">updateByMap</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//======= 删除</span> <span class="token keyword">int</span> <span class="token function">delete</span><span class="token punctuation">(</span>T entity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> <span class="token function">deleteById</span><span class="token punctuation">(</span>Serializable id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> <span class="token function">deleteByMap</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> <span class="token function">deleteBatchByIds</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"idList"</span><span class="token punctuation">)</span> Collection<span class="token operator"><</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Serializable</span><span class="token operator">></span> idList<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//======= 对象查询</span> T <span class="token function">getOne</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> T <span class="token function">getOneById</span><span class="token punctuation">(</span>Serializable id<span class="token punctuation">)</span><span class="token punctuation">;</span> List<span class="token operator"><</span>T<span class="token operator">></span> <span class="token function">listObjects</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//======= 统计</span> <span class="token keyword">long</span> <span class="token function">count</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">long</span> <span class="token function">count</span><span class="token punctuation">(</span>T entity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">long</span> <span class="token function">countByMap</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> List<span class="token operator"><</span>Map<span class="token operator"><</span>String<span class="token punctuation">,</span>Object<span class="token operator">>></span> <span class="token function">group</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//=======特定查询</span> <span class="token comment" spellcheck="true">// 需要 IPage 对象</span> IPage<span class="token operator"><</span>T<span class="token operator">></span> <span class="token function">listPage</span><span class="token punctuation">(</span>IPage<span class="token operator"><</span>T<span class="token operator">></span> page<span class="token punctuation">,</span> <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 格式 findXXXByYYY,XXX 获取字段名,YYY为条件对象</span> String <span class="token function">findXXXByYYY</span><span class="token punctuation">(</span> YYY param<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 获取业务数据 ,XXX 为 DTO、VO 对象</span> List<span class="token operator"><</span>XXX<span class="token operator">></span> <span class="token function">listXXXByYYY</span><span class="token punctuation">(</span>YYY params<span class="token punctuation">)</span><span class="token punctuation">;</span> List<span class="token operator"><</span>XXX<span class="token operator">></span> <span class="token function">listXXXDTO</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">"paramsMap"</span><span class="token punctuation">)</span> Map<span class="token operator"><</span>String<span class="token punctuation">,</span> Object<span class="token operator">></span> paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre><p>控制层的方法命名:前缀</p><ul><li>select:列表查询,分页以 Page 为后缀</li><li>find:单字段查找</li><li>save:保存数据,可以指新增或更新,用 add 或 update 代替</li><li>remove:移除,并不一定真删数据,如果确定真删除可以用 delete</li><li>edit:编辑</li><li>view:视图显示</li></ul><p><strong>返回布尔类型的方法,前缀:</strong></p><ul><li>is:表示对象是否符合</li><li>can:表示能否执行某操作</li><li>has:表示是否持有</li><li>need:表示是否需要执行</li><li>validate/ensure:验证或确认是否符合某状态</li></ul><p>操作对象什么生命周期的方法,前缀</p><ul><li>initial:表示初始化,可以简写为 init </li><li>pause:表示暂停</li><li>stop:表示停止</li><li>destroy:表示销毁</li></ul><p>操作某事件动作的方法</p><ul><li>create:创建</li><li>start/stop:开始执行和结束执行</li><li>open:打开控制</li><li>load:载入</li><li>import:导入</li><li>split:分隔</li><li>read:读取</li><li>backup:备份</li><li>bing:绑定</li></ul><p>操作数据相关方法,前缀</p><ul><li>create:新增</li><li>update:更新</li><li>delete:删除</li><li>remove:移除</li><li>save:保存</li><li>insert:插入</li><li>add:添加</li><li>commit:提交</li><li>copy:拷贝</li></ul><p>回调方法,前缀</p><ul><li>on:某事件发生时执行</li><li>before:某事件发生前执行,可用 pre、will 替代</li><li>after:某事件发生后执行,可用 post 替代</li></ul><h1 id="资料参考"><a href="#资料参考" class="headerlink" title="资料参考"></a>资料参考</h1><ul><li>阿里巴巴Java开发手册(华山版)</li></ul>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 实战经验 </tag>
</tags>
</entry>
<entry>
<title>JVM(4)GC 调优</title>
<link href="/2020/01/07/jvm-4-gc-diao-you/"/>
<url>/2020/01/07/jvm-4-gc-diao-you/</url>
<content type="html"><![CDATA[<p>JVM 的定位系统问题时,知识和经验是关键基础,数据是依据、工具是运用知识处理数据的手段</p><p>数据包括:运行日志、异常堆栈、GC日志、线程快照(thread dump、javacore文件)、堆转储快照(headdump / hprof 文件)</p><h1 id="调优命令"><a href="#调优命令" class="headerlink" title="调优命令"></a>调优命令</h1><p>JDK监控和故障处理命令,在bin目录下有:<strong>jps、 jstat、jmap、jhat、jstack、jinfo</strong></p><ul><li>jps:显示虚拟机进程,常用如:<code>jps -l -v</code></li><li>jstat:收集虚拟机各方面的运行数据,常用如:<code>jps-gcutil 2764</code>、<code>jstat -gc 2764 250 20</code></li><li>jinfo:显示虚拟机配置信息</li><li>jmap:生成虚拟机内存转储快照(headdump 文件),常用如:<code>jmap -dump:live,format=b,file=dump.hprof 28920</code></li><li>jhat:用于分析headdump 文件,他会建立一个http/html 的服务器,让客户可以在浏览器上查看分析结果,常用如:<code>jhat dump.hprof</code></li><li>jstack: 显示虚拟机线程快照,常用如:<code>jstack -l 11494</code></li></ul><p>下面做一 一介绍</p><h1 id="jps"><a href="#jps" class="headerlink" title="jps"></a>jps</h1><p> 显示指定系统内所有的HotSpot虚拟机进程,</p><p>格式 :</p><blockquote><p> jps -<option> [hostid]</p></blockquote><p>options 参数:</p><pre class=" language-bash"><code class="language-bash"> -q:只输出LVMID,省略主类的名称 -m:输出新建启动时传递给主类main<span class="token punctuation">(</span><span class="token punctuation">)</span>函数的参数 -l:输出主类的全名,如果进程执行的是Jar包,输出Jar路径 -v:输出虚拟机进程启动时JVM参数</code></pre><p> 其中[option]、[hostid]参数也可以不写</p><p>一般使用:</p><blockquote><p> jps -l -m</p></blockquote><h1 id="jstat"><a href="#jstat" class="headerlink" title="jstat"></a>jstat</h1><p>用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。</p><p>格式 </p><blockquote><p> jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]</p></blockquote><ul><li>vmid: 进程号,interval 和count :表示查询间隔和次数</li><li>options 参数如下</li></ul><pre class=" language-bash"><code class="language-bash">-class:监视类装载、卸载熟练、总空间以及类装载所消耗的时间-gc : 监视堆状况,包括Eden区、两个survivor区、老年代、永久代等容量、已用空间和GC 时间合计等信息-gccapacity:监视内容和 -gc基本相同,但输出主要关注堆各个区域使用到最大,最小空间-gcutil:监视内容和 -gc基本相同,但输出主要关注已使用空间占总空间的百分比-gccause:与 -gcutil一样,额外输出导致上次GC产生的原因-gcnew:监视新生代GC状况-gcnewcapacity:监视内容和 -gcnew 基本相同,输出输出主要关注使用到的最大、最小空间-gcold:监视老年代GC状况-gcoldcapacity:监视内容和 -gcold 基本相同,输出输出主要关注使用到的最大、最小空间-gcpermcapacity:输出永久代使用的最大、最小空间-compiler:输出JIT 编译期编译过的方法、耗时等信息-printcompilation:输出已经被JIT编译的方法</code></pre><p>一般使用:</p><blockquote><p> jps-gcutil 2764 //输出的是已使用空间占总空间的百分比</p><p> jstat -gc 2764 250 20 //每隔250ms输出2764的gc情况,一共输出20次</p></blockquote><h1 id="jinfo"><a href="#jinfo" class="headerlink" title="jinfo"></a>jinfo</h1><p>作用是实时查看和调整虚拟机运行参数。 之前的jps -v口令只能查看到显示指定的参数,如果想要查看未被显示指定的参数的值就要使用jinfo口令</p><p>格式 </p><blockquote><p> jinfo [option vmid]</p></blockquote><p>vmid: 进程号</p><p>option参数</p><pre class=" language-bash"><code class="language-bash">-flag <span class="token keyword">:</span> 输出指定args参数的值-flags <span class="token keyword">:</span> 不需要args参数,输出所有JVM参数的值-sysprops <span class="token keyword">:</span> 输出系统属性,等同于System.getProperties<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>一般使用:<code>jinfo -flag 11494</code></p><h1 id="jmap"><a href="#jmap" class="headerlink" title="jmap"></a>jmap</h1><p><strong>用于生成heap dump文件</strong>,如果不使用这个命令,还阔以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候·自动生成dump文件。</p><p> jmap不仅能生成dump文件,还阔以查询finalize执行队列、Java堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。</p><p>格式 </p><blockquote><p> jmap -<option> [vmid] </p></blockquote><p>option 参数</p><pre class=" language-bash"><code class="language-bash">-dump <span class="token keyword">:</span> 生成堆转储快照-finalizerinfo <span class="token keyword">:</span> 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象-heap <span class="token keyword">:</span> 显示Java堆详细信息-histo <span class="token keyword">:</span> 显示堆中对象的统计信息-permstat <span class="token keyword">:</span> to print permanent generation statistics-F <span class="token keyword">:</span> 当-dump没有响应时,强制生成dump快照</code></pre><p>一般使用 :</p><blockquote><p> jmap -dump:live,format=b,file=dump.hprof 28920</p></blockquote><p>dump堆到文件,format指定输出格式,live指明是活着的对象,file指定文件名</p><p>dump.hprof这个后缀是为了后续可以直接用MAT(Memory Anlysis Tool)打开。</p><h1 id="jhat"><a href="#jhat" class="headerlink" title="jhat"></a>jhat</h1><p>用来分析jmap生成的dump;与jmap搭配使用;jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看。</p><p>在此要注意,一般不会直接在服务器上进行分析,因为jhat是一个耗时并且耗费硬件资源的过程,一般把服务器生成的dump文件复制到本地或其他机器上进行分析。</p><p>格式 </p><blockquote><p> jhat [dumpfile] </p></blockquote><h1 id="jstack"><a href="#jstack" class="headerlink" title="jstack"></a>jstack</h1><p>用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,<strong>生成线程快照的主要目的是定位线程出现长时间停顿的原因</strong>,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。</p><p>格式 </p><blockquote><p> jstack [option] LVMID</p></blockquote><p>option参数</p><pre class=" language-bash"><code class="language-bash">-F <span class="token keyword">:</span> 当正常输出请求不被响应时,强制输出线程堆栈-l <span class="token keyword">:</span> 除堆栈外,显示关于锁的附加信息-m <span class="token keyword">:</span> 如果调用到本地方法的话,可以显示C/C++的堆栈</code></pre><p>一般使用:</p><blockquote><p> jstack -l 11494</p></blockquote><p>分析:这里有一篇文章解释的很好 <a href="http://www.hollischuang.com/archives/110" target="_blank" rel="noopener">分析打印出的文件内容</a></p><h1 id="调优工具"><a href="#调优工具" class="headerlink" title="调优工具"></a>调优工具</h1><h2 id="jconsole"><a href="#jconsole" class="headerlink" title="jconsole"></a>jconsole</h2><ul><li>jdk /bin 目录下,单机jconsole.exe 启动启动</li><li>自动搜索本机运行的所有虚拟机进程,不需要用户自己在使用jps 来查询</li></ul><p>GChisto是一款专业分析gc日志的工具,可以通过gc日志来分析:Minor GC、full gc的时间、频率等等,通过列表、报表、图表等不同的形式来反应gc的情况。</p><p>GC Easy:推荐此工具进行gc分析;这是一个web工具,在线使用非常方便,进入官网,讲打包好的zip或者gz为后缀的压缩包上传,过一会就会拿到分析结果。</p><p><a href="http://gceasy.io" target="_blank" rel="noopener">GC Easy官网地址</a></p><h2 id="VisualVM"><a href="#VisualVM" class="headerlink" title="VisualVM"></a>VisualVM</h2><p>jdk 集成的分析工具,在jdk /bin 目录下,单机jvisualvm.exe 启动</p><h2 id="Oracle-Java-Mission-Control"><a href="#Oracle-Java-Mission-Control" class="headerlink" title="Oracle Java Mission Control"></a>Oracle Java Mission Control</h2><p>jdk 集成的分析工具,在jdk /bin 目录下,单机jmc.exe 启动</p><h1 id="常见问题分析"><a href="#常见问题分析" class="headerlink" title="常见问题分析"></a>常见问题分析</h1><h2 id="查找CPU飙升的原因"><a href="#查找CPU飙升的原因" class="headerlink" title="查找CPU飙升的原因"></a>查找CPU飙升的原因</h2><p>问题分析步骤:</p><ul><li>首先,需要知道哪个进程占用CPU比较高,</li><li>其次,需要知道占用CPU高的那个进程中的哪些线程占用CPU比较高,</li><li>然后,需要知道这些线程的stack trace。</li></ul><p>问题解决步骤:</p><ul><li><p>1、<strong>top</strong>和pgrep来查看系统中Java进程的CPU占用情况。</p><ul><li>命令如下:<strong>top -p <code>pgrep -d , java</code></strong></li><li>pgrep:进程号,<code>top -p</code>:进程的信息。记录下CPU占用率最高的那个进程号。</li></ul></li><li><p>2、top来查看进程中CPU占用最高的那些线程</p><ul><li><strong>top -Hp 12345</strong></li><li>假定12345为占用CPU高的进程号。-H是显示该进程中线程的CPU占用情况。同样,记录下CPU占用率高的那些线程号。</li></ul></li><li><p>3、ctrl+H 切换到线程模式,找到占用cpu最高的线程。并把<strong>线程号转化为十六进制</strong>,<strong>printf “%x\n” <线程ID></strong></p></li><li><p>4、通过<strong>jstack</strong>导出Java应用中线程的stack trace(堆栈轨迹)</p><ul><li><strong>jstack 12345</strong></li></ul></li></ul><p>注意:因为top中显示的线程号是10进制,jstack的输出结果中的线程号是16进制,所以只需要把top中看到线程号转换成16进制</p><p>小结一下,我们通过top和jstack来找到CPU占用高的线程的stack trace,可以使用Eclipse Memory Analyzer插件分析</p><h2 id="Java堆溢出和泄漏"><a href="#Java堆溢出和泄漏" class="headerlink" title="Java堆溢出和泄漏"></a>Java堆溢出和泄漏</h2><h3 id="内存溢出"><a href="#内存溢出" class="headerlink" title="内存溢出"></a>内存溢出</h3><p>程序在申请内存时,没有足够的内存空间供其使用</p><ul><li><strong>危害:</strong>容易受攻击</li><li><strong>影响因素</strong>如下几大类: <ul><li>内存中加载的数据量过于庞大,如一次从数据库取出过多数据</li><li>集合类中有对对象的引用,使用完后未清空,使得JVM不能回收</li><li>代码中存在死循环或循环产生过多重复的对象实体</li></ul></li><li><strong>解决方案:</strong><ul><li>修改JVM启动参数,直接增加内存</li><li>检查错误日志,是否有其他异常或错误;</li><li>对代码进行走查和分析,找出可能发生内存溢出的位置</li><li>重点排查:数据库的取值,死循环和递归调用</li></ul></li></ul><h3 id="内存泄漏"><a href="#内存泄漏" class="headerlink" title="内存泄漏"></a>内存泄漏</h3><p>无法释放已申请的内存空间</p><ul><li><p><strong>危害:频繁GC、运行崩溃</strong></p></li><li><p>影响因素如下几大类: </p><ul><li><p>静态集合类引起内存泄露</p></li><li><p>当集合里面的对象属性被修改后,再调用remove()方法时不起作用。</p><pre class=" language-java"><code class="language-java">Set<span class="token operator"><</span>Person<span class="token operator">></span> set <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashSet</span><span class="token operator"><</span>Person<span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>Person p3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token string">"唐僧"</span><span class="token punctuation">,</span><span class="token string">"pwd1"</span><span class="token punctuation">,</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">;</span>p3<span class="token punctuation">.</span><span class="token function">setAge</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//修改p3的年龄,此时p3元素对应的hashcode值发生改变</span>set<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>p3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//此时remove不掉,造成内存泄漏</span></code></pre></li><li><p>监听器。释放对象时没有删除监听器。</p></li><li><p>各种连接 ,比如数据库连接</p></li><li><p>单例对象持有外部对象的引用</p></li></ul></li><li><p><strong>解决办法:</strong>使用工具jconsole分析</p></li></ul><p>堆的最小值-Xms参数,最大值-Xmx参数</p><pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//代码实现堆溢出:---> 无限循环创建 对象</span>List list <span class="token operator">=</span><span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">while</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">{</span> list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">byte</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token operator">*</span><span class="token number">1024</span><span class="token operator">*</span><span class="token number">1024</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//----------->就是这一步</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"分配次数:"</span><span class="token operator">+</span><span class="token punctuation">(</span><span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span></code></pre><h3 id="Java栈溢出"><a href="#Java栈溢出" class="headerlink" title="Java栈溢出"></a>Java栈溢出</h3><p><strong>栈溢出SOF定义</strong>:线程请求的栈深度超过虚拟机允许的最大深度</p><ul><li>无论是由于栈帧太大还是栈容量太小,当内存无法分配时都是OOM异常。</li><li>虚拟机栈溢出:<strong>深度溢出:递归方法;广度溢出:大数组,建立多线程</strong></li></ul><pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//代码实现栈泄漏---> 方法无限递归调用</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">add</span><span class="token punctuation">(</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre>]]></content>
<categories>
<category> JVM </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> JVM </tag>
</tags>
</entry>
<entry>
<title>JVM(3)GC 回收机制</title>
<link href="/2020/01/07/jvm-3-gc-hui-shou-ji-zhi/"/>
<url>/2020/01/07/jvm-3-gc-hui-shou-ji-zhi/</url>
<content type="html"><![CDATA[<p>在 JVM 中 GC 的回收机制也是非常重要的一块,废话不多说,先上张图</p><p><img src="clipboard.png" alt="JVM GC "></p><h1 id="如何确定垃圾"><a href="#如何确定垃圾" class="headerlink" title="如何确定垃圾"></a>如何确定垃圾</h1><p><strong>1. 引用计数法</strong></p><p>每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。</p><p><strong>2.</strong> <strong>可达性分析</strong></p><p>为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的<code>GC roots</code>对象作为起点搜索。<strong>如果在<code>GC roots</code>和一个对象之间没有可达路径,则称该对象是不可达的</strong>。</p><p>要注意的是,<strong>不可达对象不等价于可回收对象</strong>,不可达对象变为可回收对象<strong>至少要经过两次标记过程</strong>。两次标记后仍然是可回收对象,则将面临回收。</p><h2 id="GC对象标记过程"><a href="#GC对象标记过程" class="headerlink" title="GC对象标记过程"></a><strong>GC对象标记过程</strong></h2><p><strong>第一次标记:</strong></p><ul><li>如果对象在可达性分析后没有与GC Roots相连接的引用链,将<strong>第一次被标记</strong>,并进行一次筛选,筛选条件为<strong>是否有必要执行finalize()方法</strong>,</li><li>没有必要执行finalize()方法,便将这对象<strong>放置F-Queue队列</strong>中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它(指触发这个方法);</li><li>“没必要执行”的两种情况:<strong>当对象没有覆盖finalize()</strong>,或者此方法<strong>已经被虚拟机调用过</strong></li></ul><p><strong>第二次标记:</strong></p><ul><li>稍后GC将对F-Queue中的对象进行<strong>第二次标记</strong>,如果对象在finalize()方法中成功拯救自己(重新与引用链上的任一对象建立关联),它将被移出“即将回收”集合,否则,被回收</li></ul><h2 id="GC-Roots的对象"><a href="#GC-Roots的对象" class="headerlink" title="GC Roots的对象"></a>GC Roots的对象</h2><ul><li>虚拟机栈中引用的对象、</li><li>方法区中类静态属性</li><li>常量的引用的对象、</li><li>本地方法栈中JNI(native接口)引用的对象。</li></ul><p><strong>总结</strong>:</p><ul><li>根据向下搜索方法判断引用链不可达 </li><li>再判断是否有必要执行finalize()方法,</li><li>没有必要执行,进入f-queue队列 </li><li>再次判断与GCRoot有链接 </li><li>没有回收</li></ul><h1 id="对象引用关系"><a href="#对象引用关系" class="headerlink" title="对象引用关系"></a>对象引用关系</h1><p>无论通过引用计数算法还是可达性分析算法,来判读对象是否存活,都与引用相关;</p><p>引用分:<strong>强引用、软引用、弱引用、虚引用;引用强度依次减弱</strong></p><ul><li>强引用:<strong>永远不会被回收</strong>,类似“Object obj = new Object()”的引用,强引用是造成 Java 内存泄漏的主要原因之一</li><li>软引用: <strong>内存不足回收</strong> ,用来描述一些还有用但是并非必须的对象, 通过SoftReference类实现</li><li>弱引用: <strong>只能生存到下一次垃圾收集之前</strong>,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。 用来描述非必须的对象,通过WeakReference类实现,</li><li>虚引用: <strong>无影响</strong>,无法通过虚引用获取对象实例,其目的为了能在对象被回收时收到一个系统通知,通过PhantomReference类实现</li></ul><h1 id="GC-算法"><a href="#GC-算法" class="headerlink" title="GC 算法"></a>GC 算法</h1><p>共有 4 种:<strong>标记-清除算法、复制算法、标记-整理算法、分代收集算法</strong></p><h2 id="标记-清除算法"><a href="#标记-清除算法" class="headerlink" title="标记-清除算法"></a>标记-清除算法</h2><ul><li>算法分为“标记”和“清除”两个阶段</li><li>缺点:效率不高,<strong>产生大量不连续的内存碎片</strong></li></ul><p><img src="clipboard-1578404417512.png" alt="标记-清除算法"></p><h2 id="复制算法"><a href="#复制算法" class="headerlink" title="复制算法"></a>复制算法</h2><p>为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小</p><p>的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用</p><p>的内存清掉</p><ul><li>内存效率高,不易产生碎片,当大量存活对象时会进行较多次复制操作,效率大大降低。</li><li><strong>需要分配担保</strong>:survivor空间不足时,需要老年代进行分配担保,来保证所有对象有存活的情况</li><li><strong>gc过程简单,运行高效</strong> ,不需要考虑内存碎片等复杂情况</li></ul><p><img src="clipboard-1578404442145.png" alt="复制算法"></p><h2 id="标记-整理算法"><a href="#标记-整理算法" class="headerlink" title="标记-整理算法"></a>标记-整理算法</h2><p>结合了以上两个算法,为了避免缺陷而提出。标记阶段和 Mark-Sweep 算法相同,标记后不是清</p><p>理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象</p><p><img src="clipboard-1578404472763.png" alt="标记-整理算法"></p><h2 id="分代收集算法"><a href="#分代收集算法" class="headerlink" title="分代收集算法"></a>分代收集算法</h2><p>分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将 GC 堆划分为<strong>老生代</strong>(Tenured/Old Generation)和<strong>新生代</strong>(Young Generation)。</p><p><strong>老生代的特点:是每次垃圾回收时只有少量对象需要被回收,</strong></p><p><strong>新生代的特点:是每次垃圾回收时都有大量垃圾需要被回收,</strong></p><p>因此可以根据不同区域选择不同的算法。</p><p><strong>新生代与复制算法</strong></p><p> 目前大部分 JVM 的 GC 对于新生代都采取 Copying 算法,<strong>因为新生代中每次垃圾回收都要回收大部分对象,即要复制的操作比较少</strong>,但通常并不是按照 1:1 来划分新生代。一般将新生代划分为一块较大的 Eden 空间和两个较小的 Survivor 空间(From Space, To Space),每次使用Eden 空间和其中的一块 Survivor 空间,当进行回收时,将该两块空间中还存活的对象复制到另一块 Survivor 空间中。</p><p><strong>老年代与标记复制算法</strong></p><p> 老年代因为每次只回收少量对象,因为对象存活率高、没有额外空间对它进行分配担保, 就必须采用“标记—清理”或“标记—整理”算法来进行回收, 不必进行内存复制, 且直接腾出空闲内存.</p><ol><li><p>JAVA 虚拟机提到过的处于方法区的永生代(Permanet Generation),它用来存储 class 类,常量,方法描述等。对永生代的回收主要包括废弃常量和无用的类。</p></li><li><p>对象的内存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目前存放对象的那一块),少数情况会直接分配到老生代。</p></li><li><p>当新生代的 Eden Space 和 From Space 空间不足时就会发生一次 GC,进行 GC 后,Eden Space 和 From Space 区的存活对象会被挪到 To Space,然后将 Eden Space 和 From Space 进行清理。</p></li><li><p>如果 To Space 无法足够存储某个对象,则将这个对象存储到老生代。</p></li><li><p>在进行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反复循环。</p></li><li><p>当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。默认情况下年龄到达 15 的对象会被移到老生代中。</p></li></ol><h2 id="分区收集算法"><a href="#分区收集算法" class="headerlink" title="分区收集算法"></a><strong>分区收集算法</strong></h2><p>分区算法则将整个堆空间划分为连续的不同小区间, 每个小区间独立使用, 独立回收.</p><p>这样做的好处是可以控制一次回收多少个小区间 , 根据目标停顿时间, 每次合理地回收若干个小区间(而不是整个堆), 从而减少一次 GC 所产生的停顿。</p><h1 id="垃圾收集器"><a href="#垃圾收集器" class="headerlink" title="垃圾收集器"></a>垃圾收集器</h1><p><img src="clipboard-1578404707683.png" alt="垃圾收集器"></p><h2 id="Serial-垃圾收集器(单线程、复制算法)"><a href="#Serial-垃圾收集器(单线程、复制算法)" class="headerlink" title="Serial 垃圾收集器(单线程、复制算法)"></a>Serial <strong>垃圾收集器(单线程、复制算法)</strong></h2><p> Serial 垃圾收集器虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率,</p><p> 因此 Serial垃圾收集器依然是 java 虚拟机运行在 Client 模式下<strong>默认的新生代垃圾收集器</strong>。</p><h2 id="ParNew-垃圾收集器(Serial-多线程)"><a href="#ParNew-垃圾收集器(Serial-多线程)" class="headerlink" title="ParNew 垃圾收集器(Serial+多线程)"></a>ParNew 垃圾收集器(Serial+多线程)</h2><p> ParNew 垃圾收集器其实<strong>是 Serial 收集器的多线程版本</strong></p><p> ParNew 收集器默认开启和 CPU 数目相同的线程数,可以通过-XX:ParallelGCThreads 参数来限制垃圾收集器的线程数。【Parallel:平行的】,是很多 java虚拟机运行在 Server 模式下新生代的默认垃圾收集器。</p><h2 id="Parallel-Scavenge-收集器(多线程复制算法、高效)"><a href="#Parallel-Scavenge-收集器(多线程复制算法、高效)" class="headerlink" title="Parallel Scavenge 收集器(多线程复制算法、高效)"></a>Parallel Scavenge 收集器(多线程复制算法、高效)</h2><p> 是一个新生代垃圾收集器,同样使用复制算法,也是一个多线程的垃圾收集器,</p><p> 它<strong>重点关注的是程序达到一个可控制的吞吐量</strong>(Thoughput,CPU 用于运行用户代码的时间/CPU 总消耗时间,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,</p><p>主要适用于在后台运算而不需要太多交互的任务。自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个重要区别。</p><h2 id="Serial-Old-收集器(单线程标记整理算法-)"><a href="#Serial-Old-收集器(单线程标记整理算法-)" class="headerlink" title="Serial Old 收集器(单线程标记整理算法 )"></a>Serial Old 收集器(单线程标记整理算法 )</h2><p> <strong>Serial Old 是 Serial 垃圾收集器年老代版本,它同样是个单线程的收集器</strong>,使使用标记-整理算法,这个收集器也主要是运行在 Client 默认的 java 虚拟机默认的年老代垃圾收集器。</p><h2 id="Parallel-Old-收集器(多线程标记整理算法)"><a href="#Parallel-Old-收集器(多线程标记整理算法)" class="headerlink" title="Parallel Old 收集器(多线程标记整理算法)"></a>Parallel Old 收集器(多线程标记整理算法)</h2><p>Parallel Old 收集器是Parallel Scavenge的年老代版本</p><p>Parallel Old 正是为了在年老代同样提供吞吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge和年老代 Parallel Old 收集器的搭配策略。</p><h2 id="CMS-收集器(多线程标记清除算法)"><a href="#CMS-收集器(多线程标记清除算法)" class="headerlink" title="CMS 收集器(多线程标记清除算法)"></a>CMS 收集器(多线程标记清除算法)</h2><p>Concurrent mark sweep(CMS)收集器是一种年老代垃圾收集器,其<strong>最主要目标是获取最短垃圾回收停顿时间</strong>,和其他年老代使用标记-整理算法不同,它使用<strong>多线程的标记-清除算法</strong>。最短的垃圾收集停顿时间可以为交互比较高的程序提高用户体验。</p><p><strong>优点</strong>:并发收集、低停顿;</p><p><strong>缺点</strong>:对CPU资源非常敏感,无法清除浮动垃圾,产生大量空间碎片;标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC</p><p>CMS 工作机制相比其他的垃圾收集器来说更复杂,整个过程分为以下 4 个阶段:</p><ul><li><strong>初始标记:</strong>只是标记一下 GC Roots 能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。</li><li><strong>并发标记:</strong>进行 GC Roots 跟踪的过程,和用户线程一起工作,不需要暂停工作线程。</li><li><strong>重新标记:</strong>为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。</li><li><strong>并发清除:</strong>清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行。</li></ul><h2 id="G1-收集器"><a href="#G1-收集器" class="headerlink" title="G1 收集器"></a>G1 收集器</h2><p>Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器,G1 收集器两个最突出的改进是:</p><ol><li><p>基于标记-整理算法,<strong>不产生内存碎片。</strong></p></li><li><p>可以非常精确控制停顿时间,<strong>在不牺牲吞吐量前提下,实现低停顿垃圾回收</strong>。</p></li></ol><p><strong>G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。</strong></p><p><strong>区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。整体基于标记整理算法,局部region之间基于复制算法</strong></p><p><strong>特点:并行与并发、分代收集、空间整合、可预测的停顿</strong></p><p>整个过程分为 4 个阶段:初始标记、并发标记、最终标记、筛选回收</p><p><strong>整理上:响应优先选择CMS,吞吐量高选择G1</strong></p><h1 id="JVM启动参数"><a href="#JVM启动参数" class="headerlink" title="JVM启动参数"></a>JVM启动参数</h1><p><strong>-Xmx</strong> :设置最大堆容量</p><p><strong>-Xms</strong> :设置初始堆容量</p><p><strong>-Xmn</strong> :新生代大小</p><p><strong>-Xss</strong> :参数设定每个线程的栈大小</p><p>-XX:newRatio :新生代与老年代的比例</p><p>-XX:SurvivorRatio :Eden区与Survivor的比例</p><p>-XX:PermSize :永久代的初始大小</p><p>-XX:MaxPermSize :永久代的最大空间</p><p>-XX:MaxTenuringThreshold:设置垃圾最大年龄</p><p>-XX:MaxDirectMemorySize :直接内存,如果不指定与Xmx 一样</p><p>Eclipse Memory Analyzer:Eclipse 插件,Java内存分析器,可帮助您查找内存泄漏并减少内存消耗。</p><p>以上图片引用他人,已忘记从哪拷贝,如图片作者特殊需说明,请留言!!</p>]]></content>
<categories>
<category> JVM </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> JVM </tag>
</tags>
</entry>
<entry>
<title>JVM(2)类的加载</title>
<link href="/2020/01/07/jvm-2-lei-de-jia-zai/"/>
<url>/2020/01/07/jvm-2-lei-de-jia-zai/</url>
<content type="html"><![CDATA[<h1 id="类加载机制"><a href="#类加载机制" class="headerlink" title="类加载机制"></a>类加载机制</h1><p>在 jvm 中,Java类的加载过程分为5个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这5个过程。</p><p><img src="/clipboard.png" alt="加载过程"></p><h2 id="加载"><a href="#加载" class="headerlink" title="加载"></a>加载</h2><p><strong>这个阶段会在内存中生成一个代表这个类的 <code>java.lang.Class</code> 对象,作为方法区这个类的各种数据的入口</strong></p><p>注意这里不一定非得要从一个 Class 文件获取,这里既可以从 ZIP 包中读取(比如从 jar 包和 war 包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将 JSP 文件转换成对应的 Class 类)</p><p><strong>此过程完成 3 件事</strong></p><ul><li><strong>通过全限定名获取此类的二进制字节流</strong></li><li>将字节流所代表的<strong>静态存储结构转化为方法区的运行时数据结构</strong></li><li>在内存中生成此类的Class对象(Hotspot虚拟机,class对象存储在方法区),作为方法区这个类的各种数据访问入口</li></ul><p><strong>总结:获取二进制字节流,类的静态信息存储至方法区,在内存中生成一个class类对象</strong></p><h2 id="验证"><a href="#验证" class="headerlink" title="验证"></a>验证</h2><p>这一阶段的主要目的是为了<strong>确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求</strong>,并且不会危害虚拟机自身的安全。</p><p>大致分 4 阶段:文件格式验证、元数据验证、字节码验证、符号引用验证</p><h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><p>正式为类变量分配内存并设置类变量的初始值阶段,即<strong>在方法区中分配这些变量所使用的内存空间</strong></p><p><strong>数据类型默认零值,final修饰过的直接赋值</strong></p><p>比如一个类变量定义为:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> v <span class="token operator">=</span> <span class="token number">8080</span><span class="token punctuation">;</span></code></pre><p>实际上变量 v 在准备阶段过后的初始值为 0 而不是 8080,将 v 赋值为 8080 的 put static 指令是程序被编译后,存放于类构造器<client>方法之中。</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> v <span class="token operator">=</span> <span class="token number">8080</span><span class="token punctuation">;</span></code></pre><p>在编译阶段会为 v 生成 ConstantValue 属性,在<strong>准备阶段虚拟机会根据 ConstantValue 属性将 v 赋值为 8080</strong>。</p><h2 id="解析"><a href="#解析" class="headerlink" title="解析"></a>解析</h2><p><strong>解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程</strong></p><p>符号引用就是 class 文件中的:1. CONSTANT_Class_info、2. CONSTANT_Field_info、3. CONSTANT_Method_info 等类型的常量。</p><p><strong>符号引用:引用的目标并不一定要已经加载到内存中。各种虚拟机实现的内存布局可以各不相同同</strong>,但是它们能接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在 Java 虚拟机规范的 Class 文件格式中。</p><p><strong>直接引用:是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。</strong>如果有了直接引用,那引用的目标必定已经在内存中存在。</p><h2 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h2><p>初始化阶段是类加载最后一个阶段。到了初始阶段,<strong>才开始真正执行类中定义的 Java 程序代码</strong>。就是执行类构造器<clinit>()的方法过程,</p><p><client>方法是由编译器自动收集类中的类变量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证子<client>方法执行之前,父类的<client>方法已经执行完毕<strong>,如果一个类中没有对静态变量赋值也没有静态语句块,那么编译器可以不为这个类生成<client>(/)方法。</strong></p><p><strong>卸载</strong></p><p>JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):</p><ul><li>该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。</li><li>加载该类的ClassLoader已经被GC。</li><li>该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法</li></ul><h1 id="类初始化的时机"><a href="#类初始化的时机" class="headerlink" title="类初始化的时机"></a>类初始化的时机</h1><ul><li>使用new 实例化对象时</li><li>调用静态变量时(常量除外)、静态方法 </li><li>通过反射调用 </li><li>初始化一个类如果父类没有初始化,先触发父类的初始化 </li><li>执行main方法的启动类</li></ul><p><strong>注意以下几种情况不会执行类初始化</strong>:</p><ol><li><p>通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。</p></li><li><p>定义对象数组,不会触发该类的初始化。</p></li><li><p>常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。</p></li><li><p>通过类名获取 Class 对象,不会触发类的初始化。</p></li><li><p>通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。</p></li><li><p>通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作。</p></li></ol><p><strong>接口和类的的初始化区别:</strong>只需要真正使用到的父接口初始化,不需要所有父接口都初始化</p><h1 id="类加载方式"><a href="#类加载方式" class="headerlink" title="类加载方式"></a>类加载方式</h1><p><strong>静态加载</strong>:编译时刻加载的类是静态加载类,new关键字来实例对象,编译时执行,由JVM初始化加载</p><p><strong>动态加载</strong>:运行时刻加载的类是动态加载类,反射方式加载就是动态加载;通过Class.forName(/)方法动态加载或者通过ClassLoader.loadClass(/)方法动态加载</p><p><strong>Class.forName(/)和ClassLoader.loadClass(/)的区别</strong></p><ul><li>Class.forName:将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。</li><li>classloader只将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。</li><li>Class.forName(/name,initialize,loader)带参数也可控制是否加载static块。并且只有调用了newInstance(/)方法采用调用构造函数,创建类的对象。</li></ul><h1 id="类加载器"><a href="#类加载器" class="headerlink" title="类加载器"></a>类加载器</h1><p>JVM 提供了 3 种类加载器:</p><ul><li><p><strong>启动类加载器(/Bootstrap ClassLoader):</strong></p><p>负责加载 JAVA_HOME\lib 目录中的,或通过-bootclasspath 参数指定路径中的,且被虚拟机认可(按文件名识别,如 rt.jar)的类</p></li><li><p><strong>扩展类加载器(/Extension ClassLoader)</strong></p><p>负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库。</p></li><li><p><strong>应用程序类加载器(/Application ClassLoader)</strong></p><p>负责加载用户路径(classpath)上的类库。JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承 java.lang.ClassLoader实现自定义的类加载器。</p></li></ul><p><img src="//clipboard-1578402208674.png" alt="双亲委派"></p><p><strong>双亲委派</strong></p><p><strong>当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成</strong>,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。</p><p><strong>双亲委派模型优点:</strong></p><p><strong>避免同一个类被多次加载;每个加载器只能加载自己范围内的类,保证java程序的稳定运行</strong>,比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就<strong>保证了使用不同的类加载器最终得到的都是同样一个 Object 对象</strong>。</p><p><strong>思考:可以不可以自己写个String类?</strong></p><p>答案:不可以,因为根据类加载的双亲委派机制,会去加载父类,父类发现冲突了String就不再加载了;</p>]]></content>
<categories>
<category> JVM </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> JVM </tag>
</tags>
</entry>
<entry>
<title>JVM(1)内存模型</title>
<link href="/2020/01/06/jvm-1-nei-cun-mo-xing/"/>
<url>/2020/01/06/jvm-1-nei-cun-mo-xing/</url>
<content type="html"><![CDATA[<h1 id="JVM内存分布"><a href="#JVM内存分布" class="headerlink" title="JVM内存分布"></a>JVM内存分布</h1><p><img src="clipboard-1578317326416.png" alt="JVM 内存"></p><p><strong>JVM 内存区域主要分为:</strong></p><ul><li>线程私有区域【<strong>程序计数器、虚拟机栈、本地方法区</strong>】</li><li>线程共享区域【<strong>JAVA 堆、方法区</strong>】</li><li>直接内存。</li></ul><p><strong>线程私有数据区域生命周期与线程相同,依赖用户线程的启动/结束 而 创建/销毁</strong></p><p><strong>线程共享区域随虚拟机的启动/关闭而创建/销毁。线程共享区域随虚拟机的启动/关闭而创建/销毁。</strong></p><p><img src="clipboard-1578317375718.png" alt="内存分布"></p><h1 id="堆-Heap-线程共享)"><a href="#堆-Heap-线程共享)" class="headerlink" title="堆(Heap-线程共享)"></a>堆(Heap-线程共享)</h1><p><strong>是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 堆内存中</strong>,也是垃圾收集器进行垃圾收集的最重要的内存区域。</p><p>由于现代 VM 采用<strong>分代收集算法</strong>,因此 Java 堆从 GC 的角度还可以细分为: <strong>新生代</strong>(<em>Eden 区<em>、</em>From Survivor 区*和 *To Survivor 区</em>)和<strong>老年代。</strong></p><p><strong>JDK8 时字符串池和类的静态变量放入 java 堆中</strong></p><p><strong>JVM 运行时内存</strong></p><p>Java 堆从 GC 的角度还可以细分为: <strong>新生代</strong>(<em>Eden 区<em>、</em>From Survivor 区*和 *To Survivor 区</em>)和<strong>老年代</strong>。</p><p><img src="clipboard.png" alt="JVM 运行时内存"></p><h2 id="新生代"><a href="#新生代" class="headerlink" title="新生代"></a>新生代</h2><p>是用来存放新生的对象。一般占据堆的 1/3 空间。由于频繁创建对象,所以新生代会频繁触发MinorGC 进行垃圾回收。新生代又分为 Eden 区、ServivorFrom、ServivorTo 三个区。</p><p><strong>1. Eden 区</strong></p><p>Java 新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当 Eden区内存不够的时候就会触发 MinorGC,对新生代区进行一次垃圾回收。</p><p><strong>2. ServivorFrom</strong></p><p>上一次 GC 的幸存者,作为这一次 GC 的被扫描者。</p><p><strong>3. ServivorTo</strong></p><p>保留了一次 MinorGC 过程中的幸存者。</p><h2 id="老年代"><a href="#老年代" class="headerlink" title="老年代"></a><strong>老年代</strong></h2><p>主要存放应用程序中生命周期长的内存对象。</p><p>老年代的对象比较稳定,所以 <strong>MajorGC</strong> 不会频繁执行。在进行 <strong>MajorGC 前一般都先进行了一次 MinorGC</strong>,使得有新生代的对象晋身入老年代,<strong>导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时</strong>也会提前触发一次 MajorGC 进行垃圾回收腾出空间。</p><p>MajorGC 采用标记清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC 的耗时比较长,因为要扫描再回收。MajorGC 会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的时候,就会抛出 <code>OOM(Out of Memory)</code>异常。</p><h2 id="永久代"><a href="#永久代" class="headerlink" title="永久代"></a>永久代</h2><p>指内存的永久保存区域,主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域,它和和存放实例的区域不同,<strong>GC 不会在主程序运行期对永久区域进行清理</strong>。所以这也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。</p><h1 id="方法区-线程共享)"><a href="#方法区-线程共享)" class="headerlink" title="方法区(线程共享)"></a>方法区(线程共享)</h1><p>和堆区一样,别名 Non-heap (<strong>非堆</strong>), 又被称为<strong>永久代(Permanent Generation)</strong>,<strong>线程共享</strong>,用于<strong>存储被 JVM 加载的类信息</strong>、<strong>常量</strong>、<strong>静态变量</strong>、<strong>即时编译器编译后的代码</strong>等数据. </p><p><strong>运行时常量池</strong>(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是<strong>常量池:用于存放编译期生成的各种字面量和符号引用</strong>,这部分内容将在<strong>类加载后</strong>存放到方法区的运行时常量池中。</p><p>HotSpot VM把GC分代收集扩展至方法区,即<strong>使用Java堆的永久代来实现方法区</strong>,这样 HotSpot 的垃圾收集器就可以像管理 Java 堆一样管理这部分内存,而不必为方法区开发专门的内存管理器(<strong>永久代的内存回收的主要目标是针对常量池的回收和类型的卸载</strong>,因此收益一般很小)。</p><h1 id="Metaspace-元空间)"><a href="#Metaspace-元空间)" class="headerlink" title="Metaspace(元空间)"></a>Metaspace(元空间)</h1><p><strong>在 Java8 中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代</strong>。</p><p>元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:<strong>元空间并不在虚拟机中,而是使用本地内存</strong>。因此,默认情况下,元空间的大小仅受本地内存限制。</p><p><strong>类的元数据放入 native memory,字符串池和类的静态变量放入 java 堆中</strong>,这样可以加载多少类的元数据就不再由 MaxPermSize 控制,而由系统的实际可用空间来控制。</p><h1 id="虚拟机栈-线程私有"><a href="#虚拟机栈-线程私有" class="headerlink" title="虚拟机栈(线程私有)"></a>虚拟机栈(线程私有)</h1><p>虚拟机栈是描述java方法执行的内存模型,其特点如下:</p><ul><li>每个方法在执行的同时都会创建一个<strong>栈帧</strong>(Stack Frame)用于存储局部变量、操作数栈、动态链接、方法出口等信息。</li><li>每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。</li><li><strong>线程私有;生命周期与线程相同</strong></li></ul><p><strong>栈帧( Frame)</strong></p><p>是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。</p><p><strong>局部变量表</strong></p><ul><li>存储编译期可知的各种 <strong>基本数据类型、对象引用类型</strong>(引用指针或句柄)和 <strong>returnAddress类型</strong>(指向了一条字节码指令的地址);</li><li>在编译期完成内存分配,当内存不足时,会抛出两种异常:SOF 异常、OOM异常;<strong>SOF 异常</strong> <code>(StackOverflowError)</code>:线程请求的栈深度大于虚拟机允许的深度时抛出;<strong>OOM异常</strong> <code>(OutOfMemoryError)</code>:无法申请到足够内存时抛出</li></ul><h1 id="本地方法区-线程私有"><a href="#本地方法区-线程私有" class="headerlink" title="本地方法区(线程私有)"></a>本地方法区(线程私有)</h1><p>本地方法区和 Java Stack 作用类似,区别是虚拟机栈为执行 Java 方法服务,而本地方法栈则为Native 方法服务,如果一个 VM 实现使用 C-linkage 模型来支持 Native 调用,那么该栈将会是一个C 栈,但 HotSpot VM 直接就把本地方法栈和虚拟机栈合二为一。</p><p>也会抛出两种异常:SOF 异常、OOM异常</p><h1 id="程序计数器-线程私有"><a href="#程序计数器-线程私有" class="headerlink" title="程序计数器(线程私有)"></a>程序计数器(线程私有)</h1><p>一块较小的内存空间,<strong>是当前线程所执行的字节码的行号指示器</strong>,每条线程都要有一个独立的程序计数器,这类内存也称为 ”线程私有“ 内存。</p><p>正在执行 java 方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果还是 Native 方法,则为空。</p><p>这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域。</p><h1 id="内存分配策略"><a href="#内存分配策略" class="headerlink" title="内存分配策略"></a>内存分配策略</h1><p>Java 程序运行时的内存分配策略有三种</p><ul><li>静态分配:静态存储区(也称方法区),静态数据、全局 static 数据和常量</li><li>栈式分配:栈区,方法体内的局部变量(其中包括基础数据类型、对象的引用)</li><li>堆式分配:堆区,new 出来的内存,也就是对象的实例</li></ul><h2 id="堆内存分配策略"><a href="#堆内存分配策略" class="headerlink" title="堆内存分配策略"></a>堆内存分配策略</h2><p>Eden区存活对象进入Survivor区(Eden肯定会被清空),<strong>大对象(长字符串或数组,byte[] 就是典型)进入直接进入老年代;如果Survivor区无法提供足够的内存,则通过分配担保机制提前进入老年代</strong></p><ul><li>Survivor区中存活年龄<strong>大于等于15</strong>的对象直接进入老年代(每次Minor GC对象年龄加1)</li><li>Survivor区<strong>同年龄的对象大小总和大于Survivor空间的一半时</strong>,其他年龄大于或等于该年龄的对象直接进入老年代,年龄不必等到15</li><li>当发生MinorGC时,<strong>survivor空间不够时</strong>,需要老年代分配担保,让survivor无法容纳的对象进入老年代</li><li>年轻代空间回收称作 Minor GC ,发生频繁,老年代的垃圾回收称作 Full GC/Major GC</li></ul><p><strong>Minor GC</strong> :年轻代进行的垃圾回收,非常频繁,一把回收速度较快</p><p><strong>Major GC</strong>:老年代进行的垃圾回收,发生一次MajorGC至少伴随一次Minor GC,一般比Minor GC慢10倍</p><p><strong>Full GC</strong>:整个堆内存进行垃圾回收,很多时候是Major GC</p><p><strong>MinorGC 的过程(复制->清空->互换)采用复制算法</strong>。</p><p>对象创建时,会在Eden区分配内存,Eden区内存不够,触发<strong>Minor GC</strong>(年轻代的垃圾回收)</p><ul><li><strong>1:eden、servicorFrom 复制到</strong> <strong>ServicorTo,年龄+1</strong></li></ul><p>首先,把 Eden 和 ServivorFrom 区域中存活的对象复制到 ServicorTo 区域(如果有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 不够位置了就放到老年区);</p><ul><li><strong>2:清空 eden、servicorFrom</strong></li></ul><p>然后,清空 Eden 和 ServicorFrom 中的对象;</p><ul><li><strong>3:ServicorTo 和 ServicorFrom 互换</strong></li></ul><p>最后,ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom区。</p><p><strong>Full GC 的触发条件:</strong></p><ul><li>调用System.gc(), 建议虚拟机执行 Full GC,不一定正在执行,不推荐</li><li>老年代不足时,常见场景大对象、长期存活的对象直接进入老年代时内存不足,导致频繁GC</li><li>为 survivor 的空间担保失败。</li></ul><p><strong>永久代主要回收:废弃常量和无用的类</strong>,废弃常量和无用的类的判断方式:</p><ul><li><strong>废弃常量:</strong> 该常量没有任何对象进行引用,就会被回收。</li><li><strong>无用的类:</strong> 该类的所有实例都已经被回收,该类的ClassLoader已经被回收,该类的Class对象没有被引用,无法完成通过反射访问该类 </li></ul>]]></content>
<categories>
<category> JVM </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> JVM </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(8)异常</title>
<link href="/2020/01/05/java-ji-chu-pian-8-yi-chang/"/>
<url>/2020/01/05/java-ji-chu-pian-8-yi-chang/</url>
<content type="html"><![CDATA[<h2 id="异常分类"><a href="#异常分类" class="headerlink" title="异常分类"></a>异常分类</h2><p>Throwable 是 Java 语言中所有错误或异常的超类。下一层分为 <strong>Error</strong> 和 <strong>Exception</strong></p><ul><li><p><strong>Error</strong>:用来表示 JVM 无法处理的错误,是指 java 运行时系统的内部错误和资源耗尽错误。应用程序不会抛出该类对象不便于也不需要捕获,属于不可检查时异常。常见的比如<code>OutOfMemoryError</code>、<code>StackOverflowError</code>都是Error的子类。</p></li><li><p><strong>Exception(RuntimeException、CheckedException)</strong>: Exception 又 有 两 个 分 支 , 一 个 是 运 行 时 异 常 RuntimeException , 一 个 是CheckedException。</p></li></ul><p><img src="untitled%20diagram.png" alt="异常分类"></p><h2 id="Exception"><a href="#Exception" class="headerlink" title="Exception"></a>Exception</h2><p><strong>运行时异常 RuntimeException</strong> : 其与子类都是未检查的异常,如 <code>NullPointerException</code> 、 <code>ClassCastException</code> ;是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。 如果出现 <code>RuntimeException</code>,那么一定是程序员的错误.</p><p><strong>检查异常 CheckedException</strong>:如 I/O 错误导致的 <code>IOException</code>、<code>SQLException</code>,一般是外部错误,这种异常都发生在编译阶段,Java 编译器会<strong>强制程序去捕获此类异常</strong>,即会出现要求程序进行 try catch,如:<code>Thread.sleep()</code>、<code>IOException</code>、<code>SQLException</code>等以及用户自定义的Exception异常</p><p><strong>抛出异常有 3 种形式,一是 throw,一个 throws,还有一种系统自动抛异常。</strong></p><h3 id="Throw-和-throws-的区别:"><a href="#Throw-和-throws-的区别:" class="headerlink" title="Throw 和 throws 的区别:"></a>Throw 和 throws 的区别:</h3><ol><li>throws 用在函数上,后面跟的是异常类,可以跟多个;而 throw 用在函数内,后面跟的是异常对象。</li><li>throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先的处理方式;throw 抛出具体的问题对象,执行到 throw,功能就已经结束了,跳转到调用者,并将具体的问题对象抛给调用者。也就是说 throw 语句独立存在时,下面不要定义其他语句,因为执行不到。</li><li>throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。</li></ol><h3 id="常见Exception"><a href="#常见Exception" class="headerlink" title="常见Exception"></a>常见Exception</h3><p><strong>运行时异常</strong>(RuntimeException)</p><ul><li>NullPointerException(空指针异常)</li><li>ArrayIndexOutOfBoundsException(数组下标越界)</li><li>ClassNotFoundException(找不到类)</li><li>ArithmeticException(算术异常)</li></ul><p><strong>检查异常 (CheckedException)</strong></p><ul><li>IOException:输入输出异常</li><li>SQLException:操作数据库异常</li><li>FileNotFoundException:文件未找到异常</li><li>NoSuchMethodException:方法未找到异常</li></ul><h2 id="Throwable类常用方法"><a href="#Throwable类常用方法" class="headerlink" title="Throwable类常用方法"></a>Throwable类常用方法</h2><ul><li><strong>public string getMessage()</strong>:返回异常发生时的详细信息</li><li><strong>public string toString()</strong>:返回异常发生时的简要描述</li><li><strong>public string getLocalizedMessage()</strong>:返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同</li><li><strong>public void printStackTrace()</strong>:在控制台上打印Throwable对象封装的异常信息</li></ul>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(7)反射</title>
<link href="/2020/01/05/java-ji-chu-pian-7-fan-she/"/>
<url>/2020/01/05/java-ji-chu-pian-7-fan-she/</url>
<content type="html"><![CDATA[<h2 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h2><h3 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h3><p>在 Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;</p><p>这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。</p><p><code>Class</code> 和 <code>java.lang.reflect</code> 一起对反射提供了支持,<code>java.lang.reflect</code> 类库主要包含了以下三个类:</p><ul><li>Field 类:表示类的成员变量,可以用来获取和设置类之中的属性值。</li><li>Method 类:表示类的方法,它可以用来获取类中的方法信息或者执行方法。</li><li>Constructor 类: 表示类的构造方法。</li></ul><p><strong>反射的优点:</strong></p><ul><li><strong>能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。</strong></li><li>与Java动态编译相结合,可以实现无比强大的功能</li></ul><p><strong>反射的缺点:</strong></p><ul><li><strong>性能开销</strong> :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。</li><li><strong>安全限制</strong> :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。</li><li><strong>内部暴露</strong> :破坏了类的封装性,可以通过反射获取这个类的私有方法和属性</li></ul><h3 id="实现方式"><a href="#实现方式" class="headerlink" title="实现方式"></a>实现方式</h3><p><strong>在 Java 中反射有 3 中获取 <code>Class</code> 的实现方式</strong>,如下:</p><ol><li><p>调用某个对象的 <code>getClass()</code>方法</p><pre class=" language-java"><code class="language-java"> Person p<span class="token operator">=</span><span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Class <span class="token class-name">clazz</span><span class="token operator">=</span>p<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></li><li><p>调用某个类的 class 属性来获取该类对应的 Class 对象</p><pre class=" language-java"><code class="language-java"> Class <span class="token class-name">clazz</span><span class="token operator">=</span>Person<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">;</span></code></pre></li><li><p>使用 Class 类中的 <code>forName()</code>静态方法是最安全、性能最好,最常用的一种方式</p><pre class=" language-java"><code class="language-java"> Class <span class="token class-name">clazz</span><span class="token operator">=</span>Class<span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">"类的全路径"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre></li></ol><p><strong>Class 创建对象的 2 种方式</strong></p><ol><li>使用 Class 对象的 <code>newInstance()</code></li><li>先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()</li></ol><h2 id="实战演练"><a href="#实战演练" class="headerlink" title="实战演练"></a>实战演练</h2><pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//获取 Person 类的 Class 对象</span>Class <span class="token class-name">clazz</span><span class="token operator">=</span>Class<span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">"reflection.Person"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//获取 Person 类的所有方法信息</span>Method<span class="token punctuation">[</span><span class="token punctuation">]</span> method<span class="token operator">=</span>clazz<span class="token punctuation">.</span><span class="token function">getDeclaredMethods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span><span class="token punctuation">(</span>Method m<span class="token operator">:</span>method<span class="token punctuation">)</span><span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment" spellcheck="true">//获取 Person 类的所有成员属性信息</span>Field<span class="token punctuation">[</span><span class="token punctuation">]</span> field<span class="token operator">=</span>clazz<span class="token punctuation">.</span><span class="token function">getDeclaredFields</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span><span class="token punctuation">(</span>Field f<span class="token operator">:</span>field<span class="token punctuation">)</span><span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>f<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment" spellcheck="true">//获取 Person 类的所有构造方法信息</span>Constructor<span class="token punctuation">[</span><span class="token punctuation">]</span> constructor<span class="token operator">=</span>clazz<span class="token punctuation">.</span><span class="token function">getDeclaredConstructors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span><span class="token punctuation">(</span>Constructor c<span class="token operator">:</span>constructor<span class="token punctuation">)</span><span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment" spellcheck="true">//使用.newInstane 方法创建对象</span>Person p<span class="token operator">=</span><span class="token punctuation">(</span>Person<span class="token punctuation">)</span> clazz<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//获取构造方法并创建对象</span>Constructor c<span class="token operator">=</span>clazz<span class="token punctuation">.</span><span class="token function">getDeclaredConstructor</span><span class="token punctuation">(</span>String<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span>String<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span><span class="token keyword">int</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//创建对象并设置属性</span>Person p1<span class="token operator">=</span><span class="token punctuation">(</span>Person<span class="token punctuation">)</span> c<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token string">"李四"</span><span class="token punctuation">,</span><span class="token string">"男"</span><span class="token punctuation">,</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(6)逻辑运算</title>
<link href="/2020/01/05/java-ji-chu-pian-6-luo-ji-yun-suan/"/>
<url>/2020/01/05/java-ji-chu-pian-6-luo-ji-yun-suan/</url>
<content type="html"><![CDATA[<p>在本篇章中会从参数传递、++ 和 += 运算、try/catch、循环、switch 等方面讲述来讲述一下,在 Java 中的一些逻辑运算规则</p><h2 id="参数传递"><a href="#参数传递" class="headerlink" title="参数传递"></a>参数传递</h2><p>在 Java 中,方法参数传递过程,其实是传递一个副本值过程,所以有2种结果</p><ul><li>基本数据类型和 String 都是只修改的副本值。所以,<strong>对参数不会发生改变</strong></li><li>引用类型是其引用地址不会修改,但副本地址也指向了原来的值,因此<strong>引用类型属性值是会发生修改的。</strong></li></ul><p>总结一句话就是:<strong>基本数据类型和String类型,值不会;引用类型引用地址不变</strong></p><p>上代码进行说明:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> String name<span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">int</span> age<span class="token punctuation">;</span> <span class="token keyword">public</span> String <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> name<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setName</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setAge</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> Person person <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> person<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> person<span class="token punctuation">.</span><span class="token function">setAge</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span> String name <span class="token operator">=</span> <span class="token string">"张三"</span><span class="token punctuation">;</span> <span class="token keyword">int</span> age <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Person: "</span> <span class="token operator">+</span> person<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">","</span> <span class="token operator">+</span> person<span class="token punctuation">.</span><span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"main : "</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">","</span> <span class="token operator">+</span> age<span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"=============================="</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">stringChange</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span>age<span class="token punctuation">,</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Person: "</span> <span class="token operator">+</span> person<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">","</span> <span class="token operator">+</span> person<span class="token punctuation">.</span><span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"main : "</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">","</span> <span class="token operator">+</span> age<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">stringChange</span><span class="token punctuation">(</span>String name<span class="token punctuation">,</span> <span class="token keyword">int</span> age<span class="token punctuation">,</span> Person person<span class="token punctuation">)</span> <span class="token punctuation">{</span> name <span class="token operator">=</span> <span class="token string">"-----"</span><span class="token punctuation">;</span> age <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> person<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">"-----"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> person<span class="token punctuation">.</span><span class="token function">setAge</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>执行结果如下:</p><pre><code>Person: 张三,10main : 张三,10==============================Person: -----,0main : 张三,10</code></pre><p>由上代码得出:<strong>基本数据类型和String类型,不会改变;引用类型其属性会改变</strong></p><h2 id="和-运算"><a href="#和-运算" class="headerlink" title="++ 和 += 运算"></a>++ 和 += 运算</h2><p>该小节是重点,面试一定会出现的考点,可要记牢了</p><h3 id="i-和-i-的区别"><a href="#i-和-i-的区别" class="headerlink" title="i++ 和 ++i 的区别"></a>i++ 和 ++i 的区别</h3><blockquote><p> i++:先赋值,在相加,</p><p> ++i:先相加,在赋值</p></blockquote><p>实战以下,看以下代码</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">print1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token keyword">return</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">print2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator">++</span>i<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token function">print1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token function">print2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>执行结果为:1,2,0,2;</p><p>我们获取以下方法执行时的指令集</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">print1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">return</span> i<span class="token operator">++</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">print2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator">++</span>i<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>查看汇编指令如<img src="image-20200101202719891.png" alt="执行偏移地址为6时的指令执行情况"></p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">print1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Code<span class="token operator">:</span> <span class="token number">0</span><span class="token operator">:</span> iconst_0 <span class="token comment" spellcheck="true">//将int类型常量0压入栈 </span> <span class="token number">1</span><span class="token operator">:</span> istore_0 <span class="token comment" spellcheck="true">//将int类型值存入局部变量</span> <span class="token number">2</span><span class="token operator">:</span> iload_0 <span class="token comment" spellcheck="true">//第一个int型局部变量进栈</span> <span class="token number">3</span><span class="token operator">:</span> iinc <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> <span class="token comment" spellcheck="true">//把一个常量值加到一个int类型的局部变量上,0 表示局部变量索引</span> <span class="token number">6</span><span class="token operator">:</span> ireturn <span class="token comment" spellcheck="true">//将操作数栈栈顶的值返回个此方法的调用者</span> LineNumberTable<span class="token operator">:</span> line <span class="token number">5</span><span class="token operator">:</span> <span class="token number">0</span> line <span class="token number">6</span><span class="token operator">:</span> <span class="token number">2</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">print2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Code<span class="token operator">:</span> <span class="token number">0</span><span class="token operator">:</span> iconst_0 <span class="token comment" spellcheck="true">//将int类型常量0压入栈 </span> <span class="token number">1</span><span class="token operator">:</span> istore_0 <span class="token comment" spellcheck="true">//将int类型值存入局部变量</span> <span class="token number">2</span><span class="token operator">:</span> iinc <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> <span class="token comment" spellcheck="true">//把一个常量值加到一个int类型的局部变量上,0 表示局部变量索引</span> <span class="token number">5</span><span class="token operator">:</span> iload_0 <span class="token comment" spellcheck="true">//第一个int型局部变量进栈</span> <span class="token number">6</span><span class="token operator">:</span> ireturn <span class="token comment" spellcheck="true">//将操作数栈栈顶的值返回个此方法的调用者</span> LineNumberTable<span class="token operator">:</span> line <span class="token number">5</span><span class="token operator">:</span> <span class="token number">0</span> line <span class="token number">6</span><span class="token operator">:</span> <span class="token number">2</span></code></pre><ul><li><p><code>iload_0</code> 指将整型指存入操作数栈</p></li><li><p><code>iinc</code> 用于实现局部变量的自增操作。在所有字节码指令中,只有该指令可直接用于操作局部变量。</p></li><li><p><code>ireturn</code> 是将操作数栈<strong>栈顶</strong>的值返回个此方法的调用者</p></li></ul><p><strong>i=i++到底是怎么执行的</strong></p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Inc</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> Inc inc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Inc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> inc<span class="token punctuation">.</span><span class="token function">fermin</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">=</span> i <span class="token operator">++</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">fermin</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span><span class="token punctuation">{</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">//答案是0; inc.fermin(i); 是一个干扰项,考值传递还是引用传递</span></code></pre><h3 id="i-i-1-和-i-1-的区别"><a href="#i-i-1-和-i-1-的区别" class="headerlink" title="i=i+1 和 i+=1 的区别"></a>i=i+1 和 i+=1 的区别</h3><p>i+=1 会进行自动类型转换</p><h2 id="try-catch"><a href="#try-catch" class="headerlink" title="try/catch"></a>try/catch</h2><p>在 Java 中 try/catch/finally 的语法中的 <strong>finally 块的代码一定会执行</strong></p><ul><li>当finally中<strong>有return</strong>时,不管什么类型,都会<strong>会影响</strong>try块或catch块中的<code>返回值</code></li><li>当finally中<strong>没有return</strong>时,不管什么类型,都<strong>不会影响</strong>try块或catch块中的<code>返回值</code></li></ul><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">fun</span><span class="token punctuation">(</span>String key<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>key<span class="token operator">=</span><span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> key<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>key<span class="token operator">=</span><span class="token string">"b"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> key<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token keyword">finally</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>key<span class="token operator">=</span><span class="token string">"c"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> key<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> argc<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token function">fun</span><span class="token punctuation">(</span><span class="token string">"0"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>执行结果为 :a、c、c</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr <span class="token operator">=</span> <span class="token punctuation">{</span>i<span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">=</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">=</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token keyword">finally</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">=</span><span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> argc<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token function">fun</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>执行结果为 :3、300、3</p><h2 id="for-do-while"><a href="#for-do-while" class="headerlink" title="for/do/while"></a>for/do/while</h2><p>在Java中有3种循环方式如下:</p><ul><li><strong>for 循环</strong></li><li><strong>while 循环</strong>:当满足条件时, 才执行执行一次代码块,不满足条件,结束循环</li><li><strong>do/while 循环</strong>: 先执行一次代码块 ,在判读是否满足条件,不满足条件,结束循环</li></ul><p><strong>continue和break 的区别</strong></p><ul><li>continue: 表示终止本次循环的执行</li><li>break : 表示结束当前层整个循环,嵌套循环时外层不受影响</li></ul><p><strong>对于for循环中条件的执行顺序是怎么样的,你知道吗?比如; for(i=0;i<10;i++){}</strong></p><p>其实很简单,普通for顺序如下:</p><ol><li>先对循环变量赋初始值,如:i=0</li><li>在执行 循环判读是否满足条件</li><li>满足条件,则执行循环体</li><li>在执行循环变量,自增或自减操作</li><li>再循环2,3,4步。知道不满足判读条件,跳出循环</li></ol><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token keyword">char</span> c<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">'A'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">'B'</span><span class="token punctuation">)</span><span class="token operator">&&</span>i<span class="token operator"><</span><span class="token number">2</span><span class="token punctuation">;</span><span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">'C'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> i<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">'D'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>执行结果:</p><pre class=" language-java"><code class="language-java">ABDCBDCB</code></pre><p>输出结果你答对了吗?</p><h2 id="switch"><a href="#switch" class="headerlink" title="switch"></a>switch</h2><p>在Java中,switch 是从选项值相匹配的 case 标签处开始执行<strong>直到遇到 break 语句, 或者执行到 switch 语句的结束处为止。</strong></p><p>注意:</p><ul><li>有可能触发多个 case 分支 。 如果在 case 分支语句的末尾没有 break 语句 , 那么就 会接着执行下一个 case 分支语句</li><li><strong>continue</strong>:该关键字不能作用于 switch 语句中</li><li><strong>switch 条件判断语句中使用对象</strong>:支持:char, byte, short, int, Character, Byte, Short, Integer, String, or an enum,不支持 long。支持String 从 Java 7 开始</li></ul><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 0:"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 1:"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 2:"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// break ; 1</span> <span class="token keyword">case</span> <span class="token number">3</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 3:"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// continue; 2</span> <span class="token keyword">case</span> <span class="token number">4</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 4:"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>执行结果:</p><pre><code>case 1:case 2:case 3:case 4:</code></pre><p><strong>如果有break 呢? 比如只取消 <code>1</code>处 的注释</strong></p><p>此时输出:</p><pre><code>case 1: case 2:</code></pre><p>所以,我们可以理解为:<strong>switch,其实就是一个case的循环,不过只能执行一次。break则可以中断case 循环。</strong></p><p><strong>如果有continue呢?比如只取消 <code>2</code> 处的注释</strong></p><p>我们发现什么,发现提示报错,为什么??因为continue 不能再switch中执行。除非外层有有循环体包裹</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> i<span class="token punctuation">;</span> j <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>j<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 0: j="</span><span class="token operator">+</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 1: j="</span><span class="token operator">+</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 2: j="</span><span class="token operator">+</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">3</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 3: j="</span><span class="token operator">+</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">4</span><span class="token operator">:</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"case 4: j="</span><span class="token operator">+</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"------"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>执行结果:</p><pre><code>case 2: j=2------case 3: j=3case 4: j=4------</code></pre><p>发现没有输出:case 3: j=2 ,并且多了一行“——”</p><p><strong>这说明 switch中 的 break, 对for循环时无效的,只作用于switch 上</strong>,所以在终止switch循环后,还会执行for循环中后续的代码</p>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(5)类加载和初始化</title>
<link href="/2020/01/05/java-ji-chu-pian-5-lei-jia-zai-he-chu-shi-hua/"/>
<url>/2020/01/05/java-ji-chu-pian-5-lei-jia-zai-he-chu-shi-hua/</url>
<content type="html"><![CDATA[<p>虚拟机将描述类的数据从.class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型</p><h1 id="类加载"><a href="#类加载" class="headerlink" title="类加载"></a>类加载</h1><p>在类的加载阶段,即生命周期分:加载、验证、准备、解析、初始化、调用、卸载等七个时期,其中验证、准备、解析3个部分统称为连接。</p><p>结束生命周期方式: </p><ul><li>执行了System.exit()方法</li><li>程序正常执行结束</li><li>程序在执行过程中遇到了异常或错误而异常终止</li><li>由于操作系统出现错误而导致Java虚拟机进程终止</li></ul><h2 id="加载阶段"><a href="#加载阶段" class="headerlink" title="加载阶段"></a>加载阶段</h2><p>指获取二进制字节流,类的静态信息存储至方法区,在内存中生成一个class类对象;加载方式一般分2种,静态加载和动态加载:</p><ul><li><strong>静态加载</strong> :编译时刻加载的类是静态加载类;通过<strong>new关键字来实例对象</strong>,编译时执行</li><li><strong>动态加载</strong> :运行时刻加载的类是动态加载类。通过<strong>反射、序列化、克隆等方式</strong>加载,运行期执行</li></ul><p><strong>所以创建对象方式</strong>有4种:使用new关键字、反射、克隆(clone方法)、序列化</p><p>数组类本身不通过类加载器创建,由Java虚拟机直接创建,但数组类的元素类型由加载创建(基本数据类型除外)</p><h2 id="验证阶段"><a href="#验证阶段" class="headerlink" title="验证阶段"></a>验证阶段</h2><p>校验二进制字节流是否符合JVM标准,大致分 4 阶段:文件格式验证、元数据验证、字节码验证、符号引用验证</p><h2 id="准备阶段"><a href="#准备阶段" class="headerlink" title="准备阶段"></a>准备阶段</h2><p>该阶段是将类的<strong>静态变量分配内存,并设置类变量的初始值</strong>,数据类型默认零值,<strong>final修饰过的直接赋值</strong></p><blockquote><p> 假设上面的类变量value被定义为: public static final int value = 3;</p><p> 编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。这种情况。我们可以理解为static final常量在编译期就将其结果放入了调用它的类的常量池中</p></blockquote><h2 id="解析阶段"><a href="#解析阶段" class="headerlink" title="解析阶段"></a>解析阶段</h2><p><strong>把类中的符号引用转换为直接引用</strong>;主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符等 7 类符号引用</p><p>符号引用:以一组符号(任一形式字面值)描述目标的引用</p><p>直接引用:句柄或直接指针描述目标引用</p><h2 id="初始化阶段"><a href="#初始化阶段" class="headerlink" title="初始化阶段"></a>初始化阶段</h2><p>该阶段就是执行类构造器<code><clinit>()</code>的方法过程;<code><clinit>()</code>是由编译期收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的</p><hr><h1 id="类初始化"><a href="#类初始化" class="headerlink" title="类初始化"></a>类初始化</h1><h2 id="类初始化时机"><a href="#类初始化时机" class="headerlink" title="类初始化时机"></a>类初始化时机</h2><p>在 Java 代码运行中,什么时候开始初始化一个类呢?一般有以下5种情景,都会进行类初始化</p><ol><li>使用 new 实例化对象时</li><li>调用静态变量时(常量除外)、静态方法</li><li>通过反射调用</li><li>初始化一个类如果父类没有初始化,先触发父类的初始化</li><li>执行main方法的启动类</li></ol><p><strong>但是值得注意的是,以上情景中,以下情况是不会触发初始化的</strong></p><ul><li>子类调用父类的静态变量,子类不会被初始化,只有父类被初始化</li><li>通过数组定义来引用类,不会触发类的初始化</li><li>访问类的常量(包含静态常量),不会初始化类</li></ul><p>举例说明:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">class</span> <span class="token class-name">SuperClassA</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"superclassA init"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> value <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">SuperClassB</span> <span class="token keyword">extends</span> <span class="token class-name">SuperClassA</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"superclassB init"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> value <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// 如果注释此代码</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">SuperClassC</span> <span class="token keyword">extends</span> <span class="token class-name">SuperClassB</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"superclassC init"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">SubClass</span> <span class="token keyword">extends</span> <span class="token class-name">SuperClassC</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"subclass init"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> argc<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>SubClass<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">new</span> <span class="token class-name">SubClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre><p>执行结果:</p><pre class=" language-java"><code class="language-java">superclassA initsuperclassB init<span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>superclassC initsubclass init</code></pre><p>分析一下为什么出现以上结果呢?:</p><ol><li>当调用 <code>SubClass.value</code>,<code>SubClass</code> 本身没有定义<code>value</code>变量,但是通过继承的规则:子类会继承或覆盖父类属性,因此我们这里应该取<code>SubClassB.value</code>,所以预初始化<code>SuperClassB</code>,但是根据类初始化顺序规则:<strong>初始化一个类如果父类没有初始化,先触发父类的初始化</strong>,所以先初始化<code>SuperclassA</code>,再初始化 <code>SuperClassB</code> ;由于<strong>子类调用父类的静态变量,子类不会被初始化,只有父类被初始化</strong>的原则,因此并不会初始化 <code>SubClass</code> 自己</li><li>当调用<code>new SubClass()</code> 时,根据 <strong>初始化一个类如果父类没有初始化,先触发父类的初始化</strong> 的原则,所以预初始化<code>SuperClassC</code>、<code>SuperClassB</code>、<code>SuperClassA</code>,但是此时只有<code>SuperClassC</code>没有初始化,所以这里会 初始化 <code>SuperClassC</code>、<code>SubClass</code></li></ol><p><strong>调用静态常量不出进行类初始化</strong></p><pre class=" language-java"><code class="language-java"><span class="token keyword">class</span> <span class="token class-name">ConstClass</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"ConstClass init"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> String HELLOWORLD <span class="token operator">=</span> <span class="token string">"hello world"</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>ConstClass<span class="token punctuation">.</span>HELLOWORLD<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// 调用类常量</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>执行结果:</p><pre class=" language-java"><code class="language-java">hello world</code></pre><hr><h2 id="类初始化顺序"><a href="#类初始化顺序" class="headerlink" title="类初始化顺序"></a>类初始化顺序</h2><p>我们在笔试时经常遇到根据类初始化顺序,确认结果的面试题,因此我们非常有必要掌握该知识点。先上代码,我们在分析</p><p>父类SuperClass:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">package</span> com<span class="token punctuation">.</span>hsy<span class="token punctuation">.</span>demo<span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SuperClass</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 普通变量</span> <span class="token keyword">private</span> String field <span class="token operator">=</span> <span class="token function">getField</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 静态变量</span> <span class="token keyword">private</span> <span class="token keyword">static</span> String staticField <span class="token operator">=</span> <span class="token function">getStaticField</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 构造函数</span> <span class="token keyword">public</span> <span class="token function">SuperClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 构造函数 SuperClass()"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 普通方法块</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 普通方法块{}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 静态方法块</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 静态方法块 static{}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// ----------------------相反顺序-----------------------------</span> <span class="token comment" spellcheck="true">// 静态方法块</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 静态方法块static {} > 顺序:第2个"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 普通方法块</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 普通方法块 {} > 顺序:第2个"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 构造函数</span> <span class="token keyword">public</span> <span class="token function">SuperClass</span><span class="token punctuation">(</span><span class="token keyword">int</span> n<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 构造函数 SuperClass(int n)"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 静态变量</span> <span class="token keyword">private</span> <span class="token keyword">static</span> String staticField2 <span class="token operator">=</span> <span class="token function">getStaticField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 普通变量</span> <span class="token keyword">private</span> String field2 <span class="token operator">=</span> <span class="token function">getField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// =====================================</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getStaticField</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String statiFiled <span class="token operator">=</span> <span class="token string">"Static Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 静态变量staticField"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> statiFiled<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getStaticField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String statiFiled <span class="token operator">=</span> <span class="token string">"Static Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 静态变量staticField > 顺序第2个 "</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> statiFiled<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getField</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String filed <span class="token operator">=</span> <span class="token string">"Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 普通变量:field"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> filed<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String filed <span class="token operator">=</span> <span class="token string">"Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"父类SuperClass > 普通变量:field > 顺序第2个"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> filed<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>子类SubClass:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">package</span> com<span class="token punctuation">.</span>hsy<span class="token punctuation">.</span>demo<span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SubClass</span> <span class="token keyword">extends</span> <span class="token class-name">SuperClass</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// 普通变量</span> <span class="token keyword">private</span> String field <span class="token operator">=</span> <span class="token function">getField</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 静态变量</span> <span class="token keyword">private</span> <span class="token keyword">static</span> String staticField <span class="token operator">=</span> <span class="token function">getStaticField</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 构造函数</span> <span class="token keyword">public</span> <span class="token function">SubClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 构造函数 SuperClass()"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 普通方法块</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 普通方法块{}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 静态方法块</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 静态方法块 static{}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// ----------------------相反顺序-----------------------------</span> <span class="token comment" spellcheck="true">// 静态方法块</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 静态方法块static {} > 顺序:第2个"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 普通方法块</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 普通方法块 {} > 顺序:第2个"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 构造函数</span> <span class="token keyword">public</span> <span class="token function">SubClass</span><span class="token punctuation">(</span><span class="token keyword">int</span> n<span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 构造函数 SuperClass(int n)"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment" spellcheck="true">// 静态变量</span> <span class="token keyword">private</span> <span class="token keyword">static</span> String staticField2 <span class="token operator">=</span> <span class="token function">getStaticField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 普通变量</span> <span class="token keyword">private</span> String field2 <span class="token operator">=</span> <span class="token function">getField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// =====================================</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getStaticField</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String statiFiled <span class="token operator">=</span> <span class="token string">"Static Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 静态变量staticField"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> statiFiled<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getStaticField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String statiFiled <span class="token operator">=</span> <span class="token string">"Static Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 静态变量staticField > 顺序第2个 "</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> statiFiled<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getField</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String filed <span class="token operator">=</span> <span class="token string">"Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 普通变量:field"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> filed<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">getField2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> String filed <span class="token operator">=</span> <span class="token string">"Field Initial"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"子类SubClass > 普通变量:field > 顺序第2个"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> filed<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>执行结果:</p><pre><code>父类SuperClass > 静态变量staticField父类SuperClass > 静态方法块 static{}父类SuperClass > 静态方法块static {} > 顺序:第2个父类SuperClass > 静态变量staticField > 顺序第2个 子类SubClass > 静态变量staticField子类SubClass > 静态方法块 static{}子类SubClass > 静态方法块static {} > 顺序:第2个子类SubClass > 静态变量staticField > 顺序第2个 父类SuperClass > 普通变量:field父类SuperClass > 普通方法块{}父类SuperClass > 普通方法块 {} > 顺序:第2个父类SuperClass > 普通变量:field > 顺序第2个父类SuperClass > 构造函数 SuperClass()子类SubClass > 普通变量:field子类SubClass > 普通方法块{}子类SubClass > 普通方法块 {} > 顺序:第2个子类SubClass > 普通变量:field > 顺序第2个子类SubClass > 构造函数 SuperClass(int n)</code></pre><p>通过以上代码你找到规律了吗?是否和以下规则一样</p><p><strong>存在继承的情况下,初始化顺序如下依次进行:</strong></p><p><strong>存在继承的情况下,初始化顺序如下依次进行:</strong></p><ol><li>父类(静态变量、静态语句块),初始化顺序取决于它们在代码中定义的先后顺序</li><li>子类(静态变量、静态语句块),初始化顺序取决于它们在代码中定义的先后顺序</li><li>父类(普通变量、普通语句块),初始化顺序取决于它们在代码中定义的先后顺序</li><li>父类(构造函数),默认初始化父类无参构造函数</li><li>子类(普通变量、普通语句块),初始化顺序取决于它们在代码中定义的先后顺序</li><li>子类(构造函数),调谁用谁</li></ol><p>知道以上规则了,我们在看看以下代码:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">class</span> <span class="token class-name">SingleTon</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">static</span> SingleTon singleTon <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SingleTon</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> count1<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> count2 <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token function">SingleTon</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> count1<span class="token operator">++</span><span class="token punctuation">;</span> count2<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> SingleTon <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> singleTon<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> SingleTon singleTon <span class="token operator">=</span> SingleTon<span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"count1="</span> <span class="token operator">+</span> singleTon<span class="token punctuation">.</span>count1<span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"count2="</span> <span class="token operator">+</span> singleTon<span class="token punctuation">.</span>count2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>以上代码会有啥结果呢?这里我们先不着急揭秘,先分析一下</p><ol><li>当调用<code>SingleTon.getInstance();</code> 时,根据初始化规则,由于<code>getInstance</code>是静态方法,<code>SingleTon</code>还没有初始化,所以会先初始化该类</li><li>根据类加载过程,在类准备阶段会将非<code>final</code> 的静态属性,赋上初始值,也就是说<code>count1</code> 和 <code>count2</code> 先赋上 0 值;然后在类初始化阶段赋予实际程序员定义的值,所以过程如下:<ol><li>第1步准备阶段:即singleton=null count1=0,count2=0</li><li>第2步初始化阶段:根据执行的属性,静态变量,谁先定义,谁先初始化。即过程为:先初始化 SingleTon ;这里是构造方法赋值。执行后count1=1,count2=1;然后初始化count1和count2,由于count1 没有赋值动作,则不执行。最后给count2 赋值,即:count2=0。</li></ol></li></ol><p>所以执行结果如下</p><pre class=" language-java"><code class="language-java">count1<span class="token operator">=</span><span class="token number">1</span>count2<span class="token operator">=</span><span class="token number">0</span></code></pre><p>注意:如果singleTon 属性放在count2 后, 则结果就不一样了。而是count1=1,count2=1;</p>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(4)数据类型</title>
<link href="/2020/01/04/java-ji-chu-pian-4-shu-ju-lei-xing/"/>
<url>/2020/01/04/java-ji-chu-pian-4-shu-ju-lei-xing/</url>
<content type="html"><![CDATA[<p>在本章中,主要介绍一下 Java 最常用、也是基础考点的数据类型;我们都知道 Java 语言提供了八种基本类型:六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。并且还提供了其对应的引用类型。</p><hr><h2 id="基本类型"><a href="#基本类型" class="headerlink" title="基本类型"></a>基本类型</h2><table><thead><tr><th>类型</th><th>字节数/位数</th><th>最小值</th><th>最大值</th></tr></thead><tbody><tr><td><strong>byte</strong></td><td>1/8</td><td>-128(-2^7)</td><td>127(2^7-1)</td></tr><tr><td><strong>short</strong></td><td>2/16</td><td>-32768(-2^15)</td><td>32767(2^15 - 1)</td></tr><tr><td><strong>int</strong></td><td>4/32</td><td>-2,147,483,648(-2^31)</td><td>2,147,483,647(2^31 - 1)</td></tr><tr><td><strong>long</strong></td><td>8/64</td><td>-2^63</td><td>2^63 -1</td></tr><tr><td><strong>float</strong></td><td>4/32</td><td></td><td></td></tr><tr><td><strong>double</strong></td><td>8/64</td><td></td><td></td></tr></tbody></table><p><strong>char</strong>:在 Java 中是用 unicode来表示字符,所以 2 个字节来表示一个字符; 一个数字或英文或汉字都是一个字符,只不过数字和英文时,存储的2个字节的第一个字节都为0,就是浪费了点空间。存汉字就占满了2个字节。</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">char</span> c1 <span class="token operator">=</span> <span class="token string">'a'</span><span class="token punctuation">;</span> <span class="token keyword">char</span> c2 <span class="token operator">=</span> <span class="token string">'中'</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"char字符:"</span><span class="token operator">+</span> c1 <span class="token operator">+</span> <span class="token string">",字节数:"</span> <span class="token operator">+</span> <span class="token function">charToByte</span><span class="token punctuation">(</span>c1<span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"char字符:"</span><span class="token operator">+</span> c2 <span class="token operator">+</span> <span class="token string">",字节数:"</span> <span class="token operator">+</span> <span class="token function">charToByte</span><span class="token punctuation">(</span>c2<span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">charToByte</span><span class="token punctuation">(</span><span class="token keyword">char</span> c<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> b <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">byte</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span> b<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">byte</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">(</span>c <span class="token operator">&</span> <span class="token number">0xFF00</span><span class="token punctuation">)</span> <span class="token operator">>></span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span> b<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">byte</span><span class="token punctuation">)</span><span class="token punctuation">(</span>c <span class="token operator">&</span> <span class="token number">0xFF</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> b<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>运行结果:</p><pre><code>char字符:a,字节数:2char字符:中,字节数:2</code></pre><p><strong>boolean</strong>:在 Java 基本类型中只有两个状态,true、false,理论上只占一个字节,但是实际如下:</p><ul><li>单个的boolean类型变量在编译的时候是使用的 int 类型,即 boolean a = true 时,这个a在 JVM 中<strong>占用 4 个字节</strong>,即32位;</li><li>boolean类型的数组时,在编译时是作为byte array来编译的。所以,boolean数组里的每一个元件占用一个字节;即 boolean[] b = new boolean[10] 的数组时,每一个boolean在 JVM中占<strong>一个字节</strong>;</li></ul><p><strong>注意</strong>: <code>float</code> 和 <code>double</code> 都不能表示精确的值,所以一般不能用在计算货币,要想精度不失效,可以使用 <code>BigDecimal</code></p><hr><h2 id="引用类型"><a href="#引用类型" class="headerlink" title="引用类型"></a>引用类型</h2><p>在 Java 中引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。</p><ul><li>对象、数组都是引用数据类型;</li><li>所有引用类型的默认值都是null;</li><li>一个引用变量可以用来引用任何与之兼容的类型</li></ul><p>我们的基本类型都有对应的引用类型,且基本类型与其对应的引用类型之间的赋值使用自动装箱与拆箱完成</p><p><strong>Integer需要几个字节 ?</strong>,答案是每个Integer 占用了 3 * 4bytes</p><ul><li><p>Integer在内存中有一个指向方法区里边类信息的指针,这个指针占用4bytes;</p></li><li><p>另外Integer中实例变量只有一个int类型的字段,所以为32位,4bytes。</p></li><li><p>有4bytes的指向对象池的指针</p></li></ul><hr><h3 id="自动装箱和拆箱"><a href="#自动装箱和拆箱" class="headerlink" title="自动装箱和拆箱"></a><strong>自动装箱和拆箱</strong></h3><p>自动拆箱:故名思议就是<code>将对象重新转化为基本数据类型</code>;是享元模式(flyweight)</p><pre class=" language-java"><code class="language-java">Integer num <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//装箱</span><span class="token keyword">int</span> num1 <span class="token operator">=</span> num<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//拆箱</span></code></pre><p><strong>基本数据类型和引用数据类型区别</strong></p><ul><li><code>基本数据类型</code>在被创建时,数值直接存储在栈上。</li><li><code>引用数据类型</code>在被创建时,对象的具体信息都存储在堆内存上,对象的引用地址存储在栈上</li></ul><hr><h3 id="new-Integer-123-与-Integer-valueOf-123-区别"><a href="#new-Integer-123-与-Integer-valueOf-123-区别" class="headerlink" title="new Integer(123) 与 Integer.valueOf(123)区别"></a>new Integer(123) 与 Integer.valueOf(123)区别</h3><p>注意:我们使用基本类型的引用类型新建对象时,可能出现一些意料之外的变化,如:</p><pre class=" language-java"><code class="language-java">Integer x <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>Integer y <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Integer</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>x <span class="token operator">==</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// false</span>Integer z <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>Integer k <span class="token operator">=</span> Integer<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>z <span class="token operator">==</span> k<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// true</span></code></pre><p>为什么出现以上结果,这是因为 valueOf() 方法的实现,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容,而不是每次新建一个对象,所以:</p><ul><li>new Integer(10) 每次都会新建一个对象;</li><li>Integer.valueOf(10) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。</li></ul><p><strong>注意:4种整型都有相同效果,有兴趣的可以分别试试 Byte、Short、Integer、Long 的效果</strong></p><hr><h3 id="Integer或-Short-缓存池上下边界"><a href="#Integer或-Short-缓存池上下边界" class="headerlink" title="Integer或 Short 缓存池上下边界"></a>Integer或 Short 缓存池上下边界</h3><p>Short 其实和 Integer 是相同效果,这里以 Integer 为例</p><pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//在-128~127 之外的数</span>Integer num1 <span class="token operator">=</span> <span class="token number">128</span><span class="token punctuation">;</span> Integer num2 <span class="token operator">=</span> <span class="token number">128</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"num1==num2: "</span><span class="token operator">+</span><span class="token punctuation">(</span>num1<span class="token operator">==</span>num2<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//false </span><span class="token comment" spellcheck="true">// 在-128~127 之内的数 </span>Integer num3 <span class="token operator">=</span> <span class="token number">127</span><span class="token punctuation">;</span> Integer num4 <span class="token operator">=</span> <span class="token number">127</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"num3==num4: "</span><span class="token operator">+</span><span class="token punctuation">(</span>num3<span class="token operator">==</span>num4<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//true </span></code></pre><p>为什么出现以上结果,这是因为 *<em>Integer *</em>如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象</p><hr><h3 id="IntegerCache-源码分析"><a href="#IntegerCache-源码分析" class="headerlink" title="IntegerCache 源码分析"></a>IntegerCache 源码分析</h3><pre class=" language-java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">IntegerCache</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> low <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">128</span><span class="token punctuation">;</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> high<span class="token punctuation">;</span> <span class="token keyword">static</span> <span class="token keyword">final</span> Integer cache<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">static</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// high value may be configured by property</span> <span class="token keyword">int</span> h <span class="token operator">=</span> <span class="token number">127</span><span class="token punctuation">;</span> String integerCacheHighPropValue <span class="token operator">=</span> sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>VM<span class="token punctuation">.</span><span class="token function">getSavedProperty</span><span class="token punctuation">(</span><span class="token string">"java.lang.Integer.IntegerCache.high"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>integerCacheHighPropValue <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>integerCacheHighPropValue<span class="token punctuation">)</span><span class="token punctuation">;</span> i <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">127</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// Maximum array size is Integer.MAX_VALUE</span> h <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> Integer<span class="token punctuation">.</span>MAX_VALUE <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token operator">-</span>low<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span> NumberFormatException nfe<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment" spellcheck="true">// If the property cannot be parsed into an int, ignore it.</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> high <span class="token operator">=</span> h<span class="token punctuation">;</span> cache <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Integer</span><span class="token punctuation">[</span><span class="token punctuation">(</span>high <span class="token operator">-</span> low<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">int</span> j <span class="token operator">=</span> low<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k <span class="token operator"><</span> cache<span class="token punctuation">.</span>length<span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span> cache<span class="token punctuation">[</span>k<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Integer</span><span class="token punctuation">(</span>j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// range [-128, 127] must be interned (JLS7 5.1.7)</span> <span class="token keyword">assert</span> IntegerCache<span class="token punctuation">.</span>high <span class="token operator">>=</span> <span class="token number">127</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token function">IntegerCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><blockquote><p> 通过源码,可以知道默认的Integer缓存池的大小范围是 -128~127。也是是说在这个范围里面,只要缓存池中有需要的值,会直接从缓存池中来获取,而不是重新new一个对象。</p></blockquote><pre class=" language-java"><code class="language-java"><span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> low <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">128</span><span class="token punctuation">;</span><span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> high<span class="token punctuation">;</span></code></pre><blockquote><p> 在 jdk 1.8 IntegerCache 缓冲池中,可以看出,这个缓冲池的下界是 - 128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax= 来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。</p></blockquote><hr><h2 id="String类型"><a href="#String类型" class="headerlink" title="String类型"></a>String类型</h2><h3 id="String-不可变"><a href="#String-不可变" class="headerlink" title="String 不可变"></a>String 不可变</h3><p>String 类型 是一个final修饰的类型。因此它不可被继承。在 Java 8 中,String 内部使用 char 数组存储数据。</p><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">String</span> <span class="token keyword">implements</span> <span class="token class-name">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span>Serializable</span><span class="token punctuation">,</span> Comparable<span class="token operator"><</span>String<span class="token operator">></span><span class="token punctuation">,</span> CharSequence <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">char</span> value<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,<strong>因此可以保证 String 不可变。</strong></p><p><strong>String 不可变的好处</strong></p><ul><li><strong>可以缓存 hash 值</strong>:因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。</li><li><strong>String Pool 的需要</strong>:如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。<strong>只有 String 是不可变的,才可能使用 String Pool</strong>。</li><li><strong>安全性</strong>:String 不可变性天生具备线程安全,可以在多个线程中安全地使用。String 经常作为参数,String 不可变性可以保证参数不可变。</li></ul><h3 id="String-赋值"><a href="#String-赋值" class="headerlink" title="String 赋值"></a>String 赋值</h3><pre class=" language-java"><code class="language-java">String s1 <span class="token operator">=</span> <span class="token string">"bbb"</span><span class="token punctuation">;</span>String s2 <span class="token operator">=</span> <span class="token string">"bbb"</span><span class="token punctuation">;</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>s5 <span class="token operator">==</span> s6<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// true</span></code></pre><p>如果是采用 “bbb” 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。而不是象new一样放在压缩堆中;当声明这样的一个字符串后,JVM会在常量池中先查找有没有一个值为”bbb”的对象,</p><ul><li>如果有:就会把它赋给当前引用。即原来那个引用和现在这个引用指点向了同一对象,</li><li>如果没有:则在常量池中新创建一个”bbb”,</li></ul><p>下一次如果有String s2 = “bbb”;又会将s2指向”abcd”这个对象;即以这形式声明的字符串,只要值相等,任何多个引用都指向同一对象.</p><p>而<code>String s = new String("abcd");</code>和其它任何对象一样,每调用一次就产生一个对象</p><pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//代码1 </span>String sa <span class="token operator">=</span> <span class="token string">"ab"</span><span class="token punctuation">;</span> String sb <span class="token operator">=</span> <span class="token string">"cd"</span><span class="token punctuation">;</span> String sab<span class="token operator">=</span>sa<span class="token operator">+</span>sb<span class="token punctuation">;</span> String s<span class="token operator">=</span><span class="token string">"abcd"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>sab<span class="token operator">==</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// false </span><span class="token comment" spellcheck="true">//当执行sa+sb时,JVM首先会在堆中创建一个StringBuilder类,将刚生成的String对象的堆地址存放在局部变量sab中</span><span class="token comment" spellcheck="true">//局部变量 s 存储的是常量池中"abcd"所对应的拘留字符串对象的地址</span><span class="token comment" spellcheck="true">//代码2 </span>String sc<span class="token operator">=</span><span class="token string">"ab"</span><span class="token operator">+</span><span class="token string">"cd"</span><span class="token punctuation">;</span> String sd<span class="token operator">=</span><span class="token string">"abcd"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>sc<span class="token operator">==</span>sd<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//true </span><span class="token comment" spellcheck="true">//"ab"+"cd"会直接在编译期就合并成常量"abcd", 因此相同字面值常量"abcd"所对应的是同一个拘留字符串对象,自然地址也就相同。</span></code></pre><p>扩展:</p><pre class=" language-java"><code class="language-java"><span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">"abc"</span><span class="token punctuation">)</span></code></pre><p>这种方式一共会创建两个字符串对象(<strong>前提是 String Pool 中还没有 “abc” 字符串对象</strong>)。</p><ul><li>“abc” 属于字符串字面量,因此编译时期会在 <strong>String Pool 中</strong>创建一个字符串对象,指向这个字符串字面量;</li><li>而使用 new 的方式会在<strong>堆中</strong>创建一个字符串对象。</li></ul><h3 id="String-字节-编码"><a href="#String-字节-编码" class="headerlink" title="String 字节/编码"></a>String 字节/编码</h3><p>如果编码和解码过程使用不同的编码方式那么就出现了乱码。</p><ul><li>GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节;</li><li>UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节;</li><li>UTF-16 编码中,中文字符和英文字符都占 2 个字节。</li></ul><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> String str1 <span class="token operator">=</span> <span class="token string">"a"</span><span class="token punctuation">;</span> String str2 <span class="token operator">=</span> <span class="token string">"你"</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"utf-8:'a'所占的字节数:"</span> <span class="token operator">+</span> str1<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"gbk:'a'所占的字节数:"</span> <span class="token operator">+</span> str1<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token string">"gbk"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"utf-8:'中'所占的字节数:"</span> <span class="token operator">+</span> str2<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"gbk:'中'所占的字节数:"</span> <span class="token operator">+</span> str2<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token string">"gbk"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">UnsupportedEncodingException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre><p>运行结果如下:</p><pre class=" language-java"><code class="language-java">utf<span class="token operator">-</span><span class="token number">8</span><span class="token operator">:</span><span class="token string">'a'</span>所占的字节数<span class="token operator">:</span><span class="token number">1</span>gbk<span class="token operator">:</span><span class="token string">'a'</span>所占的字节数<span class="token operator">:</span><span class="token number">1</span>utf<span class="token operator">-</span><span class="token number">8</span><span class="token operator">:</span><span class="token string">'中'</span>所占的字节数<span class="token operator">:</span><span class="token number">3</span>gbk<span class="token operator">:</span><span class="token string">'中'</span>所占的字节数<span class="token operator">:</span><span class="token number">2</span></code></pre><h3 id="String、StringBuffer、-StringBuilder的区别"><a href="#String、StringBuffer、-StringBuilder的区别" class="headerlink" title="String、StringBuffer、 StringBuilder的区别"></a>String、StringBuffer、 StringBuilder的区别</h3><ul><li><p>从运行速度上说,StringBuilder>StringBuffer>String,因为String是不可变的对象</p></li><li><p>String:是字符串常量(由final修饰),StringBuffer和StringBuilder 是字符串变量</p></li><li><p><strong>StringBuffer:有同步锁</strong>,但效率低,适用于多线程下字符缓冲区进行大量操作。</p></li><li><p>StringBuilder:效率高,线程不安全,适用于单线程下的字符缓冲区进行大量操作的情况;</p><p> </p></li></ul><p><strong>StringBuffer 和 StringBuilder 能大量操作字符的原理</strong></p><p>在append是后,采用了<code>Arrays.copyOf()</code> 进行了数组复制</p><pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">synchronized</span> StringBuffer <span class="token function">append</span><span class="token punctuation">(</span>Object obj<span class="token punctuation">)</span> <span class="token punctuation">{</span> toStringCache <span class="token operator">=</span> null<span class="token punctuation">;</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>String<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment" spellcheck="true">// AbstractStringBuilder 类</span><span class="token keyword">public</span> AbstractStringBuilder <span class="token function">append</span><span class="token punctuation">(</span>String str<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>str <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">appendNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> len <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">ensureCapacityInternal</span><span class="token punctuation">(</span>count <span class="token operator">+</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 采用复制方式增加数组长度</span> str<span class="token punctuation">.</span><span class="token function">getChars</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> len<span class="token punctuation">,</span> value<span class="token punctuation">,</span> count<span class="token punctuation">)</span><span class="token punctuation">;</span> count <span class="token operator">+=</span> len<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">ensureCapacityInternal</span><span class="token punctuation">(</span><span class="token keyword">int</span> minimumCapacity<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>minimumCapacity <span class="token operator">-</span> value<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> value <span class="token operator">=</span> Arrays<span class="token punctuation">.</span><span class="token function">copyOf</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> <span class="token function">newCapacity</span><span class="token punctuation">(</span>minimumCapacity<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><hr><h3 id="String-Pool"><a href="#String-Pool" class="headerlink" title="String Pool"></a>String Pool</h3><ul><li>字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定</li><li>String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中</li></ul><pre class=" language-java"><code class="language-java">String s1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">"aaa"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>String s2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">"aaa"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>s1 <span class="token operator">==</span> s2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// false</span>String s3 <span class="token operator">=</span> s1<span class="token punctuation">.</span><span class="token function">intern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>String s4 <span class="token operator">=</span> s2<span class="token punctuation">.</span><span class="token function">intern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>s3 <span class="token operator">==</span> s4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// true</span></code></pre><p><strong>String#intern</strong> 方法:intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中返回这个新字符串的引用,若存在(使用 equals() 方法进行确定)那么就会返回 String Pool 中字符串的引用;</p><p>在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。</p><hr><h3 id="String-常用方法"><a href="#String-常用方法" class="headerlink" title="String 常用方法"></a>String 常用方法</h3><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">endsWith</span><span class="token punctuation">(</span>String suffix<span class="token punctuation">)</span> <span class="token comment" spellcheck="true">//测试此字符串是否以指定的后缀结束</span><span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">startsWith</span><span class="token punctuation">(</span>String prefix<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">char</span> <span class="token function">charAt</span><span class="token punctuation">(</span><span class="token keyword">int</span> index<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//返回指定索引处的 char 值</span><span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">indexOf</span><span class="token punctuation">(</span>String str<span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">lastIndexOf</span><span class="token punctuation">(</span><span class="token keyword">int</span> ch<span class="token punctuation">)</span><span class="token keyword">public</span> String<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">split</span><span class="token punctuation">(</span>String regex<span class="token punctuation">)</span><span class="token keyword">public</span> String <span class="token function">substring</span><span class="token punctuation">(</span><span class="token keyword">int</span> beginIndex<span class="token punctuation">)</span> <span class="token keyword">public</span> String <span class="token function">replace</span><span class="token punctuation">(</span><span class="token keyword">char</span> oldChar<span class="token punctuation">,</span><span class="token keyword">char</span> newChar<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><h2 id="Object"><a href="#Object" class="headerlink" title="Object"></a>Object</h2><p>在 Java 中 Object 是所有的祖类。</p><h3 id="常用方法"><a href="#常用方法" class="headerlink" title="常用方法"></a>常用方法</h3><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">native</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">equals</span><span class="token punctuation">(</span>Object obj<span class="token punctuation">)</span><span class="token keyword">protected</span> <span class="token keyword">native</span> Object <span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> CloneNotSupportedException<span class="token keyword">public</span> String <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> Class<span class="token operator"><</span><span class="token operator">?</span><span class="token operator">></span> <span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">finalize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> Throwable <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">notifyAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token keyword">long</span> timeout<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token keyword">long</span> timeout<span class="token punctuation">,</span> <span class="token keyword">int</span> nanos<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException</code></pre><h3 id="equals"><a href="#equals" class="headerlink" title="equals()"></a>equals()</h3><ul><li>对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。</li><li>对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。</li></ul><p><strong>“==”和equals的区别</strong></p><p><code>==</code>: 用来判断两个对象的内存地址是否相同(比较的是变量(栈)内存中存放的对象的(堆)内存地址,)。比较的是真正意义上的指针操作。</p><p><code>equals</code>:用来比较的是两个对象的内容是否相等</p><pre><code>String s1 = new String("ab"); // s1 为一个引用String s2 = new String("ab"); // s2 为另一个引用,对象的内容一样String s3 = "ab"; // 放在常量池中String s4 = "ab"; // 从常量池中查找System.out.println(s1 == s2); // falseSystem.out.println(s3 == s4); // trueSystem.out.println(s1 == s3); // falseSystem.out.println(s1.equals(s2)); // trueSystem.out.println(s3.equals(s4)); // trueSystem.out.println(s1.equals(s3)); // true</code></pre><p>对equals重新需要注意五点:</p><ul><li>1 自反性:对任意引用值X,x.equals(x)的返回值一定为true;</li><li>2 对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;</li><li>3 传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true ;</li><li>4 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变;</li><li>5 非空性:任何非空的引用值X,x.equals(null)的返回值一定为false 。</li></ul><h3 id="hashCode"><a href="#hashCode" class="headerlink" title="hashCode()"></a>hashCode()</h3><p>hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。</p><p>所以:在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。</p><p><strong>为什么要有 hashCode?</strong>因为 <code>hashCode()</code> 的作用就是<strong>获取哈希码</strong>,确定该对象在哈希表中的索引位置</p><p><strong>hashCode()与equals()</strong></p><ol><li>如果两个对象相等,则hashcode一定也是相同的</li><li>两个对象相等,对两个对象分别调用equals方法都返回true</li><li>两个对象有相同的hashcode值,它们也不一定是相等的</li><li><strong>因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖</strong></li><li>hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)</li></ol><h3 id="clone"><a href="#clone" class="headerlink" title="clone()"></a>clone()</h3><p>clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。</p><p>克隆(clone方法)为浅拷贝</p><p><strong>1.浅拷贝</strong>:对基本数据类型进行值拷贝,对引用数据类型的<code>引用地址进行拷贝</code>,拷贝对象和原始对象的引用类型引用同一个对象</p><p><strong>2.深拷贝</strong>: 对基本数据类型进行值拷贝,对引用数据类型的<code>内容进行拷贝</code>,拷贝对象和原始对象的引用类型引用不同对象。</p><p><strong>深拷贝实现</strong>:</p><ul><li><code>序列化</code>(serialization)这个对象,再反序列化回来,就可以得到这个新的对象,无非就是序列化的规则需要我们自己来写。</li><li><code>实现Clonable接口</code>,覆盖并重写clone(),除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。如果只是用<strong>Object中默认的clone方法,是浅拷贝的</strong></li></ul><pre><code>public class Test implements Cloneable { private int[] arr = {1,2,3,4}; @Override protected Test clone() throws CloneNotSupportedException { Test newBody = (Test) super.clone(); newBody.arr = arr.clone(); // 深拷贝实现 return newBody; }}</code></pre><p>开发中常用的对象拷贝工具:</p><p>例如DozerMapper、Apache BeanUtils、Spring、Jodd BeanUtils、甚至是Cglib 都提供了这样的功能</p><p>选择Cglib的 <strong>BeanCopier</strong> 进行Bean拷贝的理由是,其性能要比 <strong>Spring的BeanUtils **,</strong>Apache的BeanUtils <strong>和 **PropertyUtils</strong> 要好很多,尤其是数据量比较大的情况下</p><p>Cglib 的beans 包 操作</p><ul><li>BeanCopier:用于两个bean之间,同名属性间的拷贝。</li><li>BulkBean:用于两个bean之间,自定义get&set方法间的拷贝。</li><li>BeanMap:针对POJO Bean与Map对象间的拷贝。</li><li>BeanGenerator:根据Map<String,Class>properties的属性定义,动态生成POJO Bean类。</li></ul>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(3)常用关键字特性</title>
<link href="/2020/01/03/java-ji-chu-pian-3-chang-yong-guan-jian-zi-te-xing/"/>
<url>/2020/01/03/java-ji-chu-pian-3-chang-yong-guan-jian-zi-te-xing/</url>
<content type="html"><![CDATA[<p>本章中主要了解一下我们在开发过程中常用,也必须掌握的一些特殊关键字的作用。</p><h2 id="访问权限"><a href="#访问权限" class="headerlink" title="访问权限"></a>访问权限</h2><p>在Java中有4中访问权限的修饰符:<strong>private</strong>、<strong>default</strong>((默认一般省略)、<strong>public</strong>、<strong>protected</strong>。一般用于对类或类中的成员(字段以及方法)加上访问修饰符</p><p>权限的主要作用范围:同一个类中、同一个包下、父子类、不同的包</p><p>可被修饰对象:类和成员变量;类可见表示其它类可以用这个类创建实例对象;成员可见表示其它类可以用这个类的实例对象访问到该成员。</p><p><strong>4种修饰符的权限范围:</strong></p><blockquote><ul><li>private:指”私有的”。被其修饰的属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问</li><li>default:即不加任何访问修饰符,通常称为“默认访问权限“或者“包访问权限”。该模式下,只允许在同一个包中进行访问。</li><li>protected: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护访问权限”。被其修饰的属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。</li><li>public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问。</li></ul></blockquote><table><thead><tr><th>修饰符</th><th>同类</th><th align="left">同包</th><th>子类</th><th>不同包非子类</th></tr></thead><tbody><tr><td>private</td><td>√</td><td align="left">×</td><td>×</td><td>×</td></tr><tr><td>default</td><td>√</td><td align="left">√</td><td>×</td><td>×</td></tr><tr><td>protected</td><td>√</td><td align="left">√</td><td>√</td><td>×</td></tr><tr><td>public</td><td>√</td><td align="left">√</td><td>√</td><td>√</td></tr></tbody></table><p>从上表中我们很容易看出,权限范围从小到大依次为:<strong>private < default < protected < public</strong></p><hr><h2 id="final-和-static"><a href="#final-和-static" class="headerlink" title="final 和 static"></a>final 和 static</h2><h3 id="final"><a href="#final" class="headerlink" title="final"></a>final</h3><p>在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)</p><ul><li><strong>修饰变量</strong>:表示常量,对于基本类型,final 使数值不变;对于引用类型,final 使引用地址不变,但对象本身的属性是可以被修改的。</li><li><strong>修饰方法</strong>:不能被子类的方法重写,但可以被继承,<strong>不能修饰构造方法</strong>。。</li><li><strong>修饰类</strong> :该不能被继承,没有子类,final类中的方法默认是final的。Java中的String类就是一个final类</li></ul><h3 id="static"><a href="#static" class="headerlink" title="static"></a>static</h3><p>在Java语言中,static 可以用来修饰成员变量和成员方法,当然也可以是静态代码块</p><ul><li><strong>静态变量</strong>:又称为类变量,该类的所有实例都共享本类的静态变量,且在内存中只存在一份</li><li><strong>静态方法</strong>:在类加载的时候就存在了,它不依赖于任何实例,只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字(此时可能没有实例)。</li><li><strong>静态语句块</strong>:在类初始化时运行一次。</li><li><strong>静态内部类</strong>:非静态内部类依赖于外部类的实例,而静态内部类不需要。静态内部类不能访问外部类的非静态的变量和方法。</li></ul><p><strong>使用时注意:</strong></p><ol><li>静态变量,静态方法可以通过类名直接访问</li><li>初始化顺序:静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。(此处不演示,在类初始化篇章中演示)</li></ol><p><strong>问:在一个静态方法内调用一个非静态成员为什么是非法的?</strong></p><p>由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。</p><h3 id="成员变量、静态变量、局部变量的区别"><a href="#成员变量、静态变量、局部变量的区别" class="headerlink" title="成员变量、静态变量、局部变量的区别"></a><strong>成员变量、静态变量、局部变量的区别</strong></h3><p>从生命周期比较:</p><ul><li>静态变量可以被对象调用,也可以被类名调用。以static关键字申明的变量,其独立在对象之外,有许多对象共享的变量。在对象产生之前产生,存在于<strong>方法区静态区中</strong>。</li><li>成员变量只能被对象调用。随着对象创建而存在,随对象销毁而销毁。存在于<strong>堆栈内存中</strong></li><li>局部变量在方法或语句块中申明的变量,生命周期只在定义的{}之中,不能跨方法或语句块使用。</li></ul><p>从访问权限比较:</p><ul><li><strong>静态变量称为对象的共享数据</strong>,成员变量可以称为对象的特有数据,局部变量为方法所有</li><li>成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。</li></ul><hr><h2 id="abstract-和-interface"><a href="#abstract-和-interface" class="headerlink" title="abstract 和 interface"></a>abstract 和 interface</h2><h3 id="abstract"><a href="#abstract" class="headerlink" title="abstract"></a>abstract</h3><p>在 Java 中 abstract 即抽象,一般使用 <code>abstract</code> 关键字修饰的类或方法</p><p>修饰的类时</p><blockquote><ol><li>不能被实例化,需要继承抽象类才能实例化其子类。</li><li>访问权限可以使用<code>public</code>、<code>private</code>、<code>protected</code>,其表达形式为:(public)abstract class 类名{} </li><li>抽象类不能使用final关键字修饰,因为final修饰的类是无法被继承</li><li>可以定义构造方法、静态方法、普通方法;非抽象的普通成员变量、静态成员变量</li></ol></blockquote><p>修饰的方法时</p><blockquote><ol><li>含有该抽象方法的类必须定义为抽象类,但抽象类可以没有抽象方法。</li><li>访问权限可以使用<code>public</code>、<code>default</code>、<code>protected</code>,不能为<code>private</code>,因为抽象方法必须被子类实现(覆写),而private权限对于子类来 说是不能访问的,所以就会产生矛盾,</li><li>不能用static修饰,因为没有主体</li></ol></blockquote><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">MyAbstract</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> String name<span class="token operator">=</span><span class="token string">"小米"</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> price<span class="token operator">=</span> <span class="token number">1800</span><span class="token punctuation">;</span> <span class="token function">MyAbstract</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>price<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">void</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//权限不能为 private</span><span class="token punctuation">}</span></code></pre><h3 id="interface"><a href="#interface" class="headerlink" title="interface"></a>interface</h3><p>在 Java中 interface 即接口,是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,Java 8 开始,接口也可以拥有<code>default</code>的方法实现,是因为不支持默认方法的接口的维护成本太高</p><blockquote><ol><li>接口的方法访问权限只能为 <code>public</code>,Java 8可以为<code>default</code>,但是必须有方法体</li><li>接口的方法默认<code>public abstract</code> 也可以由 static 修饰</li><li>接口的方法可以定义为 <code>public static</code> ,但是必须有方法体,且只能有接口类名调用</li><li>成员变量默认为<code>public staic final</code></li></ol></blockquote><pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">MyInterface</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> price <span class="token operator">=</span> <span class="token number">1800</span><span class="token punctuation">;</span> <span class="token keyword">void</span> <span class="token function">outName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">default</span> <span class="token keyword">void</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"MyInterface print: default Method"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"MyInterface price="</span><span class="token operator">+</span>price<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyInterfaceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">MyInterface</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">outName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"I'm a MyInterfaceImpl"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> MyInterface my <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyInterfaceImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> my<span class="token punctuation">.</span><span class="token function">outName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> my<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// MyInterfaceImpl.print();// 实现类类名调用时, 提示编译错误</span> MyInterface<span class="token punctuation">.</span><span class="token function">price</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="abstract-和-interface-的区别"><a href="#abstract-和-interface-的区别" class="headerlink" title="abstract 和 interface 的区别"></a>abstract 和 interface 的区别</h3><p><strong>从定义分析</strong></p><ul><li>抽象类和接口都不能直接实例化;抽象方法必须由子类来进行重写</li><li>抽象类单继承,接口多实现</li><li>抽象类可有构造方法,普通成员变量,非抽象的普通方法,静态方法</li><li>抽象类的抽象方法访问权限可以为:public、protected 、default</li><li>接口中变量类型默认public staic final,</li><li>接口中普通方法默认public abstract,没有具体实现</li><li>jdk1.8 中接口可有<strong>静态方法和default(有方法体)方法</strong></li></ul><p><strong>从应用场合分析</strong></p><ul><li>接口:需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。</li><li>抽象类:1、在既需要统一的接口,又需要实例变量或缺省的方法的情况下就可以使用它;2、定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口</li></ul>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(2)三大特性和六大原则</title>
<link href="/2020/01/02/java-ji-chu-pian-2-san-da-te-xing-he-liu-da-yuan-ze/"/>
<url>/2020/01/02/java-ji-chu-pian-2-san-da-te-xing-he-liu-da-yuan-ze/</url>
<content type="html"><![CDATA[<h1 id="三大特性"><a href="#三大特性" class="headerlink" title="三大特性"></a>三大特性</h1><p>在 Java 编程中三大特性指的是<strong>封装、继承、多态</strong></p><ul><li>封装:封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问优点:减少耦合,代码重用,减轻维护</li><li>继承:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。</li><li>多态:指允许不同类的对象对同一消息做出响应。</li></ul><h2 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h2><p>多态一般分为编译时多态和运行时多态,编译时主要指方法的重载;运行时主要指程序中定义的对象引用所指向的具体类型在运行期间才确定</p><p><strong>运行时多态有三个条件:继承、覆盖和重写、向上转型(父类引用指向子类对象)</strong></p><h2 id="方法重载和重写区别"><a href="#方法重载和重写区别" class="headerlink" title="方法重载和重写区别"></a>方法重载和重写区别</h2><p>重写:<strong>发生在继承类中,方法名和参数列表相同</strong>,重写有以下三个限制:</p><ul><li>子类方法的访问权限必须大于等于父类方法;</li><li>子类方法的返回类型必须是父类方法返回类型或为其子类型。</li><li>子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。</li></ul><p>重载:<strong>发生在同一个类中,方法名相同,参数列表不同(个数、类型、顺序),与权限修饰、返回值类型、抛出异常无关</strong></p><p><strong>注意</strong>:构造器是不可以被重写的,但是能重载。</p><p>构造方法有哪些特性?</p><ol><li>名字与类名相同。</li><li>没有返回值,但不能用void声明构造函数。</li><li>生成类的对象时自动执行,无需调用。</li></ol><hr><h1 id="六大原则"><a href="#六大原则" class="headerlink" title="六大原则"></a>六大原则</h1><ol><li><strong>开闭原则</strong>:对扩展开发放,对修改关闭,要求在添加新功能时不需要修改代码,符合开闭原则最典型的设计模式是装饰者模式</li><li><strong>单一职责原则</strong>:一个类只负责一件事,尽量使用合成/聚合的方式,而不是使用继承。</li><li><strong>里式替换原则</strong> :任何基类可以出现的地方,子类一定可以出现。</li><li><strong>依赖倒转原则</strong>:依赖于抽象而不依赖于具体</li><li><strong>接口隔离原则</strong>:使用多个隔离的接口,比使用单个接口要好 ,不应该强迫客户依赖于它们不用的方法。</li><li><strong>迪米特法则</strong>:一个软件实体应当尽可能少地与其他实体发生相互作用。</li></ol>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
<entry>
<title>Java-基础篇(1)总纲</title>
<link href="/2020/01/01/java-ji-chu-pian-1-zong-gang/"/>
<url>/2020/01/01/java-ji-chu-pian-1-zong-gang/</url>
<content type="html"><![CDATA[<p> Java 篇章中,一般我们面试时都会考察我们掌握的基础点,看是否基础牢固,决定了我们是不是能进一步的交流,如果一个人的基础都牢固,那面试官肯定不要你。</p><p>以下我们从以下几个方便来巩固以下我们的技术点:</p><ul><li>三大特性和六大原则</li><li>关键字</li><li>数据类型</li><li>类初始化</li><li>逻辑运算</li><li>异常</li><li>反射</li></ul><p><img src="Java%E5%9F%BA%E7%A1%80.png" alt="Java基础"></p>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> 面试考点 </tag>
<tag> Java 基础 </tag>
</tags>
</entry>
</search>