-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
558 lines (295 loc) · 136 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>hlx</title>
<link href="/atom.xml" rel="self"/>
<link href="http://inmyai.com/"/>
<updated>2018-10-10T13:56:04.247Z</updated>
<id>http://inmyai.com/</id>
<author>
<name>hlx</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>JVM:对象还活着吗</title>
<link href="http://inmyai.com/2018/10/10/JVM-%E5%AF%B9%E8%B1%A1%E8%BF%98%E6%B4%BB%E7%9D%80%E5%90%97/"/>
<id>http://inmyai.com/2018/10/10/JVM-对象还活着吗/</id>
<published>2018-10-10T12:06:47.000Z</published>
<updated>2018-10-10T13:56:04.247Z</updated>
<content type="html"><![CDATA[<h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>堆存放着很多实例,那么垃圾收集器是如何判断实例是否可以进行回收的呢?</p><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><h3 id="引用计数算法-Reference-Counting"><a href="#引用计数算法-Reference-Counting" class="headerlink" title="引用计数算法(Reference Counting)"></a>引用计数算法(Reference Counting)</h3><p>这个算法实现起来比较简单,给每个对象加一个引用计数器,当有其他地方引用该对象时,引用计数器就加一,取消引用时则减一。目前, Python 就是采用这种算法来判断对象是否已经死亡。 </p><p>往往简单的东西就存在一些弊端,对于这么一种情况,A 对象中的成员引用 B 对象,B 对象中的成员引用 A 对象,然后让 A 和 B 对象指向 null。但是由于 A 还有被 B 引用, B 还有被 A 引用,由此形成一个闭环,这两个对象都无法被垃圾收集器回收。</p><h3 id="可达性分析算法-Reachability-Analysis"><a href="#可达性分析算法-Reachability-Analysis" class="headerlink" title="可达性分析算法(Reachability Analysis)"></a>可达性分析算法(Reachability Analysis)</h3><p>通过所谓的 GC Roots 作为对象的起始点,不断向下搜索,从搜索到的对象到 GC Roots 之间的所走的路径称之为 引用链(Reference Chain)。如果从 GC Roots 找不到这么一条链路到达该对象,则该对象不可达,符合可回收的对象。</p><p>所谓的 GC Roots:</p><ul><li>1.虚拟机栈引用的对象</li><li>2.方法区中静态变量引用的对象</li><li>3.方法区中常量引用的对象</li><li>4.JNI引用的对象</li></ul>]]></content>
<summary type="html">
<h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>堆存放着很多实例,那么垃圾收集器是如何判断实例是否可以进行回收的呢?</p>
<h3 id="方法"><a href="#方法" class
</summary>
</entry>
<entry>
<title>LC:所有可能的满二叉树</title>
<link href="http://inmyai.com/2018/10/10/LC-%E6%89%80%E6%9C%89%E5%8F%AF%E8%83%BD%E7%9A%84%E6%BB%A1%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
<id>http://inmyai.com/2018/10/10/LC-所有可能的满二叉树/</id>
<published>2018-10-10T11:20:00.000Z</published>
<updated>2018-10-10T11:48:23.297Z</updated>
<content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。</p><p>返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。</p><p>答案中每个树的每个结点都必须有 node.val=0。</p><p>你可以按任何顺序返回树的最终列表。</p><p><strong>Example 1:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Input: 7</span><br><span class="line">Output: [[0,0,0,null,null,0,0,null,null,0,0],[0,0,0,null,null,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,null,null,null,null,0,0],[0,0,0,0,0,null,null,0,0]]</span><br></pre></td></tr></table></figure><p><strong>Explanation:</strong></p><p><img src="https://s3-lc-upload.s3.amazonaws.com/uploads/2018/08/22/fivetrees.png" alt="解释"></p><p><strong>提示:</strong></p><ul><li>1 <= N <= 20</li></ul><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>这道题目不是那么好写,最后还是看了解析才懂的。最主要的一步是发现其中的规律,直接通过 BFS查找是非常困难的。 </p><p>最关键的规律,也是通往成功的大门: </p><ul><li>1.只有当N为奇数的时候,才有解(省了一半的时间)</li><li>2.对于一个结点N的树,可以分解为有 X 个结点的左子树和有 (N-1-X) 个结点的右子树</li></ul><p>利用第二点特性,就可以直接通过一个循环,遍历完所有 X 的情况,并利用递归获取到拥有 X 个结点的所有子树 和 拥有 (N-1-X) 个结点的所有子树,最后遍历左右子树的所有情况,进行组合。 </p><p>主要的想法即是通过动态规划对树不断分解,最后还可以通过备忘录继续优化。</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>未使用备忘录:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">class Solution {</span><br><span class="line">public:</span><br><span class="line"> vector<TreeNode*> allPossibleFBT(int N) {</span><br><span class="line"> vector<TreeNode*> ans;</span><br><span class="line"> if(N==1){</span><br><span class="line"> TreeNode* node = new TreeNode(0);</span><br><span class="line"> ans.push_back(node);</span><br><span class="line"> return ans;</span><br><span class="line"> }</span><br><span class="line"> if(N&1!=1||N<1) return ans;</span><br><span class="line"> for(int i=1;i<N;i=i+2){</span><br><span class="line"> vector<TreeNode*> lAns = allPossibleFBT(i);</span><br><span class="line"> vector<TreeNode*> rAns = allPossibleFBT(N-i-1);</span><br><span class="line"> for(int j=0;j<lAns.size();j++){</span><br><span class="line"> for(int k=0;k<rAns.size();k++){</span><br><span class="line"> TreeNode* node = new TreeNode(0);</span><br><span class="line"> node->left = lAns;</span><br><span class="line"> node->right = rAns;</span><br><span class="line"> ans.push_back(node);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return ans;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>使用备忘录:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">class Solution {</span><br><span class="line">public:</span><br><span class="line"> vector<TreeNode*> allPossibleFBT(int N) {</span><br><span class="line"> map<int,vector<TreeNode*>> ansMap;</span><br><span class="line"> vector<TreeNode*> ans;</span><br><span class="line"> if(N==1){</span><br><span class="line"> TreeNode* node = new TreeNode(0);</span><br><span class="line"> ans.push_back(node);</span><br><span class="line"> return ans;</span><br><span class="line"> }</span><br><span class="line"> if(N&1!=1||N<1) return ans;</span><br><span class="line"> for(int i=1;i<N;i=i+2){</span><br><span class="line"> vector<TreeNode*> lAns,rAns;</span><br><span class="line"> if(ansMap.count(i)==1) lAns=ansMap[i];</span><br><span class="line"> else{</span><br><span class="line"> lAns = allPossibleFBT(i);</span><br><span class="line"> ansMap[i] = lAns;</span><br><span class="line"> }</span><br><span class="line"> if(ansMap.count(N-i-1)==1) rAns=ansMap[N-i-1];</span><br><span class="line"> else{</span><br><span class="line"> rAns = allPossibleFBT(N-i-1);</span><br><span class="line"> ansMap[N-i-1] = rAns;</span><br><span class="line"> } </span><br><span class="line"> for(int j=0;j<lAns.size();j++){</span><br><span class="line"> for(int k=0;k<rAns.size();k++){</span><br><span class="line"> TreeNode* node = new TreeNode(0);</span><br><span class="line"> node->left = lAns[j];</span><br><span class="line"> node->right = rAns[k];</span><br><span class="line"> ans.push_back(node);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return ans;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。</p>
<p>返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元
</summary>
<category term="Leetcode" scheme="http://inmyai.com/categories/Leetcode/"/>
</entry>
<entry>
<title>LC:回文子串</title>
<link href="http://inmyai.com/2018/10/05/LC-%E5%9B%9E%E6%96%87%E5%AD%90%E4%B8%B2/"/>
<id>http://inmyai.com/2018/10/05/LC-回文子串/</id>
<published>2018-10-05T07:51:00.000Z</published>
<updated>2018-10-05T08:30:38.280Z</updated>
<content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。</p><p>具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。</p><p><strong>示例 1:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: "abc"</span><br><span class="line">输出: 3</span><br><span class="line">解释: 三个回文子串: "a", "b", "c".</span><br></pre></td></tr></table></figure><p><strong>示例 2:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: "aaa"</span><br><span class="line">输出: 6</span><br><span class="line">说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".</span><br></pre></td></tr></table></figure><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>纯暴力解法,先是双重循环遍历所有情况需要O(n^2),每种情况判断回文需要O(n),因此总计需要O(n^3)。 </p><p>优化的方法即是利用之前所找到的回文,加快判断新的回文。而建立最基础的回文(已知回文)是非常关键的,这点可能不太容易想到。 </p><p>判断一个字符串是否为回文,例如<code>s.......b</code>,只要判断中间的<code>.......</code>是否为回文,并且开头的字符和最后一个字符是否相等。</p><p>因此,我们先遍历一个字符和两个字符的情况,建立一个基础的回文,通过二维数组<code>result[i][j]</code>进行存储。例如,<code>result[0][1]</code>代表下标范围[0,1]的字符串是否为回文,回文取1,非回文取0。基础回文建立完之后,以O(n^2)时间遍历完所有情况,并利用之前判断回文的规律,在O(1)时间判断是否回文。最后总计需要O(n^2)时间。</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">class Solution {</span><br><span class="line">public:</span><br><span class="line"> int result[1000][1000] = {0};</span><br><span class="line"> int countSubstrings(string s) {</span><br><span class="line"> if(s.length()==0) return 0;</span><br><span class="line"> int cnt = 0;</span><br><span class="line"> for(int i=0;i<s.length();i++){</span><br><span class="line"> result[i][i] = 1;</span><br><span class="line"> cnt++;</span><br><span class="line"> if(i+1<s.length()&&s[i]==s[i+1]){</span><br><span class="line"> result[i][i+1] = 1;</span><br><span class="line"> cnt++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> for(int j=2;j<s.length();j++){</span><br><span class="line"> for(int i=0;i<s.length();i++){</span><br><span class="line"> if(s[i]==s[i+j]&&result[i+1][i+j-1]==1){</span><br><span class="line"> result[i][i+j] = 1;</span><br><span class="line"> cnt++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return cnt;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。</p>
<p>具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被
</summary>
<category term="Leetcode" scheme="http://inmyai.com/categories/Leetcode/"/>
</entry>
<entry>
<title>LC:买卖股票的最佳时机</title>
<link href="http://inmyai.com/2018/10/05/LC-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA/"/>
<id>http://inmyai.com/2018/10/05/LC-买卖股票的最佳时机/</id>
<published>2018-10-05T02:26:00.000Z</published>
<updated>2018-10-05T02:56:58.388Z</updated>
<content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。</p><p>如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。</p><p>注意你不能在买入股票前卖出股票。</p><p><strong>示例 1:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入: [7,1,5,3,6,4]</span><br><span class="line">输出: 5</span><br><span class="line">解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。</span><br><span class="line"> 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。</span><br></pre></td></tr></table></figure><p><strong>示例 2:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: [7,6,4,3,1]</span><br><span class="line">输出: 0</span><br><span class="line">解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。</span><br></pre></td></tr></table></figure><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>引入两个概念,<code>cash</code>代表在卖掉股票的情况下(即手上没有股票)所能持有的最大现金,<code>hold</code>代表在拥有一支股票情况下所能持有的最大现金。</p><p>假设知道第一天的<code>cash</code>和<code>hold</code>,那么第二天的<code>cash</code>有两种结果,一个就是保留原有的<code>cash</code>(之前的股票已经卖出情况),另一个就是通过卖掉第一天仍然持有的股票(之前还剩有股票情况),其值为<code>hold - prices[i] - fee</code>。<br>而<code>hold</code>也有两种结果,一个就是保留原有的<code>hold</code>(保留剩余的股票),另一个就是用之前的<code>cash</code>购买股票(之前手头没有股票情况),其值为<code>cash - prices[i]</code>。</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">class Solution {</span><br><span class="line"> public int maxProfit(int[] prices, int fee) {</span><br><span class="line"> int cash = 0, hold = -prices[0];</span><br><span class="line"> for (int i = 1; i < prices.length; i++) {</span><br><span class="line"> cash = Math.max(cash, hold + prices[i] - fee);</span><br><span class="line"> hold = Math.max(hold, cash - prices[i]);</span><br><span class="line"> }</span><br><span class="line"> return cash;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="思考"><a href="#思考" class="headerlink" title="思考"></a>思考</h3><p>注意到,每次循环,<code>hold</code>是通过当前已经得出的<code>cash</code>进行计算,这是一个经验规律。更好理解的写法应该是:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cash = max(oldCash, oldHold + prices[i] - fee);</span><br><span class="line">hold = max(oldHold, oldCash - prices[i]);</span><br></pre></td></tr></table></figure><p>至于那个经验规律,当<code>hold + prices[i] - fee</code> < <code>cash</code> 的情况下,<code>cash</code> = <code>oldCash</code>,<code>hold = Math.max(hold, cash - prices[i])</code>也就没什么问题。<br>而当<code>hold + prices[i] - fee</code> ><code>cash</code> 的情况下:<br><code>cash - prices[i]</code> < <code>hold - fee</code> < <code>hold</code><br>因此,<code>hold</code>的最大值为<code>oldHold</code>,当前循环所计算出来新的<code>cash</code>并不会产生任何影响</p>]]></content>
<summary type="html">
<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。</p>
<p>如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一
</summary>
<category term="Leetcode" scheme="http://inmyai.com/categories/Leetcode/"/>
</entry>
<entry>
<title>Shell:单引号|双引号|不加引号</title>
<link href="http://inmyai.com/2018/09/22/Shell-%E5%8D%95%E5%BC%95%E5%8F%B7-%E5%8F%8C%E5%BC%95%E5%8F%B7-%E4%B8%8D%E5%8A%A0%E5%BC%95%E5%8F%B7/"/>
<id>http://inmyai.com/2018/09/22/Shell-单引号-双引号-不加引号/</id>
<published>2018-09-22T06:07:00.000Z</published>
<updated>2018-10-10T12:04:02.623Z</updated>
<content type="html"><![CDATA[<h3 id="单引号"><a href="#单引号" class="headerlink" title="单引号"></a>单引号</h3><p><strong>所见即所得</strong>,任何由单引号包含的内容都会被原样输出,即便里面包含一个变量的名字,变量名也会直接被输出,而非把该变量取值后再进行输出,例如<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/sh</span><br><span class="line">data="s"</span><br><span class="line">echo '$data'</span><br></pre></td></tr></table></figure></p><h3 id="双引号"><a href="#双引号" class="headerlink" title="双引号"></a>双引号</h3><p>相比于单引号,如果内容包括指令或者变量名,则会先把执行的执行结果替代指令,或是把变量值解析后替代变量名。注意,变量名的前面应该加上<code>$</code>,例如<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/sh</span><br><span class="line">data="s"</span><br><span class="line">echo "$data"</span><br></pre></td></tr></table></figure></p><h3 id="不加引号"><a href="#不加引号" class="headerlink" title="不加引号"></a>不加引号</h3><p>不加引号与加双引号基本功能类似,都具有转义的功能。唯一的一个区别是,如果不加引号,则含有空格的字符串将不会作为一个整体,而且,一些转义字符也无法输出。例如<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/sh</span><br><span class="line">a=b c</span><br><span class="line">echo "$a"</span><br><span class="line">a="b c"</span><br><span class="line">echo "$a"</span><br><span class="line">a=b \n c</span><br><span class="line">echo "$a"</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html">
<h3 id="单引号"><a href="#单引号" class="headerlink" title="单引号"></a>单引号</h3><p><strong>所见即所得</strong>,任何由单引号包含的内容都会被原样输出,即便里面包含一个变量的名字,变量名也会直接被输出
</summary>
<category term="Shell" scheme="http://inmyai.com/categories/Shell/"/>
<category term="归纳" scheme="http://inmyai.com/tags/%E5%BD%92%E7%BA%B3/"/>
</entry>
<entry>
<title>LC:Longest Substring Without Repeating Characters</title>
<link href="http://inmyai.com/2018/09/08/LC-Longest-Substring-Without-Repeating-Characters/"/>
<id>http://inmyai.com/2018/09/08/LC-Longest-Substring-Without-Repeating-Characters/</id>
<published>2018-09-08T01:59:00.000Z</published>
<updated>2018-09-08T04:00:24.372Z</updated>
<content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>Given a string, find the length of the longest substring without repeating characters.</p><h4 id="Example-1"><a href="#Example-1" class="headerlink" title="Example 1:"></a>Example 1:</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Input: "abcabcbb"</span><br><span class="line">Output: 3 </span><br><span class="line">Explanation: The answer is "abc", which the length is 3.</span><br></pre></td></tr></table></figure><h4 id="Example-2"><a href="#Example-2" class="headerlink" title="Example 2:"></a>Example 2:</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Input: "bbbbb"</span><br><span class="line">Output: 1</span><br><span class="line">Explanation: The answer is "b", with the length of 1.</span><br></pre></td></tr></table></figure><h4 id="Example-3"><a href="#Example-3" class="headerlink" title="Example 3:"></a>Example 3:</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Input: "pwwkew"</span><br><span class="line">Output: 3</span><br><span class="line">Explanation: The answer is "wke", with the length of 3. </span><br><span class="line"> Note that the answer must be a substring, "pwke" is a subsequence and not a substring.</span><br></pre></td></tr></table></figure><h3 id="解法"><a href="#解法" class="headerlink" title="解法"></a>解法</h3><h4 id="方法一"><a href="#方法一" class="headerlink" title="方法一"></a>方法一</h4><h5 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h5><p>根据题意,最长的子字符串需要满足不含有重复字符,也就是该字符串没有2个相同的字符。因此,寻找子字符串的过程中,如果遇到重复字符,则需要重新计算最大长度。<br>问题的关键在于: </p><ul><li>计算最大长度 </li><li>判断重复字符</li></ul><p>计算最大长度:引入两个”指针”,第一个指针指向子字符串”起点”(子字符串前面的一个字符),初始为-1,第二个指针指向子字符串的终点,指针值即为字符串的下标,初始为-1。循环遍历字符串,第二个指针不断自增,为当前循环的字符的下标。每次循环计算终点指针和起点指针的差值即为子字符串的长度。 </p><p>判断重复字符:初始化一个字符映射,键为字符的ASCII值,值为字符的下标。字符下标代表着该字符上次所出现的位置,初始值为-1,即没有出现过。如果字符下标大于起点,则代表该字符已经出现过一次了,需要将第一个指针重新指向该重复字符,即为新子字符串的”起点”</p><h5 id="图解"><a href="#图解" class="headerlink" title="图解"></a>图解</h5><p>输入: <code>ABCB</code></p><p>起点指针指向-1下标,<code>A</code>上次的下标为-1 <= 起点(<code>A</code>上次的位置在起点之前),<code>A</code>没有重复,起点指针不变,终点指针指向<code>A</code>,当前长度 = 终点 - 起点 = 0 - (-1) = 1;依次类推到<code>C</code>,此时状态图: </p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-9-8/39755096.jpg" alt="初始"></p><p>起点为-1,加入B之后,<code>B</code>上次的下标为1 > 起点(<code>B</code>上次的位置在起点之后),<code>B</code>有重复,起点指针指向<code>B</code>前面的一个字符,终点指针指向<code>B</code>,当前长度 = 终点 - 起点 = 3 - 1 = 2,代表的子字符串为<code>CB</code>(起点不包括)。</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-9-8/67350660.jpg" alt="结果"></p><h5 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">int lengthOfLongestSubstring(string s) {</span><br><span class="line"> vector<int> dict(256, -1);</span><br><span class="line"> int maxLen = 0, start = -1;</span><br><span class="line"> for (int i = 0; i != s.length(); i++) {</span><br><span class="line"> if (dict[s[i]] > start)</span><br><span class="line"> start = dict[s[i]];</span><br><span class="line"> dict[s[i]] = i;</span><br><span class="line"> maxLen = max(maxLen, i - start);</span><br><span class="line"> }</span><br><span class="line"> return maxLen;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h5 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h5><ul><li>ASCII一共有128个字符</li><li>扩展ASCII一共有256个字符,非国际标准</li></ul>]]></content>
<summary type="html">
<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>Given a string, find the length of the longest substring without repea
</summary>
<category term="algorithm" scheme="http://inmyai.com/categories/algorithm/"/>
<category term="leetcode" scheme="http://inmyai.com/tags/leetcode/"/>
</entry>
<entry>
<title>第一个Shell | Spring Boot 快速注册服务脚本</title>
<link href="http://inmyai.com/2018/08/09/%E7%AC%AC%E4%B8%80%E4%B8%AAShell-Spring-Boot-%E5%BF%AB%E9%80%9F%E6%B3%A8%E5%86%8C%E6%9C%8D%E5%8A%A1%E8%84%9A%E6%9C%AC/"/>
<id>http://inmyai.com/2018/08/09/第一个Shell-Spring-Boot-快速注册服务脚本/</id>
<published>2018-08-09T09:46:00.000Z</published>
<updated>2018-09-22T06:29:59.676Z</updated>
<content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>Spring Boot项目通过JAR打包部署的时候,一般我们所采取的措施是将其注册为服务,并通过<strong>service</strong>命令管理项目。但注册服务的过程相对繁琐,不如写一个脚本来快速注册(入门Shell)。</p><h3 id="注册服务脚本"><a href="#注册服务脚本" class="headerlink" title="注册服务脚本"></a>注册服务脚本</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/sh</span><br><span class="line">echo "Please input the path of jar:"</span><br><span class="line">read -e jar_path</span><br><span class="line">echo "Please input the name of service:"</span><br><span class="line">read -e service_name</span><br><span class="line">service_path="/etc/init.d/"$service_name</span><br><span class="line">ln -s $jar_path $service_path</span><br><span class="line">chmod +x $service_path</span><br><span class="line">echo "Register success!"</span><br></pre></td></tr></table></figure><h3 id="脚本说明"><a href="#脚本说明" class="headerlink" title="脚本说明"></a>脚本说明</h3><ul><li>‘#’开头所在行即为注释,’#!’为约定的标记,代表这个脚本需要使用的解释器</li><li>echo用于字符的显示,提高用户体验</li><li>read用于读取输入流,并将其存入指定的变量;-e使得输入的字符暂时存储在缓存区中,解决read退格异常问题</li><li>字符串拼接:只需将变量紧挨在一起即可</li><li>ln -s : 创建指向目标jar的软连接(类似于快捷方式),存放在’/etc/init.d/‘中</li><li>chmod +x :增加可执行权限</li></ul><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p>1.通过maven打包出一个<strong>完全可执行的jar</strong>,即可以被注册为服务,具体请参照<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html" target="_blank" rel="noopener">Spring Boot官方文档</a>。 </p><p>2.<code>vim deploy.sh</code>,复制以上脚本代码,保存退出 </p><p>3.<code>chmod +x deploy.sh</code>,为脚本增加可执行的权限</p><p>4.<code>./deploy.sh</code>,执行该脚本。输入jar的路径,然后输入服务的名称(可自定义),最后启动测试 </p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-8-9/88921587.jpg" alt="测试样例"></p><h3 id="坑"><a href="#坑" class="headerlink" title="坑"></a>坑</h3><p>变量赋值的时候,等号旁边不能有空白,例如上面脚本中的第一个<strong>service_path</strong>所在行,如果写成<code>service_path = "/etc/init.d/"$service_name</code>,脚本执行将会报错。</p>]]></content>
<summary type="html">
<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>Spring Boot项目通过JAR打包部署的时候,一般我们所采取的措施是将其注册为服务,并通过<strong>service</stron
</summary>
<category term="Shell" scheme="http://inmyai.com/categories/Shell/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
</entry>
<entry>
<title>Linux:解除端口占用 [探讨篇]</title>
<link href="http://inmyai.com/2018/07/21/Linux-%E8%A7%A3%E9%99%A4%E7%AB%AF%E5%8F%A3%E5%8D%A0%E7%94%A8/"/>
<id>http://inmyai.com/2018/07/21/Linux-解除端口占用/</id>
<published>2018-07-21T07:04:00.000Z</published>
<updated>2018-08-09T09:41:13.673Z</updated>
<content type="html"><![CDATA[<h3 id="查看端口是否被占用-所属的网络协议"><a href="#查看端口是否被占用-所属的网络协议" class="headerlink" title="查看端口是否被占用(所属的网络协议)"></a>查看端口是否被占用(所属的网络协议)</h3><p><code>netstat -anp | grep 端口号</code></p><h3 id="杀掉进程"><a href="#杀掉进程" class="headerlink" title="杀掉进程"></a>杀掉进程</h3><p><code>kill -s 9 进程标识号</code>,进程标记号即为PID</p><h3 id="Netstat"><a href="#Netstat" class="headerlink" title="Netstat"></a>Netstat</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><p>监控TCP/UDP的工具,用于显示个人网络连接的详细信息。大胆假设,netstat为Net Status的缩写,即网络状态</p><h4 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h4><p>直接窗口命令行输入<code>netstat /?</code>,一份api文档就出炉了</p><ul><li><p>Win10环境下</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">NETSTAT [-a] [-b] [-e] [-f] [-n] [-o] [-p proto] [-r] [-s] [-x] [-t] [interval]</span><br><span class="line"></span><br><span class="line"> -a 显示所有连接和侦听端口。</span><br><span class="line"> -b 显示在创建每个连接或侦听端口时涉及的</span><br><span class="line"> 可执行程序。在某些情况下,已知可执行程序承载</span><br><span class="line"> 多个独立的组件,这些情况下,</span><br><span class="line"> 显示创建连接或侦听端口时</span><br><span class="line"> 涉及的组件序列。在此情况下,可执行程序的</span><br><span class="line"> 名称位于底部 [] 中,它调用的组件位于顶部,</span><br><span class="line"> 直至达到 TCP/IP。注意,此选项</span><br><span class="line"> 可能很耗时,并且在你没有足够</span><br><span class="line"> 权限时可能失败。</span><br><span class="line"> -e 显示以太网统计信息。此选项可以与 -s 选项</span><br><span class="line"> 结合使用。</span><br><span class="line"> -f 显示外部地址的完全限定</span><br><span class="line"> 域名(FQDN)。</span><br><span class="line"> -n 以数字形式显示地址和端口号。</span><br><span class="line"> -o 显示拥有的与每个连接关联的进程 ID。</span><br><span class="line"> -p proto 显示 proto 指定的协议的连接;proto</span><br><span class="line"> 可以是下列任何一个: TCP、UDP、TCPv6 或 UDPv6。如果与 -s</span><br><span class="line"> 选项一起用来显示每个协议的统计信息,proto 可以是下列任何一个:</span><br><span class="line"> IP、IPv6、ICMP、ICMPv6、TCP、TCPv6、UDP 或 UDPv6。</span><br><span class="line"> -q 显示所有连接、侦听端口和绑定的</span><br><span class="line"> 非侦听 TCP 端口。绑定的非侦听端口</span><br><span class="line"> 不一定与活动连接相关联。</span><br><span class="line"> -r 显示路由表。</span><br><span class="line"> -s 显示每个协议的统计信息。默认情况下,</span><br><span class="line"> 显示 IP、IPv6、ICMP、ICMPv6、TCP、TCPv6、UDP 和 UDPv6 的统计信息;</span><br><span class="line"> -p 选项可用于指定默认的子网。</span><br><span class="line"> -t 显示当前连接卸载状态。</span><br><span class="line"> -x 显示 NetworkDirect 连接、侦听器和共享</span><br><span class="line"> 终结点。</span><br><span class="line"> -y 显示所有连接的 TCP 连接模板。</span><br><span class="line"> 无法与其他选项结合使用。</span><br><span class="line"> interval 重新显示选定的统计信息,各个显示间暂停的</span><br><span class="line"> 间隔秒数。按 CTRL+C 停止重新显示</span><br><span class="line"> 统计信息。如果省略,则 netstat 将打印当前的</span><br><span class="line"> 配置信息一次。</span><br></pre></td></tr></table></figure></li><li><p>Linux环境下(排版不是很友好,指令较多,说明简洁)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">usage: netstat [-vWeenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}</span><br><span class="line"> netstat [-vWnNcaeol] [<Socket> ...]</span><br><span class="line"> netstat { [-vWeenNac] -I[<Iface>] | [-veenNac] -i | [-cnNe] -M | -s [-6tuw] } [delay]</span><br><span class="line"></span><br><span class="line"> -r, --route display routing table</span><br><span class="line"> -I, --interfaces=<Iface> display interface table for <Iface></span><br><span class="line"> -i, --interfaces display interface table</span><br><span class="line"> -g, --groups display multicast group memberships</span><br><span class="line"> -s, --statistics display networking statistics (like SNMP)</span><br><span class="line"> -M, --masquerade display masqueraded connections</span><br><span class="line"></span><br><span class="line"> -v, --verbose be verbose</span><br><span class="line"> -W, --wide don't truncate IP addresses</span><br><span class="line"> -n, --numeric don't resolve names</span><br><span class="line"> --numeric-hosts don't resolve host names</span><br><span class="line"> --numeric-ports don't resolve port names</span><br><span class="line"> --numeric-users don't resolve user names</span><br><span class="line"> -N, --symbolic resolve hardware names</span><br><span class="line"> -e, --extend display other/more information</span><br><span class="line"> -p, --programs display PID/Program name for sockets</span><br><span class="line"> -o, --timers display timers</span><br><span class="line"> -c, --continuous continuous listing</span><br><span class="line"></span><br><span class="line"> -l, --listening display listening server sockets</span><br><span class="line"> -a, --all display all sockets (default: connected)</span><br><span class="line"> -F, --fib display Forwarding Information Base (default)</span><br><span class="line"> -C, --cache display routing cache instead of FIB</span><br><span class="line"> -Z, --context display SELinux security context for sockets</span><br><span class="line"></span><br><span class="line"> <Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-S|--sctp} {-w|--raw}</span><br><span class="line"> {-x|--unix} --ax25 --ipx --netrom</span><br><span class="line"> <AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: inet</span><br><span class="line"> List of possible address families (which support routing):</span><br><span class="line"> inet (DARPA Internet) inet6 (IPv6) ax25 (AMPR AX.25)</span><br><span class="line"> netrom (AMPR NET/ROM) ipx (Novell IPX) ddp (Appletalk DDP)</span><br><span class="line"> x25 (CCITT X.25)</span><br></pre></td></tr></table></figure></li></ul><h4 id="查看端口号是否被占用的由来"><a href="#查看端口号是否被占用的由来" class="headerlink" title="查看端口号是否被占用的由来"></a>查看端口号是否被占用的由来</h4><p>netstat -anp 即为 netstat -a -n -p的缩写</p><ul><li>-a用于列出所有连接</li><li>-n用于取消信息的解析,即将信息数字化(numeric),包括主机(host),端口(port)和用户(user)。例如,主机为localhost,数字化为127.0.0.1;端口为http,数字化为80;关于用户,找不到实例,日后补充</li><li>-p用于显示进程标识号和进程名称<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">PID/Program name</span><br><span class="line">28161/nginx: master</span><br></pre></td></tr></table></figure></li></ul><p><code>28161</code>为进程号,<code>nginx: master</code>为进程名称</p><p>至于<code>| grep 端口号</code>,grep为一个使用正则表达式的文本搜索命令。<br>事实上,如果仅仅查看端口占用情况,只需要<code>netstat -an | grep 端口号</code>。且该正则表达式明显不足,如果端口号为80,进行查询之后会出现很多无关的信息,因此我们需要优化一下。端口号显示数据的一个普遍规律是:端口号前面为冒号,后面为空格,例如<strong>:80 </strong><br>因此,更为精准的匹配为<strong>grep:80\ </strong>,注意\后面有一个空格<br>But……….依然无法去除来源地址存在80端口号的网络连接信息<br>最终查询命令:<br><code>netstat -anp | grep :端口号\空格</code></p>]]></content>
<summary type="html">
<h3 id="查看端口是否被占用-所属的网络协议"><a href="#查看端口是否被占用-所属的网络协议" class="headerlink" title="查看端口是否被占用(所属的网络协议)"></a>查看端口是否被占用(所属的网络协议)</h3><p><code>ne
</summary>
<category term="Linux" scheme="http://inmyai.com/categories/Linux/"/>
<category term="端口" scheme="http://inmyai.com/tags/%E7%AB%AF%E5%8F%A3/"/>
<category term="探讨" scheme="http://inmyai.com/tags/%E6%8E%A2%E8%AE%A8/"/>
</entry>
<entry>
<title>入门Java:Clone(克隆)</title>
<link href="http://inmyai.com/2018/05/23/%E5%85%A5%E9%97%A8Java-Clone-%E5%85%8B%E9%9A%86/"/>
<id>http://inmyai.com/2018/05/23/入门Java-Clone-克隆/</id>
<published>2018-05-23T14:59:00.000Z</published>
<updated>2018-05-30T12:55:15.851Z</updated>
<content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>有时候,我们由于一些奇怪的原因需要拷贝一个已经存在的对象,而JAVA正好提供了一种拷贝对象的机制,即clone(),不幸的是,这种拷贝机制还存在某些不足。</p><h3 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h3><h4 id="clone"><a href="#clone" class="headerlink" title="clone()"></a>clone()</h4><p>查看Object类的源码,其中就有一个clone()方法,<code>protected native Object clone() throws CloneNotSupportedException;</code> </p><h5 id="方法类型"><a href="#方法类型" class="headerlink" title="方法类型"></a>方法类型</h5><p>这是一个保护级别的方法,因此,只有2种方式可以访问。第一种是包内访问(即让自己的类处于和该方法所属类的相同包内,impossible!),另一种则是继承Object的类可以访问,这也是我们唯一的访问方式<br>这还是一个native(本地)方法, 至于<strong>native method</strong>,<code>A native method is a Java method whose implementation is provided by non-java code</code>,本地方法就是一种通过非JAVA语言实现的方法,例如C语言代码,且代码不不在<strong>JVM</strong>运行,具体内容参见未来的博客文章</p><h5 id="通用规定"><a href="#通用规定" class="headerlink" title="通用规定"></a>通用规定</h5><p>其注释提到,clone()必须遵守的三个通用约定: </p><ul><li>x.clone() != x</li><li>x.clone().getClass() == x.getClass()</li><li>x.clone().equals(x)</li></ul><p>但这些约定都不是绝对要求的,仅仅作为一个建议</p><h5 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h5><p>而当一个对象调用clone方法,如果该对象的类没有实现Cloneable接口,就会抛出受检异常<code>CloneNotSupportedException</code></p><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>举个不好的栗子<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">package clone;</span><br><span class="line"></span><br><span class="line">import java.util.Date;</span><br><span class="line"></span><br><span class="line">public class App implements Cloneable{</span><br><span class="line"></span><br><span class="line"> private Date createTime;</span><br><span class="line"></span><br><span class="line"> private Date getCreateTime() {</span><br><span class="line"> return createTime;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> private void setCreateTime(Date createTime) {</span><br><span class="line"> this.createTime = createTime;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public App(Date createTime) {</span><br><span class="line"> this.createTime = createTime;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public App clone() {</span><br><span class="line"> try {</span><br><span class="line"> return (App)super.clone();</span><br><span class="line"> } catch (CloneNotSupportedException e) {</span><br><span class="line"> throw new AssertionError();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public String toString() {</span><br><span class="line"> return "App{" +</span><br><span class="line"> "createTime=" + createTime +</span><br><span class="line"> '}';</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> App app = new App(new Date());</span><br><span class="line"> App cloneApp = app.clone();</span><br><span class="line"> System.out.println(cloneApp.getCreateTime());</span><br><span class="line"> Date createTime = app.getCreateTime();</span><br><span class="line"> createTime.setTime(1000);</span><br><span class="line"> System.out.println(cloneApp.getCreateTime());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Tue May 29 23:43:08 CST 2018</span><br><span class="line">Thu Jan 01 08:00:01 CST 1970</span><br></pre></td></tr></table></figure></p><p>首先,我们需要覆盖clone(),然后借用Object自带的clone()方法,即super.clone() </p><p>至于返回对象为App,这是从JAVA 1.5发行版本后引入<strong>covariant return type</strong>作为泛型,简单的来说,就是可覆盖方法的返回类型可以是被覆盖方法的返回类型的子类型(本例中,可以返回Object的所有子类型)</p><p>当然也可以返回Object,但是一条来自<strong>Effective Java</strong>中的原则<code>永远不要让客户去做任何类库能够替客户完成的事情</code>,因此我们应该尽可能地减轻客户的压力,直接返回所需要的类型</p><p>通过上述的输出结果,可以知道Object自带的clone(),仅仅为我们进行了<strong>Shadow Copy(浅拷贝)</strong> ,这也就解释了为什么我们需要自己来实现clone()。本例中,对于克隆对象中中非基本类型的域(createTime),将会引用原始对象中的域,即原始对象的<code>createTime</code>一旦修改,克隆对象也会跟着改变,这显然不是一个理想中的克隆对象。正确的做法是,对于非基本类型的域,需要手动地构建实例,进行所谓的<strong>Deep Copy(深拷贝)</strong> ,修改后的clone()方法如下<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public App clone() {</span><br><span class="line"> try {</span><br><span class="line"> App app = (App) super.clone();</span><br><span class="line"> Date createTime = new Date(this.createTime.getTime());</span><br><span class="line"> app.setCreateTime(createTime);</span><br><span class="line"> return app;</span><br><span class="line"> } catch (CloneNotSupportedException e) {</span><br><span class="line"> throw new AssertionError();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Output<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Wed May 30 20:01:06 CST 2018</span><br><span class="line">Wed May 30 20:01:06 CST 2018</span><br></pre></td></tr></table></figure></p><p>此时,克隆对象不再随着原对象的改变而改变 </p><h3 id="缺陷"><a href="#缺陷" class="headerlink" title="缺陷"></a>缺陷</h3><h4 id="final-field"><a href="#final-field" class="headerlink" title="final field"></a>final field</h4><p>当原对象中存在引用可变对象的final域,克隆机制将会崩溃。因为当我们进行深拷贝时,我们无法对Object克隆出来后的对象(即已经完成构造的对象)分配其final域,<strong>final域只能在声明或者构造器中分配值域</strong>,将<code>createTime</code>改为final,即<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">private final Date createTime;</span><br></pre></td></tr></table></figure></p><p>则<code>setCreateTime()</code>方法将会报错,因此我们就无法进行深度拷贝</p><h3 id="实现机制"><a href="#实现机制" class="headerlink" title="实现机制"></a>实现机制</h3><p>为了通过clone()拷贝,我们必须为类实现Cloneable接口,否则将会抛出受检异常<code>CloneNotSupportedException</code>。通常接口表明该类的api,而clone()接口的作用却是改变Object中clone的作用,参见Cloneable接口的源码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">* A class implements the <code>Cloneable</code> interface to</span><br><span class="line">* indicate to the {@link java.lang.Object#clone()} method that it</span><br><span class="line">* is legal for that method to make a</span><br><span class="line">* field-for-field copy of instances of that class.</span><br></pre></td></tr></table></figure></p><h4 id="非同步"><a href="#非同步" class="headerlink" title="非同步"></a>非同步</h4><p>Object中的clone()没有同步,如果要设计线程安全的类,就必须编写同步的clone()方法来调用super.clone()</p><h3 id="替代方案"><a href="#替代方案" class="headerlink" title="替代方案"></a>替代方案</h3><h4 id="拷贝构造-Copy-Constructors"><a href="#拷贝构造-Copy-Constructors" class="headerlink" title="拷贝构造(Copy Constructors)"></a>拷贝构造(Copy Constructors)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public App(App originalApp) {</span><br><span class="line"> Date originalTime = originalApp.getCreateTime();</span><br><span class="line"> this.createTime = new Date(originalTime.getTime());</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>仅仅是一个普通的构造器,传入需要拷贝的对象,然后自己实现拷贝<br>优点是:不需要实现接口,不需要处理受检异常</p><h4 id="静态工厂-Static-Factory"><a href="#静态工厂-Static-Factory" class="headerlink" title="静态工厂(Static Factory)"></a>静态工厂(Static Factory)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">public static App copyApp(App originalApp) {</span><br><span class="line"> Date originalTime = originalApp.getCreateTime();</span><br><span class="line"> App app = new App(new Date(originalTime.getTime()));</span><br><span class="line"> return app;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>静态工厂和拷贝构造基本相似,差别在于这是一个静态方法,而拷贝构造是一个构造器。其也具有拷贝构造的优点,但同时还有<strong>拥有自定义的方法名</strong>,<strong>可以返回子类型</strong>等等好处,具体参见未来的博客文章</p>]]></content>
<summary type="html">
<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>有时候,我们由于一些奇怪的原因需要拷贝一个已经存在的对象,而JAVA正好提供了一种拷贝对象的机制,即clone(),不幸的是,这种拷贝机制还
</summary>
<category term="Java" scheme="http://inmyai.com/categories/Java/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Clone" scheme="http://inmyai.com/tags/Clone/"/>
</entry>
<entry>
<title>入门Sql:Normal Form(范式)</title>
<link href="http://inmyai.com/2018/05/14/%E5%85%A5%E9%97%A8Sql-Normal-Form-%E8%8C%83%E5%BC%8F/"/>
<id>http://inmyai.com/2018/05/14/入门Sql-Normal-Form-范式/</id>
<published>2018-05-14T15:47:00.000Z</published>
<updated>2018-05-23T15:00:25.937Z</updated>
<content type="html"><![CDATA[<h3 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h3><p>学校的数据库书关于范式的定义有些杂乱,用户体验不佳。因此,博主从墙外搬了几块砖头进来,以此体验原滋原味的Normal Form</p><h3 id="First-Normal-Form"><a href="#First-Normal-Form" class="headerlink" title="First Normal Form"></a>First Normal Form</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><p>A database is in first normal form if it satisfies the following conditions:</p><ul><li>Contains only atomic values</li><li>There are no repeating groups</li></ul><p>An atomic value is a value that cannot be divided. For example, in the table shown below, the values in the [Color] column in the first row can be divided into “red” and “green”, hence [TABLE_PRODUCT] is not in 1NF.</p><p>A repeating group means that a table contains two or more columns that are closely related. For example, a table that records data on a book and its author(s) with the following columns: [Book ID], [Author 1], [Author 2], [Author 3] is not in 1NF because [Author 1], [Author 2], and [Author 3] are all repeating the same attribute.</p><h4 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h4><p>How do we bring an unnormalized table into first normal form? Consider the following example:</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-19/25240910.jpg" alt=""></p><p>This table is not in first normal form because the [Color] column can contain multiple values. For example, the first row includes values “red” and “green.”</p><p>To bring this table to first normal form, we split the table into two tables and now we have the resulting tables:</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-19/42857496.jpg" alt=""></p><p>Now first normal form is satisfied, as the columns on each table all hold just one value.</p><h3 id="Second-Normal-Form"><a href="#Second-Normal-Form" class="headerlink" title="Second Normal Form"></a>Second Normal Form</h3><h4 id="定义-1"><a href="#定义-1" class="headerlink" title="定义"></a>定义</h4><p>A database is in second normal form if it satisfies the following conditions:</p><ul><li>It is in first normal form</li><li>All non-key attributes are fully functional dependent on the primary key</li></ul><p>In a table, if attribute B is functionally dependent on A, but is not functionally dependent on a proper subset of A, then B is considered fully functional dependent on A. Hence, in a 2NF table, all non-key attributes cannot be dependent on a subset of the primary key. Note that if the primary key is not a composite key, all non-key attributes are always fully functional dependent on the primary key. A table that is in 1st normal form and contains only a single key as the primary key is automatically in 2nd normal form.</p><h4 id="示例-1"><a href="#示例-1" class="headerlink" title="示例"></a>示例</h4><p>Consider the following example:</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-19/62178967.jpg" alt=""></p><p>This table has a composite primary key [Customer ID, Store ID]. The non-key attribute is [Purchase Location]. In this case, [Purchase Location] only depends on [Store ID], which is only part of the primary key. Therefore, this table does not satisfy second normal form.</p><p>To bring this table to second normal form, we break the table into two tables, and now we have the following:</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-19/54371245.jpg" alt=""></p><p>What we have done is to remove the partial functional dependency that we initially had. Now, in the table [TABLE_STORE], the column [Purchase Location] is fully dependent on the primary key of that table, which is [Store ID].</p><h3 id="Third-Normal-Form"><a href="#Third-Normal-Form" class="headerlink" title="Third Normal Form"></a>Third Normal Form</h3><h4 id="定义-2"><a href="#定义-2" class="headerlink" title="定义"></a>定义</h4><p>A database is in third normal form if it satisfies the following conditions:</p><ul><li>It is in second normal form</li><li>There is no transitive functional dependency</li></ul><p>By transitive functional dependency, we mean we have the following relationships in the table: A is functionally dependent on B, and B is functionally dependent on C. In this case, C is transitively dependent on A via B.</p><h4 id="示例-2"><a href="#示例-2" class="headerlink" title="示例"></a>示例</h4><p>Consider the following example:</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-19/20320369.jpg" alt=""></p><p>In the table able, [Book ID] determines [Genre ID], and [Genre ID] determines [Genre Type]. Therefore, [Book ID] determines [Genre Type] via [Genre ID] and we have transitive functional dependency, and this structure does not satisfy third normal form.</p><p>To bring this table to third normal form, we split the table into two as follows:</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-19/30052179.jpg" alt=""></p><p>Now all non-key attributes are fully functional dependent only on the primary key. In [TABLE_BOOK], both [Genre ID] and [Price] are only dependent on [Book ID]. In [TABLE_GENRE], [Genre Type] is only dependent on [Genre ID].</p><h3 id="来源"><a href="#来源" class="headerlink" title="来源"></a>来源</h3><p><a href="https://www.1keydata.com/database-normalization/" target="_blank" rel="noopener">https://www.1keydata.com/database-normalization/</a></p>]]></content>
<summary type="html">
<h3 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h3><p>学校的数据库书关于范式的定义有些杂乱,用户体验不佳。因此,博主从墙外搬了几块砖头进来,以此体验原滋原味的Normal Form</p>
<h
</summary>
<category term="Sql" scheme="http://inmyai.com/categories/Sql/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Normal Form" scheme="http://inmyai.com/tags/Normal-Form/"/>
</entry>
<entry>
<title>入门Java:Bounded Wildcard Type(有限制通配符类型)</title>
<link href="http://inmyai.com/2018/05/13/%E5%85%A5%E9%97%A8Java-Bounded-Wildcard-Type-%E6%9C%89%E9%99%90%E5%88%B6%E9%80%9A%E9%85%8D%E7%AC%A6%E7%B1%BB%E5%9E%8B/"/>
<id>http://inmyai.com/2018/05/13/入门Java-Bounded-Wildcard-Type-有限制通配符类型/</id>
<published>2018-05-13T14:59:00.000Z</published>
<updated>2018-05-19T02:51:19.952Z</updated>
<content type="html"><![CDATA[<h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>Bounded Wildcard Type 相对于 UnBounded Wildcard Type 多了一个对于类型参数的限制,即提供了一种有限制的”灵活”。门下有两个徒弟,一个名为Upper Bounded Wildcards(上层限制通配符),而另一个名为Lower Bounded Wildcards(下层限制通配符)</p><ul><li>Upper Bounded Wildcards 上层限制通配符,即限制了?的最高父类级别。用法:<code>? extends A</code>,则说明parameter type(类型参数)只能为A的子类型或者A本身</li><li>Lower Bounded Wildcards 下层限制通配符,与楼上的相反,即限制了?的最低子类级别。用法:<code>? super A</code>,则说明parameter type只能为A的父类型或者A本身</li></ul><h3 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h3><h3 id="Start"><a href="#Start" class="headerlink" title="Start"></a>Start</h3><p>某些情况下,我们需要编写关于泛型的方法(例如集合)。例如,一个方法的参数是List<Number>,但是该方法的灵活度不高,由于泛型不支持<strong>子类型</strong>。因此,我们只能传入List<Number>对象,而如果使用有限制通配符类型,则可以传入List<Integer>等对象,只要参数类型为Number的子类型即可。 </p><p>至于为什么不选择无限制通配符类型:</p><ul><li>相当于绕过泛型检查,未知的类型使得编译器无法在编译期间进行类型的检查,类型不安全</li></ul><p>关于<strong>子类型</strong>:<br>A是B的子类型,但List<A>不是List<B>的子类型,则说明泛型不支持<strong>子类型</strong></p><h4 id="Upper-Bounded-Wildcards"><a href="#Upper-Bounded-Wildcards" class="headerlink" title="Upper Bounded Wildcards"></a>Upper Bounded Wildcards</h4><p>编写关于读取泛型中的数据的方法(查询…)<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class App {</span><br><span class="line"></span><br><span class="line"> public static void read(List<? extends Number> numbers) {</span><br><span class="line"> for (Number number : numbers) {</span><br><span class="line"> System.out.println(number);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> List<Integer> integerList = Arrays.asList(1, 2, 3);</span><br><span class="line"> List<Double> doubleList = Arrays.asList(1.2, 1.3);</span><br><span class="line"> read(integerList);</span><br><span class="line"> read(doubleList);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">1.2</span><br><span class="line">1.3</span><br></pre></td></tr></table></figure></p><p>由于上层限制通配符类型List<? extends Number>支持<strong>子类型</strong>,可传入类型参数为Number或者Number子类型(如Integer,Double,Float)的泛型<br>通过以上方法,则可以遍历参数类型为Number或Number子类型的集合</p><p>选择extends(或者为什么类型参数一定要是”A”的子类型)的思考:</p><p>首先变量只能指向类型为该变量类型的子类型或者相同类型的对象,emmmmm有点复杂,举个栗子:<br>假设A是B的父类</p><ul><li><code>A a = new B() //打勾,因为B是A子类型</code></li><li><code>A a = new A() //打勾,因为A就是A</code></li><li><code>B b = new A() //打叉,因为A不是B的子类型</code></li></ul><p>而在遍历泛型中数据的时候,我们需要使用一个变量指向泛型数据。相当于进行读取的操作,对应的样例代码为<code>A a = b</code>,其中b为泛型中的数据。因此,为了灵活性,或者为了过编译,b的类型应该为A的子类型或者就是A,所以我们选择了<strong>extends</strong></p><h4 id="Lower-Bounded-Wildcards"><a href="#Lower-Bounded-Wildcards" class="headerlink" title="Lower Bounded Wildcards"></a>Lower Bounded Wildcards</h4><p>编写关于修改泛型中数据的方法(增加,删除…)<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class App {</span><br><span class="line"></span><br><span class="line"> public static void addOne(List<? super Integer> numbers) {</span><br><span class="line"> numbers.add(1);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> List<Integer> integerList = new ArrayList<>();</span><br><span class="line"> addOne(integerList);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>由于下层限制通配符类型List<? super Integer>同样支持<strong>子类型</strong>,可传入类型参数为Integer或者Integer父类型(如Integer,Number,Object)的泛型 </p><p>选择super的思考: </p><p>其实与上层限制通配符是一样的道理,这时候需要逆向思维。如在执行add方法的时候,类型参数?是作为消费者的角色,add方法里面应该有类似的代码<code>A a = b</code>。此时,b是我们新增的数据,而a才是泛型数据。同样的道理,为了过审。。。。。。我们选择了super</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul><li>记忆规律:<br>1.”effective java”中提及的PECS,即<strong>producer-extends,consumer-super</strong>,参数化类型作为生产者,则使用extends关键字;参数化类型作为消费者,则使用super关键字<br>2.个人记忆:如果只是想观摩泛型数据,则使用extends,而如果想给泛型数据动动手脚,则使用super</li><li>类型参数的限制图解:<br><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-17/71285439.jpg" alt=""></li></ul>]]></content>
<summary type="html">
<h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>Bounded Wildcard Type 相对于 UnBounded Wildcard Type 多了一个对于类型参数的限制,即提供了一种
</summary>
<category term="Java" scheme="http://inmyai.com/categories/Java/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Bounded Wildcard Type" scheme="http://inmyai.com/tags/Bounded-Wildcard-Type/"/>
</entry>
<entry>
<title>入门Java:Declared vs Actual Type(声明类型对比实际类型)</title>
<link href="http://inmyai.com/2018/05/09/%E5%85%A5%E9%97%A8Java-Declared-vs-Actual-Type-%E7%94%B3%E6%98%8E%E7%B1%BB%E5%9E%8B%E5%AF%B9%E6%AF%94%E5%AE%9E%E9%99%85%E7%B1%BB%E5%9E%8B/"/>
<id>http://inmyai.com/2018/05/09/入门Java-Declared-vs-Actual-Type-申明类型对比实际类型/</id>
<published>2018-05-09T15:15:00.000Z</published>
<updated>2018-05-19T02:51:04.316Z</updated>
<content type="html"><![CDATA[<h2 id="动态和静态"><a href="#动态和静态" class="headerlink" title="动态和静态"></a>动态和静态</h2><p>动态 == 事物本身的状态是可以随着外部因素而改变。一般指的就是程序的运行期间。例如,子类重写父类的方法,执行方法时,对象的类型决定执行子类或是父类的方法,而对象的类型需要在运行期间才能确定。 </p><p>静态 == 事物本身的状态一直保持不变。一般指的就是程序的编译期间。例如,类的final方法即是静态的,无法被覆盖,对象执行该方法时具有确定性。</p><p>为了更好的区分和识别,可用<code>runtime</code>指代动态,<code>compile-time</code>指代静态。</p><h2 id="声明类型-vs-实际类型"><a href="#声明类型-vs-实际类型" class="headerlink" title="声明类型 vs 实际类型"></a>声明类型 vs 实际类型</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>每一种变量都有两种类型,一个是声明类型,而另一个就是实际类型。 </p><ul><li>Declared Type:<br>as per the program syntax(由语法制作<br>This is static(静态的,即在<strong>compile-time</strong>确定</li><li>Actual Type:<br>as per its creation(由上帝制作?程序员<br>This is dynamic(动态的,即在<strong>runtime</strong>确定</li></ul><p>举个栗子:<br>首先定义以下三个类:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public class Plant {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">//植物类</span><br></pre></td></tr></table></figure></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public class Apple extends Plant{</span><br><span class="line"></span><br><span class="line"> public void hello() {</span><br><span class="line"> System.out.println("i am an apple");</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">//苹果类,继承自植物类</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class RedApple extends Apple{</span><br><span class="line"></span><br><span class="line"> public void hello() {</span><br><span class="line"> System.out.println("i am a redApple");</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void show() {</span><br><span class="line"> System.out.println("a redApple");</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">//红苹果类,继承自苹果类</span><br></pre></td></tr></table></figure><p>主函数:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Apple apple = new RedApple();</span><br></pre></td></tr></table></figure></p><p>apple的申明类型为Apple,但是实际类型是RedApple。<br>实际上,<strong>apple变量引用的究竟是Apple对象还是RedApple对象</strong>,编译器是无法知道的,只能等到<code>runtime</code>才可以确定。而<strong>apple变量的申明类型Apple</strong>是确定的,这辈子都不可能更改声明对象。因此,<code>declared type</code>属于<code>static</code>,而<code>actual type</code>属于<code>dynamic</code></p><h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ul><li>声明类型决定了方法的范围<br>尽管apple的实际类型是RedApple,但它是被禁止使用RedApple专属的 show()方法。试想:如果重新分配apple给Apple对象,然后执行RedApple专属方法,那么程序将会瞬间崩溃,而编译器又无法确定对象类型(只能在运行期间确定)。因此,这一规定也合乎情理。</li><li><p>实际类型决定了方法的版本<br>当调用apple的hello()方法(被RedApple overridden),那么它究竟是执行RedApple版本的方法,还是Apple版本的方法?<br>示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Apple apple = new RedApple();</span><br><span class="line">apple.hello();</span><br></pre></td></tr></table></figure><p>Output:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">i am a redApple</span><br></pre></td></tr></table></figure></li></ul><p>方法的执行是在运行期间,而同时运行期间能够确定变量所引用的对象的类型。这一行为称为<code>Dynamic Dispatch</code>。因此,方法的版本取决于实际类型。</p><h3 id="大坑"><a href="#大坑" class="headerlink" title="大坑"></a>大坑</h3><ul><li><p>我们经常分配父类变量给子类对象。如:<code>Apple apple = new RedApple();</code>。而规定中有这么一条:只能分配申明类型为X的变量给申明类型为Y(Y为X的子类型)的变量。因此,如果代码换成如下: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Plant plant = new RedApple();</span><br><span class="line">Apple apple = plant;</span><br></pre></td></tr></table></figure><p>乍一看,好像是正确的,然而抛出警告<code>Incompatible types</code>。不兼容的类型!事实上,背锅的编译器只能假设plant的实际类型就是申明类型Plant,为保护世界和平,不允许这种情况发生,只能依靠声明类型之间的关系进行分配。<br>但是!程序员到底还是上帝一般的存在,通过强制转换,<code>Apple apple = (RedApple) plant;</code>完美进行分配。</p></li></ul>]]></content>
<summary type="html">
<h2 id="动态和静态"><a href="#动态和静态" class="headerlink" title="动态和静态"></a>动态和静态</h2><p>动态 == 事物本身的状态是可以随着外部因素而改变。一般指的就是程序的运行期间。例如,子类重写父类的方法,执行方法时
</summary>
<category term="Java" scheme="http://inmyai.com/categories/Java/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Declared Type" scheme="http://inmyai.com/tags/Declared-Type/"/>
<category term="Actual Type" scheme="http://inmyai.com/tags/Actual-Type/"/>
</entry>
<entry>
<title>入门Java:Reference(引用)</title>
<link href="http://inmyai.com/2018/05/02/%E5%85%A5%E9%97%A8Java-Reference/"/>
<id>http://inmyai.com/2018/05/02/入门Java-Reference/</id>
<published>2018-05-02T15:23:00.000Z</published>
<updated>2018-05-19T02:50:48.068Z</updated>
<content type="html"><![CDATA[<h2 id="引用类型"><a href="#引用类型" class="headerlink" title="引用类型"></a>引用类型</h2><ul><li>strong reference(强引用)</li><li>weak reference(弱引用)</li><li>soft reference(软引用)</li><li>phantom reference(虚引用/幽灵引用)</li></ul><h2 id="Strong-Reference"><a href="#Strong-Reference" class="headerlink" title="Strong Reference"></a>Strong Reference</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>强引用,坚强的引用,233<br>有多强?强到GC(Garbage Collection)从不敢靠近它<br>如何声明这一最强的引用?(#゚Д゚)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String strongReference = new String("strong");</span><br></pre></td></tr></table></figure></p><p>实际上,这是我们平时编程所使用的。任何在内存中具有强引用的对象(不是变量!)都不会被GC处理掉。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">strongReference = null;</span><br></pre></td></tr></table></figure></p><p>执行上句之后,原本的”strong”对象将会缺少有效的引用指向它,则最有可能先被处理掉,如果GC想要的话。<br>过程:<br><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-3/98766925.jpg" alt="强引用过程图"></p><h3 id="缺陷"><a href="#缺陷" class="headerlink" title="缺陷"></a>缺陷</h3><p>当强引用过强的时候,也会出现很多麻烦。<br>假设以下场景,GUI编程的时候,经常需要从文件中读取一张非常大的图片资源,每一次读取都将会耗费巨大的时间。<br>因此,可以设计一个图片缓冲区,里面保存着指向内存中图片的引用。但同时,这个引用或者称为强引用将会使得图片定居在内存中,而你就需要进行判断,当图片不再使用时,将它从缓存区中移除,否则<code>memory leak</code>这头怪物随时可能出现。<br>这时,你也就开始你的人工GC之旅。解决方法↓↓↓</p><h2 id="Weak-Reference"><a href="#Weak-Reference" class="headerlink" title="Weak Reference"></a>Weak Reference</h2><h3 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h3><p>弱引用,多弱?一旦GC饿的时候,分分钟直接抹杀该对象(一个只有弱引用相依为命的对象),然后从内存中永远消失。<br>测试手册:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Date now = new Date();</span><br><span class="line">WeakReference<Date> weakReference = new WeakReference<>(now);</span><br><span class="line">System.out.println("isNull:"+(weakReference.get()==null));</span><br><span class="line">now = null;</span><br><span class="line">System.gc();</span><br><span class="line">System.out.println("isNull:"+(weakReference.get()==null));</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">isNull:false</span><br><span class="line">isNull:true</span><br></pre></td></tr></table></figure></p><p>大致的流程图:<br><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-5/31727949.jpg" alt="弱引用流程图"><br>简单的讲解:<br>1.now变量指向Date()对象,weakReference变量指向WeakReference()对象,且WeakReference对象内部保存着Date()对象的引用,可以通过get()方式获取<br>2.now变量指向null,则Date()对象成功入单,只有一个弱引用<br>3.System.gc();提前执行gc过程,并尽可能地促进GC清扫垃圾,实际上可能不进行清扫(还是得看心情,看内存是否够用)<br>参考源码注释:<code>Calling the gc method suggests that Java Virtual Machine expend effort toward recycling unused objects</code><br>4.原先的Date对象离开内存(很有可能)</p><h3 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h3><p>一般而言,Weak Reference 需要配合 <code>weakHashMap</code> 服用。<br>weakHashMap??打开源码:<code>public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V></code>,其继承了抽象Map,且实现Map接口。事实上与HashMap的用法一致,可直接当做HashMap。<br>其主要的特点是:</p><ul><li>键值对继承WeakReference</li><li>当key不在使用时,对应的value将自动从map释放,并被gc绝对清除(不用看心情了) </li></ul><p>上文中提到了图片缓冲区问题,而解决的方法即是通过weakHashMap实现一个高效的image cache。但image不在使用时,可以将其key指向null,则image对象自动从map移除,且被gc清除。利用这一自动清除机制,也就让我们解脱人工gc之旅。<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">WeakHashMap<String, ImageIcon> imageCache = new WeakHashMap<>();</span><br><span class="line">ImageIcon bigImage = new ImageIcon();</span><br><span class="line">String bigImageName = new String("apple");</span><br><span class="line">imageCache.put(bigImageName, bigImage);</span><br><span class="line">System.out.println("isNull:" + (imageCache.get("apple") == null));</span><br><span class="line">// when the image is no longer needed in memory</span><br><span class="line">bigImageName = null;</span><br><span class="line">System.gc();</span><br><span class="line">System.out.println("isNull:" + (imageCache.get("apple") == null));</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">isNull:false</span><br><span class="line">isNull:true</span><br></pre></td></tr></table></figure></p><h2 id="Soft-Reference"><a href="#Soft-Reference" class="headerlink" title="Soft Reference"></a>Soft Reference</h2><h3 id="概念:"><a href="#概念:" class="headerlink" title="概念:"></a>概念:</h3><p>软引用,比弱引用强一些,是个软妹子。她会乞求gc实在没有任何选择的情况下,再去清除她的对象,如内存不够用,且唯一可以释放的是她的对象。<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Date now = new Date();</span><br><span class="line">SoftReference<Date> softReference = new SoftReference<>(now);</span><br><span class="line">now = null;</span><br><span class="line">System.gc();</span><br><span class="line">System.out.println("isNull:"+(softReference.get()==null));</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">isNull:false</span><br></pre></td></tr></table></figure></p><p>可以看出,软引用的对象并没有立刻被清除。只要jvm不需要内存,那么软引用的对象就会一直存在。</p><h2 id="Phantom-Reference"><a href="#Phantom-Reference" class="headerlink" title="Phantom Reference"></a>Phantom Reference</h2><h3 id="概念-2"><a href="#概念-2" class="headerlink" title="概念"></a>概念</h3><p>幽灵引用?虚幻引用?这是所有引用中名字最装逼的。。。<br>永远无法取回幽灵引用所指向的对象,因此其get()永远返回null<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Date now = new Date();</span><br><span class="line">ReferenceQueue<Date> referenceQueue = new ReferenceQueue<>();</span><br><span class="line">PhantomReference<Date> phantomReference = new PhantomReference<>(now, referenceQueue);</span><br><span class="line">now = null;</span><br><span class="line">System.out.println("isNull:"+(phantomReference.get()==null));</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">isNull:true</span><br></pre></td></tr></table></figure></p><h3 id="应用-1"><a href="#应用-1" class="headerlink" title="应用"></a>应用</h3><p>1.精确控制对象何时从内存中消失。<br>2.避免finalize()两大缺陷: </p><ul><li>无法保证对象真正被GC清除,并且什么时候被清除</li><li>占用的资源多,降低应用程序的速度 </li></ul><h2 id="引用强度"><a href="#引用强度" class="headerlink" title="引用强度"></a>引用强度</h2><p>Strong Reference>Soft Reference>Weak Reference>Phantom Reference</p>]]></content>
<summary type="html">
<h2 id="引用类型"><a href="#引用类型" class="headerlink" title="引用类型"></a>引用类型</h2><ul>
<li>strong reference(强引用)</li>
<li>weak reference(弱引用)</li>
</summary>
<category term="Java" scheme="http://inmyai.com/categories/Java/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Reference" scheme="http://inmyai.com/tags/Reference/"/>
</entry>
<entry>
<title>入门Java:Unbounded Wildcard Type(无限制通配符类型)</title>
<link href="http://inmyai.com/2018/05/02/%E5%85%A5%E9%97%A8Java-Unbounded-Wildcard-Type-%E6%97%A0%E9%99%90%E5%88%B6%E9%80%9A%E9%85%8D%E7%AC%A6%E7%B1%BB%E5%9E%8B/"/>
<id>http://inmyai.com/2018/05/02/入门Java-Unbounded-Wildcard-Type-无限制通配符类型/</id>
<published>2018-05-02T03:36:00.000Z</published>
<updated>2018-05-19T02:50:23.079Z</updated>
<content type="html"><![CDATA[<h2 id="官方定义"><a href="#官方定义" class="headerlink" title="官方定义"></a>官方定义</h2><p>The unbounded wildcard type is specified using the wildcard character (?)<br>无限制通配符类型通过使用通配符字母(?)来明确指定</p><h2 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h2><ul><li><p>支持子类型化(subtype),例如,对于任意具体类型A,List<A>是List<?>的子类型。而对比于泛型,不支持子类型化,List<A>不是List<Object>的子类型。<br>因此,无限制通配符类型的变量可以引用具体类型A的泛型。<br>示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List<Integer> integerList = new ArrayList<>();</span><br><span class="line">List<?> test = integerList; //打勾</span><br><span class="line">List<Object> test2 = integerList; //Error:Incompatible</span><br></pre></td></tr></table></figure></li><li><p>不能insert除null以外的元素,由于<code>?</code>是未知类型,不能分配任何除null以外的值<br>示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List<?> test = new ArrayList<String>();</span><br><span class="line">test.add("a");</span><br><span class="line">Error:add (capture<?>) in List cannot be applied to (java.lang.String)</span><br></pre></td></tr></table></figure></li></ul><h2 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h2><h3 id="定义一个能够通过object类实现的方法"><a href="#定义一个能够通过object类实现的方法" class="headerlink" title="定义一个能够通过object类实现的方法"></a>定义一个能够通过object类实现的方法</h3><p>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">public class App {</span><br><span class="line"> </span><br><span class="line"> public static void show(List<Object> objectList) {</span><br><span class="line"> for (Object object : objectList) {</span><br><span class="line"> System.out.println("object->>"+object);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> List<String> stringList = Arrays.asList("a","b","c");</span><br><span class="line"> show(stringList);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Error:show (java.util.List<java.lang.Object>) in App cannot be applied<br>to (java.util.List<java.lang.String>)<br>由于泛型不支持子类型化,它不能指向List<String>,List<Integer>等等,只能指向List<Object>。而无限制通配符类型支持子类型化,修改show方法<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">public static void show(List<?> objectList) {</span><br><span class="line"> for (Object object : objectList) {</span><br><span class="line"> System.out.println("object->>"+object);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">object->>a</span><br><span class="line">object->>b</span><br><span class="line">object->>c</span><br></pre></td></tr></table></figure></p><h3 id="使用泛型类中不依赖类型参数的方法"><a href="#使用泛型类中不依赖类型参数的方法" class="headerlink" title="使用泛型类中不依赖类型参数的方法"></a>使用泛型类中不依赖类型参数的方法</h3><p>首先定义一个泛型苹果,包括一个颜色域,可以assign任何对象来表示苹果的颜色,例如,<code>Apple<String> apple = new Apple<>("red");</code>或者<code>Apple<Color> apple = new Apple<>(Color.BLACK);</code>。其中,包括一个改变颜色的方法,需要依赖于类型参数,另一个显示颜色的方法,不需要依赖于类型参数。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">public class Apple<T> {</span><br><span class="line"></span><br><span class="line"> private T color;</span><br><span class="line"></span><br><span class="line"> public Apple(T color) {</span><br><span class="line"> this.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void change(T color) {</span><br><span class="line"> this.color = color;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void show() {</span><br><span class="line"> System.out.println(color);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>接着,定义2个通用的方法,1.显示泛型苹果的颜色,2.改变泛型苹果的颜色<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">public class App {</span><br><span class="line"></span><br><span class="line"> public static void printColor(Apple<?> unboundedApple) {</span><br><span class="line"> unboundedApple.show();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void changeColor(Apple<?> unboundedApple,String color) {</span><br><span class="line"> unboundedApple.change(color);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> Apple<Color> apple = new Apple<>(Color.BLACK);</span><br><span class="line"> Apple<String> apple2 = new Apple<>("blue");</span><br><span class="line"> printColor(apple);</span><br><span class="line"> printColor(apple2);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>编译时,changeColor()抛出异常<code>change(capture<?>) in Apple cannot be appliedto (java.lang.String)</code>这是由于unboundedApple是未知类型所引发的。注释changeColor()后再次运行。<br>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">java.awt.Color[r=0,g=0,b=0]</span><br><span class="line">blue</span><br></pre></td></tr></table></figure></p><p>因此,可以使用<code>Unbounded Wildcard Type</code>指向具体的泛型类,并调用该泛型类的任何不依赖于类型参数的方法</p>]]></content>
<summary type="html">
<h2 id="官方定义"><a href="#官方定义" class="headerlink" title="官方定义"></a>官方定义</h2><p>The unbounded wildcard type is specified using the wildcard ch
</summary>
<category term="Java" scheme="http://inmyai.com/categories/Java/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Unbounded Wildcard Type" scheme="http://inmyai.com/tags/Unbounded-Wildcard-Type/"/>
</entry>
<entry>
<title>入门Java:Raw Type(原生态类型)</title>
<link href="http://inmyai.com/2018/05/01/%E5%85%A5%E9%97%A8Java-Row-Types-%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B/"/>
<id>http://inmyai.com/2018/05/01/入门Java-Row-Types-原生类型/</id>
<published>2018-05-01T15:30:00.000Z</published>
<updated>2018-05-19T02:50:08.706Z</updated>
<content type="html"><![CDATA[<h2 id="官方定义"><a href="#官方定义" class="headerlink" title="官方定义"></a>官方定义</h2><p>A raw type is the name of a generic class or interface without any type of arguements<br>生的类型?还没煮熟?原生态类型是没有任何类型参数的泛型类或泛型接口的名字</p><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List rawList = new ArrayList();</span><br></pre></td></tr></table></figure><ul><li>List = 没有类型参数的泛型接口</li><li>ArrayList = 没有类型参数的泛型类</li><li>两者都是原生态类型</li><li>注意:非泛型的类或泛型接口都不是原生态类型</li></ul><h2 id="存在的意义"><a href="#存在的意义" class="headerlink" title="存在的意义"></a>存在的意义</h2><ul><li>JAVA 1.5之前,没有泛型机制,只能编写原生态类型</li><li>为了向后兼容(Backward Compatibility),或者是移植兼容性(Migration Compatibility),现在仍然支持原生态类型。例如,可以assign一个类型参数给原生态类型</li></ul><h2 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h2><h3 id="类文字-class-literal"><a href="#类文字-class-literal" class="headerlink" title="类文字(class literal)"></a>类文字(class literal)</h3><p>类文字中必须使用原生态类型,规范不允许使用参数化类型。就是一个规定!例如,不能使用<code>List<String>.class</code>,而必须用<code>List.class</code>。可能就是为了简便吧。<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Class test = List<String>.class;</span><br><span class="line">ERROR:</span><br><span class="line"> Cannot select from parameterized type</span><br></pre></td></tr></table></figure></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class test = List.class; //打勾</span><br></pre></td></tr></table></figure><h3 id="实例-instance-操作符"><a href="#实例-instance-操作符" class="headerlink" title="实例(instance)操作符"></a>实例(instance)操作符</h3><p>禁止在参数化类型(parameterized type)上使用instanceof。这也是一个规定!<br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">List test = new ArrayList();</span><br><span class="line">if (test instanceof ArrayList<String>) {</span><br><span class="line"> System.out.println("bingo~");</span><br><span class="line">}</span><br><span class="line">ERROR:</span><br><span class="line"> Illegal generic type for instanceof</span><br></pre></td></tr></table></figure></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">List test = new ArrayList();</span><br><span class="line">if (test instanceof ArrayList) {</span><br><span class="line"> System.out.println("bingo~");</span><br><span class="line">}</span><br><span class="line">//打勾</span><br></pre></td></tr></table></figure><p>两者都是因为<strong>泛型信息在运行期间被erasure</strong>这一事实(来源自《Effective Java》)。既然被erasure,那么<code>List<String>.class</code> == <code>List.class</code>,为啥是非法的??有待考量,TODO:为啥非法。博主认为就应该只是一个规定的问题。 </p><p>较为合理的解释:type parameters 仅仅生存在编译期间,由于reflection本质上是一个运行期间的东西,无法识别type parameters</p><h2 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h2><h3 id="安全性"><a href="#安全性" class="headerlink" title="安全性"></a>安全性</h3><p>原生类型没有类型参数,导致编译器缺少足够的信息,绕过泛型检查,会引起<code>unchecked error</code>。例如,对原生态类型操作时,容易引发<code>ClassCastException</code><br>示例:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">public class App {</span><br><span class="line"></span><br><span class="line"> public void add(List list, Object object) {</span><br><span class="line"> list.add(object);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> List<Integer> integerList = new ArrayList<>();</span><br><span class="line"> new App().add(integerList,new Date());</span><br><span class="line"> Integer element = integerList.get(0);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p><code>add(List list, Object object)</code>能够通过编译,由于原生态类型没有<code>parameterized type</code>,因此,任何object都能够添加,但会引发编译警告<code>Unchecked call to 'add(E)' as a member of raw type 'java.util.List'</code>。<br>当尝试从<code>integerList</code>获取<code>element</code>时,将会付出忽略警告的代价,抛出<code>java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.Integer</code></p><h3 id="阅读性"><a href="#阅读性" class="headerlink" title="阅读性"></a>阅读性</h3><p>原生态类型没有<code>parameterized type</code>,无法直接从表面上看出这个类型所包含的具体信息。而对于泛型类,如<code>List<String></code>,可以简单的认为这是字符串列表。阅读性的丧失,将会导致代码的维护难度大大提高。</p>]]></content>
<summary type="html">
<h2 id="官方定义"><a href="#官方定义" class="headerlink" title="官方定义"></a>官方定义</h2><p>A raw type is the name of a generic class or interface without
</summary>
<category term="Java" scheme="http://inmyai.com/categories/Java/"/>
<category term="入门" scheme="http://inmyai.com/tags/%E5%85%A5%E9%97%A8/"/>
<category term="总结" scheme="http://inmyai.com/tags/%E6%80%BB%E7%BB%93/"/>
<category term="Raw Type" scheme="http://inmyai.com/tags/Raw-Type/"/>
</entry>
<entry>
<title>Hexo Admin Deploy扩展教程</title>
<link href="http://inmyai.com/2018/05/01/Hexo-Admin-Deploy%E6%AD%A3%E7%A1%AE%E6%89%93%E5%BC%80%E6%96%B9%E5%BC%8F/"/>
<id>http://inmyai.com/2018/05/01/Hexo-Admin-Deploy正确打开方式/</id>
<published>2018-05-01T12:52:00.000Z</published>
<updated>2018-05-02T13:50:18.053Z</updated>
<content type="html"><![CDATA[<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://github.com/jaredly/hexo-admin/issues/94" target="_blank" rel="noopener">hexo-admin/issues</a></p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>由于Windows的某种原因,依据网站的大部分教程,均会抛出<code>deploy Error: spawn UNKNOWN</code>异常。而GitHub上issues给出了相关解决方案,现在总结一下具体的过程(填坑</p><h2 id="填坑"><a href="#填坑" class="headerlink" title="填坑"></a>填坑</h2><ul><li><p>打开站点配置文件(<code>\xxxx.github.io\_config.yml</code>),在<code>admin</code>中加入<code>deployCommand: 'sh hexo-deploy.sh'</code>。示例:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">admin:</span><br><span class="line"> username: 看不见</span><br><span class="line"> password_hash: 看不见</span><br><span class="line"> secret: 看不见</span><br><span class="line"> deployCommand: 'sh hexo-deploy.sh'</span><br></pre></td></tr></table></figure></li><li><p>在根目录中(<code>\xxxx.github.io\</code>)新建<code>hexo-deploy.sh</code>文件,内容为:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo g -d</span><br></pre></td></tr></table></figure></li><li><p>打开deploy.js(<code>\xxxx.github.io\node_modules\hexo-admin\deploy.js</code>),将<code>var proc = spawn(command, [message], {detached: true});</code>更改为<code>var proc = spawn((process.platform === "win32" ? "hexo.cmd" : "hexo"), ['d', '-g']);</code><br>更改完后的代码:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">module.exports = function (command, message, done) {</span><br><span class="line"> done = once(done);</span><br><span class="line"> var proc = spawn((process.platform === "win32" ? "hexo.cmd" : "hexo"), ['d', '-g']);</span><br><span class="line"> var stdout = '';</span><br><span class="line"> var stderr = '';</span><br><span class="line"> proc.stdout.on('data', function(data){stdout += data.toString()})</span><br><span class="line"> proc.stderr.on('data', function(data){stderr += data.toString()})</span><br><span class="line"> proc.on('error', function(err) {</span><br><span class="line"> done(err, {stdout: stdout, stderr: stderr});</span><br><span class="line"> });</span><br><span class="line"> proc.on('close', function () {</span><br><span class="line"> done(null, {stdout: stdout, stderr: stderr});</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h2 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h2><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-5-1/52473923.jpg" alt="效果图"></p>]]></content>
<summary type="html">
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://github.com/jaredly/hexo-admin/issues/94" target="_bla
</summary>
<category term="博客" scheme="http://inmyai.com/categories/%E5%8D%9A%E5%AE%A2/"/>
<category term="Hexo" scheme="http://inmyai.com/tags/Hexo/"/>
<category term="教程" scheme="http://inmyai.com/tags/%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>NexT 底部logo栏更改教程</title>
<link href="http://inmyai.com/2018/05/01/%E5%BA%95%E9%83%A8logo%E6%A0%8F%E6%9B%B4%E6%94%B9%E6%95%99%E7%A8%8B/"/>
<id>http://inmyai.com/2018/05/01/底部logo栏更改教程/</id>
<published>2018-05-01T12:41:00.000Z</published>
<updated>2018-05-01T13:21:02.591Z</updated>
<content type="html"><![CDATA[<p>1.从 <a href="https://fontawesome.com/icons" target="_blank" rel="noopener">图标库</a> 中挑选一款图标。<br>2.修改主题配置文件(<code>\xxxx.github.io\themes\next\_config.yml</code>)中footer.icon:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">footer:</span><br><span class="line"> icon: user</span><br></pre></td></tr></table></figure><p>将icon值改为图标的名称。</p>]]></content>
<summary type="html">
<p>1.从 <a href="https://fontawesome.com/icons" target="_blank" rel="noopener">图标库</a> 中挑选一款图标。<br>2.修改主题配置文件(<code>\xxxx.github.io\themes\ne
</summary>
<category term="博客" scheme="http://inmyai.com/categories/%E5%8D%9A%E5%AE%A2/"/>
<category term="教程" scheme="http://inmyai.com/tags/%E6%95%99%E7%A8%8B/"/>
<category term="NexT" scheme="http://inmyai.com/tags/NexT/"/>
</entry>
<entry>
<title>NexT Live2D模块安装教程</title>
<link href="http://inmyai.com/2018/05/01/Live2D-%E6%A8%A1%E5%9D%97%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/"/>
<id>http://inmyai.com/2018/05/01/Live2D-模块安装教程/</id>
<published>2018-05-01T11:55:00.000Z</published>
<updated>2018-05-01T12:50:16.719Z</updated>
<content type="html"><![CDATA[<h2 id="安装模块"><a href="#安装模块" class="headerlink" title="安装模块"></a>安装模块</h2><p><code>npm install --save hexo-helper-live2d</code></p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>在站点配置文件(<code>\xxxx.github.io\_config.yml</code>)的尾部,加入:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">live2d:</span><br><span class="line"> enable: true</span><br><span class="line"> scriptFrom: local</span><br><span class="line"> pluginRootPath: live2dw/</span><br><span class="line"> pluginJsPath: lib/</span><br><span class="line"> pluginModelPath: assets/</span><br><span class="line"> model:</span><br><span class="line"> use: live2d-widget-model-koharu # 模型的名称</span><br><span class="line"> display:</span><br><span class="line"> position: right</span><br><span class="line"> width: 150</span><br><span class="line"> height: 300</span><br><span class="line"> mobile:</span><br><span class="line"> show: false # 手机是否显示,考虑手机的显示问题,可以选择false</span><br></pre></td></tr></table></figure></p><h2 id="安装模型"><a href="#安装模型" class="headerlink" title="安装模型"></a>安装模型</h2><p>从 <a href="https://huaji8.top/post/live2d-plugin-2.0/" target="_blank" rel="noopener">模型库</a> 中找到一款喜欢的,然后<code>npm install live2d-widget-model-模型名称</code>进行安装,修改配置文件。<br>例如:看上初音未来的模型(<code>miku</code>),则通过<code>npm install live2d-widget-model-miku</code>安装模型。然后修改站点配置文件中的model:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">model:</span><br><span class="line"> use: live2d-widget-model-koharu</span><br></pre></td></tr></table></figure></p><p>修改为:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">model:</span><br><span class="line"> use: live2d-widget-model-miku</span><br></pre></td></tr></table></figure></p><p>重启博客,就会发现右下角出现一只神奇的东西(斜眼笑.jpg)。</p>]]></content>
<summary type="html">
<h2 id="安装模块"><a href="#安装模块" class="headerlink" title="安装模块"></a>安装模块</h2><p><code>npm install --save hexo-helper-live2d</code></p>
<h2 id=
</summary>
<category term="博客" scheme="http://inmyai.com/categories/%E5%8D%9A%E5%AE%A2/"/>
<category term="教程" scheme="http://inmyai.com/tags/%E6%95%99%E7%A8%8B/"/>
<category term="Live 2D" scheme="http://inmyai.com/tags/Live-2D/"/>
</entry>
<entry>
<title> GitHub Pages 腾讯云CDN加速教程</title>
<link href="http://inmyai.com/2018/04/30/GitHub-Pages-%E8%85%BE%E8%AE%AF%E4%BA%91CDN%E5%8A%A0%E9%80%9F%E6%95%99%E7%A8%8B/"/>
<id>http://inmyai.com/2018/04/30/GitHub-Pages-腾讯云CDN加速教程/</id>
<published>2018-04-30T12:48:00.000Z</published>
<updated>2018-04-30T14:42:54.280Z</updated>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>基于GitHub Pages搭建的博客是存储在GitHub服务器上,而GitHub Pages共用一台服务器,且服务器是在外国。因此,打开博客 = ppt演示。目前一种主流的方式是通过CDN提高网页的响应速度。</p><p>网络上有很多关于腾讯云CDN加速教程,但是不够详细,博主也因此折腾半天。现在,总结一下目前腾讯云CDN加速的具体流程。</p><h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><ul><li>GitHub Pages 地址解析到个人域名(可以参照之前<a href="http://www.inmyai.com/2018/04/29/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E6%8C%87%E5%8D%97/" target="_blank" rel="noopener">博客搭建指南</a>中的<a href="http://localhost:4000/admin/#/posts/cjgm8pvcs00004k7kbmzh5pwj" target="_blank" rel="noopener">基础教程</a>)</li></ul><h2 id="开始食用"><a href="#开始食用" class="headerlink" title="开始食用"></a>开始食用</h2><h3 id="1-开通腾讯云CDN服务,添加域名。"><a href="#1-开通腾讯云CDN服务,添加域名。" class="headerlink" title="1.开通腾讯云CDN服务,添加域名。"></a>1.开通<a href="https://console.cloud.tencent.com/cdn" target="_blank" rel="noopener">腾讯云CDN服务</a>,添加域名。</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">域名:输入你自己的个人域名,wwww.xxxx.com</span><br><span class="line">源站设置:输入你GitHub Pages的ip地址,具体如下</span><br><span class="line">其他保持默认</span><br></pre></td></tr></table></figure><p>例如,我的GitHub Pages:hlxing.github.io,打开命令行,输入<code>ping hlxing.github.io</code></p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/37722924.jpg" alt="示例"><br>源站设置为: <code>185.199.110.153</code></p><h3 id="2-等待部署,然后获取CNAME,效果图:"><a href="#2-等待部署,然后获取CNAME,效果图:" class="headerlink" title="2.等待部署,然后获取CNAME,效果图:"></a>2.等待部署,然后获取CNAME,效果图:</h3><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/78284969.jpg" alt="效果图"></p><p>CNAME为:<code>www.xxxx.com.cdn.dnsv1.com</code></p><h3 id="3-进入域名管理,点击解析,添加4条记录。"><a href="#3-进入域名管理,点击解析,添加4条记录。" class="headerlink" title="3.进入域名管理,点击解析,添加4条记录。"></a>3.进入<a href="https://console.cloud.tencent.com/domain" target="_blank" rel="noopener">域名管理</a>,点击解析,添加4条记录。</h3><ul><li><p>第一条(可选): </p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/47077302.jpg" alt="@"></p><p>主机记录选择 <code>@</code> ,映射xxxx.com<br>记录类型选择 <code>CNAME</code><br>线路类型选择 <code>国内</code>,只有国内进行访问时生效<br>记录值输入刚刚从CDN获取的<code>CNAME</code></p></li><li><p>第二条(必选):</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/84970049.jpg" alt="www"></p><p>主机记录选择 <code>www</code> ,映射<a href="http://www.xxxx.com" target="_blank" rel="noopener">www.xxxx.com</a><br>记录类型选择 <code>CNAME</code><br>线路类型选择 <code>国内</code>,只有国内进行访问时生效<br>记录值输入刚刚从CDN获取的<code>CNAME</code></p></li><li><p>第三条(可选):</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/87422341.jpg" alt="@国外"></p><p>主机记录选择 <code>@</code> ,映射xxxx.com<br>记录类型选择 <code>CNAME</code><br>线路类型选择 <code>国外</code>,只有国外进行访问时生效<br>记录值输入 自己的<code>GitHub Pages地址</code></p></li><li><p>第四条(必选):</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/80226340.jpg" alt="www国外"></p><p>主机记录选择 <code>www</code> ,映射<a href="http://www.xxxx.com" target="_blank" rel="noopener">www.xxxx.com</a><br>记录类型选择 <code>CNAME</code><br>线路类型选择 <code>国外</code>,只有国外进行访问时生效<br>记录值输入 自己的<code>GitHub Pages地址</code></p></li><li><p>关于分国外国内:</p><p>GitHub Pages服务器在外国,用国内的CDN等于没有,且国外访问GitHub Pages是十分流畅的。</p></li></ul><h3 id="4-CDN验证"><a href="#4-CDN验证" class="headerlink" title="4.CDN验证"></a>4.CDN验证</h3><ul><li>打开命令行,输入 <code>ping xxxx.com</code> 或者 <code>www.xxxx.com</code>,如果出现的IP地址不是你GitHub Pages的ip地址,则CDN加速成功。如果没有,则可能是CDN还没有完成部署,或者域名解析还没完成(一般需要几分钟)。</li></ul><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/76553225.jpg" alt="CDN验证"></p><h2 id="食用效果"><a href="#食用效果" class="headerlink" title="食用效果"></a>食用效果</h2><p>打开<a href="http://ping.chinaz.com" target="_blank" rel="noopener">站长之家的Ping检测</a>,输入<code>xxxx.com</code>,或<code>www.xxxx.com</code>,或<code>xxxx.github.io</code>。</p><p>原本是一只褐色的公鸡(尚未开启CDN加速):</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/5166014.jpg" alt="褐色公鸡"></p><p>然后被绿了(开启CDN加速):</p><p><img src="http://hlx-blog.oss-cn-beijing.aliyuncs.com/18-4-30/2001038.jpg" alt="绿色公鸡"></p><p>可见,效果极佳!</p><ul><li>备注:检测<code>xxxx.github.io</code>时发现还是一只褐色公鸡??但实际上,它会发生重定向(F12查询),且重定向后的请求的Remote Address均是CDN加速所用的服务器,因此CDN效果依然存在。</li></ul>]]></content>
<summary type="html">
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>基于GitHub Pages搭建的博客是存储在GitHub服务器上,而GitHub Pages共用一台服务器,且服务器是在外国。因此,打开博
</summary>
<category term="博客" scheme="http://inmyai.com/categories/%E5%8D%9A%E5%AE%A2/"/>
<category term="教程" scheme="http://inmyai.com/tags/%E6%95%99%E7%A8%8B/"/>
<category term="CDN" scheme="http://inmyai.com/tags/CDN/"/>
</entry>
<entry>
<title>博客搭建指南</title>
<link href="http://inmyai.com/2018/04/29/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E6%8C%87%E5%8D%97/"/>
<id>http://inmyai.com/2018/04/29/博客搭建指南/</id>
<published>2018-04-29T13:44:00.000Z</published>
<updated>2018-07-21T13:41:30.948Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>自己写一个博客系统吧?不存在的。<br>推荐一个快速搭建博客的方法,采用Hexo + GitHub Pages进行搭建,简单实用,而且不需要自己购买9块9包月的服务器。</p><h2 id="食用方法"><a href="#食用方法" class="headerlink" title="食用方法"></a>食用方法</h2><ul><li><a href="http://www.lovebxm.com/2018/06/24/hexo-github-blog/" target="_blank" rel="noopener">基础教程</a>(大概需要20分钟,完成博客的基础模块,出自<strong>白小明</strong>大佬)</li><li><a href="https://www.jianshu.com/p/5973c05d7100" target="_blank" rel="noopener">进阶教程</a>(大概需要几个小时,扩展博客的功能,出自<strong>代码咖啡</strong>大佬)</li></ul><h2 id="备注"><a href="#备注" class="headerlink" title="备注"></a>备注</h2><ul><li>进阶教程中的搜索功能添加出现问题的话(我就是一个),可以采用另一种方法:<br><a href="https://zty.js.org/post/2016/07/08/hexo-localsearch.html" target="_blank" rel="noopener">本地站内搜索</a>(出自<strong>Zetao Yang</strong>大佬)</li><li>更多扩展功能请自行百度</li></ul><h2 id="TODO"><a href="#TODO" class="headerlink" title="TODO"></a>TODO</h2><ul><li>Live2D 模块安装教程(右下角那只宠物就是Live2D的产物</li><li>底部logo栏更改教程</li><li>Hexo-Admin后台管理中Deploy功能的正确打开方式(Windows 环境下)</li><li>腾讯云CDN加速教程</li></ul>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>自己写一个博客系统吧?不存在的。<br>推荐一个快速搭建博客的方法,采用Hexo + GitHub Pages进行搭建,简单实用,而且不需要
</summary>
<category term="博客" scheme="http://inmyai.com/categories/%E5%8D%9A%E5%AE%A2/"/>
<category term="教程" scheme="http://inmyai.com/tags/%E6%95%99%E7%A8%8B/"/>
</entry>
</feed>