auto commit
This commit is contained in:
parent
7e4d5152f7
commit
d8a3670789
|
@ -1,33 +1,33 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [???](#???)
|
* [前言](#前言)
|
||||||
* [1. §³??-§³??Git](#1-§ã??-§ã??git)
|
* [1. 小米-小米Git](#1-小米-小米git)
|
||||||
* [2. §³??-????????](#2-§ã??-????????)
|
* [2. 小米-懂二进制](#2-小米-懂二进制)
|
||||||
* [3. §³??-?§Û????](#3-§ã??-?§Û????)
|
* [3. 小米-中国牛市](#3-小米-中国牛市)
|
||||||
* [4. ???-LUCKY STRING](#4-???-lucky-string)
|
* [4. 微软-LUCKY STRING](#4-微软-lucky-string)
|
||||||
* [5. ???-Numeric Keypad](#5-???-numeric-keypad)
|
* [5. 微软-Numeric Keypad](#5-微软-numeric-keypad)
|
||||||
* [6. ???-Spring Outing](#6-???-spring-outing)
|
* [6. 微软-Spring Outing](#6-微软-spring-outing)
|
||||||
* [7. ???-S-expression](#7-???-s-expression)
|
* [7. 微软-S-expression](#7-微软-s-expression)
|
||||||
* [8. ???-?????????](#8-???-?????????)
|
* [8. 华为-最高分是多少](#8-华为-最高分是多少)
|
||||||
* [9. ???-???????](#9-???-???????)
|
* [9. 华为-简单错误记录](#9-华为-简单错误记录)
|
||||||
* [10. ???-??????§³](#10-???-??????§ã)
|
* [10. 华为-扑克牌大小](#10-华为-扑克牌大小)
|
||||||
* [11. ????-???????](#11-????-???????)
|
* [11. 去哪儿-二分查找](#11-去哪儿-二分查找)
|
||||||
* [12. ????-?????????](#12-????-?????????)
|
* [12. 去哪儿-首个重复字符](#12-去哪儿-首个重复字符)
|
||||||
* [13. ????-???Coder](#13-????-???coder)
|
* [13. 去哪儿-寻找Coder](#13-去哪儿-寻找coder)
|
||||||
* [14. ????-?????](#14-????-?????)
|
* [14. 美团-最大差值](#14-美团-最大差值)
|
||||||
* [15. ????-??????](#15-????-??????)
|
* [15. 美团-棋子翻转](#15-美团-棋子翻转)
|
||||||
* [16. ????-???](#16-????-???)
|
* [16. 美团-拜访](#16-美团-拜访)
|
||||||
* [17. ????-????????????](#17-????-????????????)
|
* [17. 美团-直方图内最大矩形](#17-美团-直方图内最大矩形)
|
||||||
* [18. ????-?????????](#18-????-?????????)
|
* [18. 美团-字符串计数](#18-美团-字符串计数)
|
||||||
* [19. ????-???????](#19-????-???????)
|
* [19. 美团-平均年龄](#19-美团-平均年龄)
|
||||||
* [20. ???-?????](#20-???-?????)
|
* [20. 百度-罪犯转移](#20-百度-罪犯转移)
|
||||||
* [22. ???-?¨¹??????](#22-???-?¨¹??????)
|
* [22. 百度-裁减网格纸](#22-百度-裁减网格纸)
|
||||||
* [23. ???-???????](#23-???-???????)
|
* [23. 百度-钓鱼比赛](#23-百度-钓鱼比赛)
|
||||||
* [24. ???-?????](#24-???-?????)
|
* [24. 百度-蘑菇阵](#24-百度-蘑菇阵)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ???
|
# 前言
|
||||||
|
|
||||||
???????
|
省略的代码:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -48,10 +48,10 @@ public class Main {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 1. §³??-§³??Git
|
# 1. 小米-小米Git
|
||||||
|
|
||||||
- ????????
|
- 重建多叉树
|
||||||
- ??? LCA
|
- 使用 LCA
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private class TreeNode {
|
private class TreeNode {
|
||||||
|
@ -65,7 +65,7 @@ private class TreeNode {
|
||||||
|
|
||||||
public int getSplitNode(String[] matrix, int indexA, int indexB) {
|
public int getSplitNode(String[] matrix, int indexA, int indexB) {
|
||||||
int n = matrix.length;
|
int n = matrix.length;
|
||||||
boolean[][] linked = new boolean[n][n]; // ?????????
|
boolean[][] linked = new boolean[n][n]; // 重建邻接矩阵
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
linked[i][j] = matrix[i].charAt(j) == '1';
|
linked[i][j] = matrix[i].charAt(j) == '1';
|
||||||
|
@ -80,7 +80,7 @@ private TreeNode constructTree(boolean[][] linked, int root) {
|
||||||
TreeNode tree = new TreeNode(root);
|
TreeNode tree = new TreeNode(root);
|
||||||
for (int i = 0; i < linked[root].length; i++) {
|
for (int i = 0; i < linked[root].length; i++) {
|
||||||
if (linked[root][i]) {
|
if (linked[root][i]) {
|
||||||
linked[i][root] = false; // ???????????????????????????????????????????
|
linked[i][root] = false; // 因为题目给的邻接矩阵是双向的,在这里需要把它转为单向的
|
||||||
tree.childs.add(constructTree(links, i));
|
tree.childs.add(constructTree(links, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,9 +102,9 @@ private TreeNode LCA(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 2. §³??-????????
|
# 2. 小米-懂二进制
|
||||||
|
|
||||||
??????????????????????????? 1 ?????¦Ë???????????????¦Ë??
|
对两个数进行异或,结果的二进制表示为 1 的那一位就是两个数不同的位。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int countBitDiff(int m, int n) {
|
public int countBitDiff(int m, int n) {
|
||||||
|
@ -112,11 +112,11 @@ public int countBitDiff(int m, int n) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 3. §³??-?§Û????
|
# 3. 小米-中国牛市
|
||||||
|
|
||||||
???????????????????§³? 2 ???????
|
背包问题,可以设一个大小为 2 的背包。
|
||||||
|
|
||||||
?????????????
|
状态转移方程如下:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] } = max(dp[i, j-1], prices[j] + max(dp[i-1, jj] - prices[jj]))
|
dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] } = max(dp[i, j-1], prices[j] + max(dp[i-1, jj] - prices[jj]))
|
||||||
|
@ -137,10 +137,10 @@ public int calculateMax(int[] prices) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 4. ???-LUCKY STRING
|
# 4. 微软-LUCKY STRING
|
||||||
|
|
||||||
- ?????????§á????????
|
- 斐波那契数列可以预计算;
|
||||||
- ?????¦Â?????????????????????????????? Set ??????? i ?? j ?????????????? Set ?????????????????? Set ???§³????????????????
|
- 从头到尾遍历字符串的过程,每一轮循环都使用一个 Set 来保存从 i 到 j 出现的字符,并且 Set 保证了字符都不同,因此 Set 的大小就是不同字符的个数。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Set<Integer> fibSet = new HashSet<>(Arrays.asList(1, 2, 3, 5, 8, 13, 21, 34, 55, 89));
|
Set<Integer> fibSet = new HashSet<>(Arrays.asList(1, 2, 3, 5, 8, 13, 21, 34, 55, 89));
|
||||||
|
@ -165,7 +165,7 @@ for (String s : arr) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 5. ???-Numeric Keypad
|
# 5. 微软-Numeric Keypad
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private static int[][] canReach = {
|
private static int[][] canReach = {
|
||||||
|
@ -209,17 +209,17 @@ public static void main(String[] args) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 6. ???-Spring Outing
|
# 6. 微软-Spring Outing
|
||||||
|
|
||||||
?????? N = 3??K = 4 ???????????
|
下面以 N = 3,K = 4 来进行讨论。
|
||||||
|
|
||||||
????????? 0 ??????????????????????????
|
初始时,令第 0 个地方成为待定地点,也就是呆在家里。
|
||||||
|
|
||||||
??? 4 ??????????????????????? 4 ???????? 0 ????????????????????????????????????? 4 ??????????????? 4 ???????????????
|
从第 4 个地点开始投票,每个人只需要比较第 4 个地方和第 0 个地方的优先级,里,如果超过半数的人选择了第 4 个地方,那么更新第 4 个地方成为待定地点。
|
||||||
|
|
||||||
???????????????????Ñk???????????????????§Ö???????????
|
从后往前不断重复以上步骤,不断更新待定地点,直到所有地方都已经投票。
|
||||||
|
|
||||||
??????????§µ?????? 0 ???????????????????????????? 4 ????????????????????§Ò???????????????????????????????? 1 ????????????????????? 2 ??????????????????????????? 2 ???????? 1 ?????????????????????????????????????
|
上面的讨论中,先令第 0 个地点成为待定地点,是因为这样的话第 4 个地点就只需要和这个地点进行比较,而不用考虑其它情况。如果最开始先令第 1 个地点成为待定地点,那么在对第 2 个地点进行投票时,每个人不仅要考虑第 2 个地点与第 1 个地点的优先级,也要考虑与其后投票地点的优先级。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int N = in.nextInt();
|
int N = in.nextInt();
|
||||||
|
@ -246,9 +246,9 @@ for (int place = K; place > 0; place--) {
|
||||||
System.out.println(ret == 0 ? "otaku" : ret);
|
System.out.println(ret == 0 ? "otaku" : ret);
|
||||||
```
|
```
|
||||||
|
|
||||||
# 7. ???-S-expression
|
# 7. 微软-S-expression
|
||||||
|
|
||||||
# 8. ???-?????????
|
# 8. 华为-最高分是多少
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int N = in.nextInt();
|
int N = in.nextInt();
|
||||||
|
@ -280,7 +280,7 @@ for (int i = 0; i < M; i++) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 9. ???-???????
|
# 9. 华为-简单错误记录
|
||||||
|
|
||||||
```java
|
```java
|
||||||
HashMap<String, Integer> map = new LinkedHashMap<>();
|
HashMap<String, Integer> map = new LinkedHashMap<>();
|
||||||
|
@ -300,7 +300,7 @@ for (int i = 0; i < 8 && i < list.size(); i++) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 10. ???-??????§³
|
# 10. 华为-扑克牌大小
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Main {
|
public class Main {
|
||||||
|
@ -391,12 +391,12 @@ public class Main {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 11. ????-???????
|
# 11. 去哪儿-二分查找
|
||||||
|
|
||||||
????????????????????ï…????????????????????
|
对于有重复元素的有序数组,二分查找需要注意以下要点:
|
||||||
|
|
||||||
- if (val <= A[m]) h = m;
|
- if (val <= A[m]) h = m;
|
||||||
- ??? h ????? m ?????? m - 1????? while ????????????? l < h????????? m - 1 ???????? l <= h??
|
- 因为 h 的赋值为 m 而不是 m - 1,因此 while 循环的条件也就为 l < h。(如果是 m - 1 循环条件为 l <= h)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int getPos(int[] A, int n, int val) {
|
public int getPos(int[] A, int n, int val) {
|
||||||
|
@ -410,7 +410,7 @@ public int getPos(int[] A, int n, int val) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 12. ????-?????????
|
# 12. 去哪儿-首个重复字符
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public char findFirstRepeat(String A, int n) {
|
public char findFirstRepeat(String A, int n) {
|
||||||
|
@ -424,7 +424,7 @@ public char findFirstRepeat(String A, int n) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 13. ????-???Coder
|
# 13. 去哪儿-寻找Coder
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public String[] findCoder(String[] A, int n) {
|
public String[] findCoder(String[] A, int n) {
|
||||||
|
@ -450,7 +450,7 @@ public String[] findCoder(String[] A, int n) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ???????????? javafx.util.Pair???????????????? Pair ??
|
// 牛客网无法导入 javafx.util.Pair,这里就自己实现一下 Pair 类
|
||||||
private class Pair<T, K> {
|
private class Pair<T, K> {
|
||||||
T t;
|
T t;
|
||||||
K k;
|
K k;
|
||||||
|
@ -470,9 +470,9 @@ private class Pair<T, K> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 14. ????-?????
|
# 14. 美团-最大差值
|
||||||
|
|
||||||
???????
|
贪心策略。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int getDis(int[] A, int n) {
|
public int getDis(int[] A, int n) {
|
||||||
|
@ -486,7 +486,7 @@ public int getDis(int[] A, int n) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 15. ????-??????
|
# 15. 美团-棋子翻转
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int[][] flipChess(int[][] A, int[][] f) {
|
public int[][] flipChess(int[][] A, int[][] f) {
|
||||||
|
@ -502,7 +502,7 @@ public int[][] flipChess(int[][] A, int[][] f) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 16. ????-???
|
# 16. 美团-拜访
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private Set<String> paths;
|
private Set<String> paths;
|
||||||
|
@ -554,7 +554,7 @@ private void backtracking(int[][] map, int n, int m, int r, int c, int[][] direc
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 17. ????-????????????
|
# 17. 美团-直方图内最大矩形
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public int countArea(int[] A, int n) {
|
public int countArea(int[] A, int n) {
|
||||||
|
@ -570,15 +570,15 @@ public int countArea(int[] A, int n) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 18. ????-?????????
|
# 18. 美团-字符串计数
|
||||||
|
|
||||||
?????????§³§Õ????????????????????? 26 ?????????????????????????????????????????????§Ò??????? "ac" ?? "abc"????????????? "ac" > "abc"???????????????????????? "abc" ????¦Ë???????????
|
字符串都是小写字符,可以把字符串当成是 26 进制。但是字典序的比较和普通的整数比较不同,是从左往右进行比较,例如 "ac" 和 "abc",字典序的比较结果为 "ac" > "abc",如果按照整数方法比较,因为 "abc" 是三位数,显然更大。
|
||||||
|
|
||||||
???????????????????????????? s1 ??????? s2 ?????????§Ò????????? s1 ???????????? 'a' ????????????
|
由于两个字符串的长度可能不想等,在 s1 空白部分和 s2 对应部分进行比较时,应该把 s1 的空白部分看成是 'a' 字符进行填充的。
|
||||||
|
|
||||||
???????????????s1 ?? s2 ????? len<sub>i</sub> ?????????????????? i ??????????? 'aaa' ?? 'bbb' ??????? 2 ?????? 'aa' ?? 'bb' ????????????????????????ÑØ????????
|
还有一点要注意的是,s1 到 s2 长度为 len<sub>i</sub> 的字符串个数只比较前面 i 个字符。例如 'aaa' 和 'bbb' ,长度为 2 的个数为 'aa' 到 'bb' 的字符串个数,不需要考虑后面部分的字符。
|
||||||
|
|
||||||
????????????? len1 ???????????????????????????????????? i ???????????????
|
在统计个数时,从 len1 开始一直遍历到最大合法长度,每次循环都统计长度为 i 的子字符串个数。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
String s1 = in.next();
|
String s1 = in.next();
|
||||||
|
@ -601,7 +601,7 @@ for (int i = len1; i <= len; i++) {
|
||||||
System.out.println(ret - 1);
|
System.out.println(ret - 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
# 19. ????-???????
|
# 19. 美团-平均年龄
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int W = in.nextInt();
|
int W = in.nextInt();
|
||||||
|
@ -609,15 +609,15 @@ double Y = in.nextDouble();
|
||||||
double x = in.nextDouble();
|
double x = in.nextDouble();
|
||||||
int N = in.nextInt();
|
int N = in.nextInt();
|
||||||
while (N-- > 0) {
|
while (N-- > 0) {
|
||||||
Y++; // ??????????????? 1
|
Y++; // 老员工每年年龄都要加 1
|
||||||
Y += (21 - Y) * x;
|
Y += (21 - Y) * x;
|
||||||
}
|
}
|
||||||
System.out.println((int) Math.ceil(Y));
|
System.out.println((int) Math.ceil(Y));
|
||||||
```
|
```
|
||||||
|
|
||||||
# 20. ???-?????
|
# 20. 百度-罪犯转移
|
||||||
|
|
||||||
??????????????????????????????
|
部分和问题,将每次求的部分和缓存起来。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int n = in.nextInt();
|
int n = in.nextInt();
|
||||||
|
@ -640,7 +640,7 @@ for (int s = 0, e = c - 1; e < n; s++, e++) {
|
||||||
System.out.println(cnt);
|
System.out.println(cnt);
|
||||||
```
|
```
|
||||||
|
|
||||||
# 22. ???-?¨¹??????
|
# 22. 百度-裁减网格纸
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int n = in.nextInt();
|
int n = in.nextInt();
|
||||||
|
@ -658,11 +658,11 @@ for (int i = 0; i < n; i++) {
|
||||||
System.out.println((int) Math.pow(Math.max(maxX - minX, maxY - minY), 2));
|
System.out.println((int) Math.pow(Math.max(maxX - minX, maxY - minY), 2));
|
||||||
```
|
```
|
||||||
|
|
||||||
# 23. ???-???????
|
# 23. 百度-钓鱼比赛
|
||||||
|
|
||||||
P ( ?????????? ) = 1 - P ( ?????????? )
|
P ( 至少钓一条鱼 ) = 1 - P ( 一条也钓不到 )
|
||||||
|
|
||||||
?????????????????????????§ß??§Ø??????????????? in.nextDouble()??
|
坑:读取概率矩阵的时候,需要一行一行进行读取,而不能直接用 in.nextDouble()。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -673,11 +673,11 @@ public static void main(String[] args) {
|
||||||
int x = in.nextInt();
|
int x = in.nextInt();
|
||||||
int y = in.nextInt();
|
int y = in.nextInt();
|
||||||
int t = in.nextInt();
|
int t = in.nextInt();
|
||||||
in.nextLine(); // ??
|
in.nextLine(); // 坑
|
||||||
double pcc = 0.0;
|
double pcc = 0.0;
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
String[] token = in.nextLine().split(" "); // ??
|
String[] token = in.nextLine().split(" "); // 坑
|
||||||
for (int j = 1; j <= m; j++) {
|
for (int j = 1; j <= m; j++) {
|
||||||
double p = Double.parseDouble(token[j - 1]);
|
double p = Double.parseDouble(token[j - 1]);
|
||||||
// double p = in.nextDouble();
|
// double p = in.nextDouble();
|
||||||
|
@ -701,13 +701,13 @@ private static double computePOfIRT(double p, int t) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 24. ???-?????
|
# 24. 百度-蘑菇阵
|
||||||
|
|
||||||
?????????????????? DP??
|
这题用回溯会超时,需要用 DP。
|
||||||
|
|
||||||
dp[i][j] ??????? (i,j) ¦Ë?¨°?????????????????? N\*M ??????? i == N || j == M????? (i,j) ???????????????????????????????????????
|
dp[i][j] 表示到达 (i,j) 位置不会触碰蘑菇的概率。对于 N\*M 矩阵,如果 i == N || j == M,那么 (i,j) 只能有一个移动方向;其它情况下能有两个移动方向。
|
||||||
|
|
||||||
??????????????§Ö? 3 ?§Ü?? 3 ?????????????????????????¦Ë????????????????????
|
考虑以下矩阵,其中第 3 行和第 3 列只能往一个方向移动,而其它位置可以有两个方向移动。
|
||||||
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
432
notes/HTTP.md
432
notes/HTTP.md
|
@ -1,83 +1,83 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [????????](#????????)
|
* [基础概念](#基础概念)
|
||||||
* [Web????](#web????)
|
* [Web基础](#web基础)
|
||||||
* [URL](#url)
|
* [URL](#url)
|
||||||
* [????????????](#????????????)
|
* [请求和响应报文](#请求和响应报文)
|
||||||
* [HTTP ????](#http-????)
|
* [HTTP 方法](#http-方法)
|
||||||
* [GET????????](#get????????)
|
* [GET:获取资源](#get获取资源)
|
||||||
* [POST?????????????](#post?????????????)
|
* [POST:传输实体主体](#post传输实体主体)
|
||||||
* [HEAD????????????](#head????????????)
|
* [HEAD:获取报文首部](#head获取报文首部)
|
||||||
* [PUT????????](#put???θ????)
|
* [PUT:上传文件](#put上传文件)
|
||||||
* [DELETE????????](#delete????????)
|
* [DELETE:删除文件](#delete删除文件)
|
||||||
* [OPTIONS????????????](#options????????????)
|
* [OPTIONS:查询支持的方法](#options查询支持的方法)
|
||||||
* [RACE?????·??](#race?????·??)
|
* [RACE:追踪路径](#race追踪路径)
|
||||||
* [CONNECT??????????Э?????????](#connect??????????э?????????)
|
* [CONNECT:要求用隧道协议连接代理](#connect要求用隧道协议连接代理)
|
||||||
* [HTTP ????](#http-????)
|
* [HTTP 状态码](#http-状态码)
|
||||||
* [2XX ???](#2xx-???)
|
* [2XX 成功](#2xx-成功)
|
||||||
* [3XX ?????](#3xx-?????)
|
* [3XX 重定向](#3xx-重定向)
|
||||||
* [4XX ????????](#4xx-????????)
|
* [4XX 客户端错误](#4xx-客户端错误)
|
||||||
* [5XX ??????????](#5xx-??????????)
|
* [5XX 服务器错误](#5xx-服务器错误)
|
||||||
* [HTTP???](#http???)
|
* [HTTP首部](#http首部)
|
||||||
* [?????????](#?????????)
|
* [通用首部字段](#通用首部字段)
|
||||||
* [??????????](#??????????)
|
* [请求首部字段](#请求首部字段)
|
||||||
* [?????????](#?????????)
|
* [响应首部字段](#响应首部字段)
|
||||||
* [?????????](#?????????)
|
* [实体首部字段](#实体首部字段)
|
||||||
* [???????](#???????)
|
* [具体应用](#具体应用)
|
||||||
* [Cookie](#cookie)
|
* [Cookie](#cookie)
|
||||||
* [????](#????)
|
* [缓存](#缓存)
|
||||||
* [???????](#???????)
|
* [持久连接](#持久连接)
|
||||||
* [????](#????)
|
* [编码](#编码)
|
||||||
* [??鴫??](#??鴫??)
|
* [分块传输](#分块传输)
|
||||||
* [????????](#????????)
|
* [多部分对象集合](#多部分对象集合)
|
||||||
* [??Χ????](#??χ????)
|
* [范围请求](#范围请求)
|
||||||
* [????Э??](#????э??)
|
* [内容协商](#内容协商)
|
||||||
* [????????](#????????)
|
* [虚拟主机](#虚拟主机)
|
||||||
* [??????????](#??????????)
|
* [通信数据转发](#通信数据转发)
|
||||||
* [HTTPs](#https)
|
* [HTTPs](#https)
|
||||||
* [????](#????)
|
* [加密](#加密)
|
||||||
* [???](#???)
|
* [认证](#认证)
|
||||||
* [??????](#??????)
|
* [完整性](#完整性)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ????????
|
# 基础概念
|
||||||
|
|
||||||
## Web????
|
## Web基础
|
||||||
|
|
||||||
HTTP??HyperText Transfer Protocol???????????Э?飩??
|
HTTP(HyperText Transfer Protocol,超为本传输协议)。
|
||||||
|
|
||||||
WWW??Word Wide Web?????????????HTML??HTTP??URL??
|
WWW(Word Wide Web)的三种技术:HTML、HTTP、URL。
|
||||||
|
|
||||||
RFC??Request for Comments??????????????飩??????????????????
|
RFC(Request for Comments,征求修正意见书),互联网的设计文档。
|
||||||
|
|
||||||
## URL
|
## URL
|
||||||
|
|
||||||
URI??Uniform Resource Indentifier????????????????URL??Uniform Resource Locator?????????λ??????URN??Uniform Resource Name?????????????????? urn:isbn:0-486-27557-4 ??URI ???? URL ?? URN???? WEB ??? URL ??????У????????????????? URL??
|
URI(Uniform Resource Indentifier,统一资源标识符),URL(Uniform Resource Locator,统一资源定位符),URN(Uniform Resource Name,统一资源名称),例如 urn:isbn:0-486-27557-4 。URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL。
|
||||||
|
|
||||||
URL?????
|
URL格式:
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4102b7d0-39b9-48d8-82ae-ac4addb7ebfb.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4102b7d0-39b9-48d8-82ae-ac4addb7ebfb.jpg)
|
||||||
|
|
||||||
## ????????????
|
## 请求和响应报文
|
||||||
|
|
||||||
**??????**
|
**请求报文**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9dbb5fc2-936b-4c6d-b3a7-9617aae45080.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9dbb5fc2-936b-4c6d-b3a7-9617aae45080.jpg)
|
||||||
|
|
||||||
**???????**
|
**响应报文**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c634b5ed-a14b-4302-b40e-3ee387dd3c8a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c634b5ed-a14b-4302-b40e-3ee387dd3c8a.jpg)
|
||||||
|
|
||||||
# HTTP ????
|
# HTTP 方法
|
||||||
|
|
||||||
?????????????????????????У????????????Ρ?
|
客户端发送的请求报文第一行为请求行,包含了方法字段。
|
||||||
|
|
||||||
## GET????????
|
## GET:获取资源
|
||||||
|
|
||||||
## POST?????????????
|
## POST:传输实体主体
|
||||||
|
|
||||||
POST ???????????????????????????????????
|
POST 主要目的不是获取资源,而是传输实体主体数据。
|
||||||
|
|
||||||
GET ?? POST ???????????????????????? GET ?????????????????????? URL?У??? POST ??????洢????????岿???
|
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL中,而 POST 的参数存储在实体主体部分。
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
|
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
|
||||||
|
@ -88,312 +88,312 @@ Host: w3schools.com
|
||||||
name1=value1&name2=value2
|
name1=value1&name2=value2
|
||||||
```
|
```
|
||||||
|
|
||||||
GET ????η??????? POST ?????????? GET ????????? URL ????????????й????????????? GET ???? ASCII ???????????????????????????????? POST ????????????
|
GET 的传参方式相比于 POST 安全性较差,因为 GET 传的参数在 URL 是可见的,可能会泄露私密信息。并且 GET 只支持 ASCII 字符,如果参数为中文则可能会出现乱码,而 POST 支持标准字符集。
|
||||||
|
|
||||||
## HEAD????????????
|
## HEAD:获取报文首部
|
||||||
|
|
||||||
?? GET ???????????????????????????岿???
|
和 GET 方法一样,但是不返回报文实体主体部分。
|
||||||
|
|
||||||
?????????? URL ????Ч??????????????????????
|
主要用于确认 URL 的有效性以及资源更新的日期时间等。
|
||||||
|
|
||||||
## PUT????????
|
## PUT:上传文件
|
||||||
|
|
||||||
???????????????????κ????????????????????????????????? WEB ????????÷?????
|
由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般 WEB 网站不使用该方法。
|
||||||
|
|
||||||
## DELETE????????
|
## DELETE:删除文件
|
||||||
|
|
||||||
?? PUT ???????????????????????????
|
与 PUT 功能相反,并且同样不带验证机制。
|
||||||
|
|
||||||
## OPTIONS????????????
|
## OPTIONS:查询支持的方法
|
||||||
|
|
||||||
???????? URL ????????????
|
查询指定的 URL 能够支持的方法。
|
||||||
|
|
||||||
???? Allow: GET, POST, HEAD, OPTIONS ???????????
|
会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容。
|
||||||
|
|
||||||
## RACE?????·??
|
## RACE:追踪路径
|
||||||
|
|
||||||
???????????·?????????????
|
服务器会将通信路径返回给客户端。
|
||||||
|
|
||||||
????????????? Max-Forwards ??????????????????????????????????? 1???????? 0 ?????????
|
发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。
|
||||||
|
|
||||||
TRACE ?????????????????????? XST ??????Cross-Site Tracing???????????????????????????
|
TRACE 一般不会使用,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪),因此更不会去使用它。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ca711108-e937-4d7d-99aa-61b325c61f1a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ca711108-e937-4d7d-99aa-61b325c61f1a.jpg)
|
||||||
|
|
||||||
## CONNECT??????????Э?????????
|
## CONNECT:要求用隧道协议连接代理
|
||||||
|
|
||||||
?????Э????? TCP ????
|
用隧道协议进行 TCP 通信。
|
||||||
|
|
||||||
?????? SSL??Secure Sokets Layer????????????? TLS??Transport Layer Security??????????Э?????????????????????????
|
主要使用 SSL(Secure Sokets Layer,安全套接字)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d8355d56-aa2b-4452-8001-8475cc095af1.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d8355d56-aa2b-4452-8001-8475cc095af1.jpg)
|
||||||
|
|
||||||
# HTTP ????
|
# HTTP 状态码
|
||||||
|
|
||||||
???????????????????е????????У???????????????????????????????????????
|
服务器返回的响应报文中第一行为状态行,包含了状态码以及原因短语,来告知客户端请求的结果。
|
||||||
|
|
||||||
| ???? | ??? | ?????? |
|
| 状态码 | 类别 | 原因短语 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 1XX | Informational??????????? | ???????????????? |
|
| 1XX | Informational(信息性状态码) | 接收的请求正在处理 |
|
||||||
| 2XX | Success????????? | ??????????????? |
|
| 2XX | Success(成功状态码) | 请求正常处理完毕 |
|
||||||
| 3XX | Redirection??????????? | ??????и??????????????? |
|
| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
|
||||||
| 4XX | Client Error?????????????? | ????????????????? |
|
| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
|
||||||
| 5XX | Server Error???????????????? | ????????????????? |
|
| 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
|
||||||
|
|
||||||
## 2XX ???
|
## 2XX 成功
|
||||||
|
|
||||||
**200 OK**
|
**200 OK**
|
||||||
|
|
||||||
**204 No Content**???????????????????????????????????????????岿?????????????????????????????????????????????????????á?
|
**204 No Content**:请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
|
||||||
|
|
||||||
**206 Partial Content**
|
**206 Partial Content**
|
||||||
|
|
||||||
## 3XX ?????
|
## 3XX 重定向
|
||||||
|
|
||||||
**301 Moved Permanently**?????????????
|
**301 Moved Permanently**:永久性重定向
|
||||||
|
|
||||||
**302 Found**????????????
|
**302 Found**:临时性重定向
|
||||||
|
|
||||||
**303 See Other**
|
**303 See Other**
|
||||||
|
|
||||||
?????? HTTP Э??涨 301??302 ????????????????? POST ??????? GET ???????????????????????? 301??302 ?? 303 ??????????? POST ??????? GET ??????
|
注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会把 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
|
||||||
|
|
||||||
**304 Not Modified**???????????????????Щ?????????磺If-Match??If-ModifiedSince??If-None-Match??If-Range??If-Unmodified-Since???????????????????????????? 304 ????
|
**304 Not Modified**:如果请求报文首部包含一些条件,例如:If-Match,If-ModifiedSince,If-None-Match,If-Range,If-Unmodified-Since,但是不满足条件,则服务器会返回 304 状态码。
|
||||||
|
|
||||||
**307 Temporary Redirect**???????????? 302 ?????????????? 307 ??????????????????????? POST ??????? GET ??????
|
**307 Temporary Redirect**:临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
|
||||||
|
|
||||||
## 4XX ????????
|
## 4XX 客户端错误
|
||||||
|
|
||||||
**400 Bad Request**?????????д?????????
|
**400 Bad Request**:请求报文中存在语法错误
|
||||||
|
|
||||||
**401 Unauthorized**??????????????????????????? HTTP ?????BASIC ?????DIGEST ????????????????????????й??????????????????????
|
**401 Unauthorized**:该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。如果之前已进行过一次请求,则表示用户认证失败。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b1b4cf7d-c54a-4ff1-9741-cd2eea331123.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b1b4cf7d-c54a-4ff1-9741-cd2eea331123.jpg)
|
||||||
|
|
||||||
**403 Forbidden**????????????????????б?????????????????ɡ?
|
**403 Forbidden**:请求被拒绝,服务器端没有必要给出拒绝的详细理由。
|
||||||
|
|
||||||
**404 Not Found**
|
**404 Not Found**
|
||||||
|
|
||||||
## 5XX ??????????
|
## 5XX 服务器错误
|
||||||
|
|
||||||
**500 Internal Server Error**????????????????????????????
|
**500 Internal Server Error**:服务器正在执行请求时发生错误
|
||||||
|
|
||||||
**503 Service Unavilable**????????????????????????????????????????????????????????????
|
**503 Service Unavilable**:该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
|
||||||
|
|
||||||
# HTTP???
|
# HTTP首部
|
||||||
|
|
||||||
HTTP ??????????????????????????? 4 ????????????Σ?????????Ρ??????????Ρ?????????κ?????????Ρ??????????μ??京???????????????????????????
|
HTTP 报文包含了首部和主体两部分。有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。各种首部字段及其含义如下(不需要全记,仅供查阅):
|
||||||
|
|
||||||
## ?????????
|
## 通用首部字段
|
||||||
|
|
||||||
| ???????? | ??? |
|
| 首部字段名 | 说明 |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| Cache-Control | ??????????? |
|
| Cache-Control | 控制缓存的行为 |
|
||||||
| Connection | ????????? ???????? |
|
| Connection | 逐跳首部、 连接的管理 |
|
||||||
| Date | ???????????????? |
|
| Date | 创建报文的日期时间 |
|
||||||
| Pragma | ??????? |
|
| Pragma | 报文指令 |
|
||||||
| Trailer | ?????????????? |
|
| Trailer | 报文末端的首部一览 |
|
||||||
| Transfer-Encoding | ??????????????????? |
|
| Transfer-Encoding | 指定报文主体的传输编码方式 |
|
||||||
| Upgrade | ?????????Э?? |
|
| Upgrade | 升级为其他协议 |
|
||||||
| Via | ????????????????? |
|
| Via | 代理服务器的相关信息 |
|
||||||
| Warning | ?????? |
|
| Warning | 错误通知 |
|
||||||
|
|
||||||
## ??????????
|
## 请求首部字段
|
||||||
|
|
||||||
| ???????? | ??? |
|
| 首部字段名 | 说明 |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| Accept | ??????????????????? |
|
| Accept | 用户代理可处理的媒体类型 |
|
||||||
| Accept-Charset | ?????????? |
|
| Accept-Charset | 优先的字符集 |
|
||||||
| Accept-Encoding | ???????????? |
|
| Accept-Encoding | 优先的内容编码 |
|
||||||
| Accept-Language | ?????????????????? |
|
| Accept-Language | 优先的语言(自然语言) |
|
||||||
| Authorization | Web?????? |
|
| Authorization | Web认证信息 |
|
||||||
| Expect | ????????????????? |
|
| Expect | 期待服务器的特定行为 |
|
||||||
| From | ?????????????? |
|
| From | 用户的电子邮箱地址 |
|
||||||
| Host | ???????????????? |
|
| Host | 请求资源所在服务器 |
|
||||||
| If-Match | ?????????ETag?? |
|
| If-Match | 比较实体标记(ETag) |
|
||||||
| If-Modified-Since | ?????????????? |
|
| If-Modified-Since | 比较资源的更新时间 |
|
||||||
| If-None-Match | ??????????? If-Match ???? |
|
| If-None-Match | 比较实体标记(与 If-Match 相反) |
|
||||||
| If-Range | ???δ???????????? Byte ???Χ???? |
|
| If-Range | 资源未更新时发送实体 Byte 的范围请求 |
|
||||||
| If-Unmodified-Since | ????????????????If-Modified-Since???? |
|
| If-Unmodified-Since | 比较资源的更新时间(与If-Modified-Since相反) |
|
||||||
| Max-Forwards | ??????????? |
|
| Max-Forwards | 最大传输逐跳数 |
|
||||||
| Proxy-Authorization | ??????????????????????? |
|
| Proxy-Authorization | 代理服务器要求客户端的认证信息 |
|
||||||
| Range | ????????Χ???? |
|
| Range | 实体的字节范围请求 |
|
||||||
| Referer | ???????? URI ????????? |
|
| Referer | 对请求中 URI 的原始获取方 |
|
||||||
| TE | ????????????? |
|
| TE | 传输编码的优先级 |
|
||||||
| User-Agent | HTTP ???????????? |
|
| User-Agent | HTTP 客户端程序的信息 |
|
||||||
|
|
||||||
## ?????????
|
## 响应首部字段
|
||||||
|
|
||||||
| ???????? | ??? |
|
| 首部字段名 | 说明 |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| Accept-Ranges | ??????????Χ???? |
|
| Accept-Ranges | 是否接受字节范围请求 |
|
||||||
| Age | ?????????????????? |
|
| Age | 推算资源创建经过时间 |
|
||||||
| ETag | ??????????? |
|
| ETag | 资源的匹配信息 |
|
||||||
| Location | ????????????????URI |
|
| Location | 令客户端重定向至指定URI |
|
||||||
| Proxy-Authenticate | ?????????????????????? |
|
| Proxy-Authenticate | 代理服务器对客户端的认证信息 |
|
||||||
| Retry-After | ????η?????????????? |
|
| Retry-After | 对再次发起请求的时机要求 |
|
||||||
| Server | HTTP????????????? |
|
| Server | HTTP服务器的安装信息 |
|
||||||
| Vary | ???????????????????? |
|
| Vary | 代理服务器缓存的管理信息 |
|
||||||
| WWW-Authenticate | ??????????????????? |
|
| WWW-Authenticate | 服务器对客户端的认证信息 |
|
||||||
|
|
||||||
## ?????????
|
## 实体首部字段
|
||||||
|
|
||||||
| ???????? | ??? |
|
| 首部字段名 | 说明 |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| Allow | ?????????HTTP???? |
|
| Allow | 资源可支持的HTTP方法 |
|
||||||
| Content-Encoding | ???????????????? |
|
| Content-Encoding | 实体主体适用的编码方式 |
|
||||||
| Content-Language | ??????????????? |
|
| Content-Language | 实体主体的自然语言 |
|
||||||
| Content-Length | ?????????С????λ?? ???? |
|
| Content-Length | 实体主体的大小(单位: 字节) |
|
||||||
| Content-Location | ???????????URI |
|
| Content-Location | 替代对应资源的URI |
|
||||||
| Content-MD5 | ????????????? |
|
| Content-MD5 | 实体主体的报文摘要 |
|
||||||
| Content-Range | ????????λ?÷?Χ |
|
| Content-Range | 实体主体的位置范围 |
|
||||||
| Content-Type | ??????????????? |
|
| Content-Type | 实体主体的媒体类型 |
|
||||||
| Expires | ?????????????????? |
|
| Expires | 实体主体过期的日期时间 |
|
||||||
| Last-Modified | ?????????????????? |
|
| Last-Modified | 资源的最后修改日期时间 |
|
||||||
|
|
||||||
# ???????
|
# 具体应用
|
||||||
|
|
||||||
## Cookie
|
## Cookie
|
||||||
|
|
||||||
HTTP Э????????????????????? HTTP Э?龡?????????????????????????HTTP/1.1 ???? Cookie ?????????????
|
HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。
|
||||||
|
|
||||||
????????????????????? Set-Cookie ??Σ???????????????? Cookie ??????浽??????С????????????????????????ж??? Cookie ????????????а??? Cookie ??Σ??????????????????????????????Cookie ?????????????????????У???????????????
|
服务器会发送的响应报文包含 Set-Cookie 字段,客户端得到该相应后把 Cookie 内容保存到浏览器中。下次再发送请求时,从浏览器中读出 Cookie 值,在请求报文中包含 Cookie 字段,这样服务器就知道客户端的状态信息了。Cookie 状态信息保存在客户端浏览器中,而不是服务器上。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ff17c103-750a-4bb8-9afa-576327023af9.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ff17c103-750a-4bb8-9afa-576327023af9.png)
|
||||||
|
|
||||||
Set-Cookie ??????????????
|
Set-Cookie 字段有以下属性:
|
||||||
|
|
||||||
| ???? | ??? |
|
| 属性 | 说明 |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| NAME=VALUE | ???? Cookie ?????????????????? |
|
| NAME=VALUE | 赋予 Cookie 的名称和其值(必需项) |
|
||||||
| expires=DATE | Cookie ????Ч???????????????????????????????? |
|
| expires=DATE | Cookie 的有效期(若不明确指定则默认为浏览器关闭前为止) |
|
||||||
| path=PATH | ??????????????????? Cookie ????????????????????????????????????? |
|
| path=PATH | 将服务器上的文件目录作为 Cookie 的适用对象(若不指定则默认为文档所在的文件目录) |
|
||||||
| domain=???? | ??? Cookie ??????????????????????????????? Cookie ??????????????? |
|
| domain=域名 | 作为 Cookie 适用对象的域名(若不指定则默认为创建 Cookie 的服务器的域名) |
|
||||||
| Secure | ???? HTTPS ???????????? Cookie |
|
| Secure | 仅在 HTTPS 安全通信时才会发送 Cookie |
|
||||||
| HttpOnly | ?????????? Cookie ????? JavaScript ??????? |
|
| HttpOnly | 加以限制,使 Cookie 不能被 JavaScript 脚本访问 |
|
||||||
|
|
||||||
**Session ?? Cookie ????**
|
**Session 和 Cookie 区别**
|
||||||
|
|
||||||
Session ?????????????????????????Σ???? Session ???????Ψ??????Session ID??????????????????? Session ??????????????????????????? Set-Cookie ??Σ????????????? sid ?????????????????? Session ID?????????????? Cookie ????????????У?????????????????????? Session ID??HTTP ???? Session ?? Cookie ???????????????????????????????? Session ????????????Cookie ?????????
|
Session 是服务器用来跟踪用户的一种手段,每个 Session 都有一个唯一标识:Session ID。当服务器创建了一个 Session 时,给客户端发送的响应报文就包含了 Set-Cookie 字段,其中有一个名为 sid 的键值对,这个键值对就是 Session ID。客户端收到后就把 Cookie 保存在浏览器中,并且之后发送的请求报文都包含 Session ID。HTTP 就是 Session 和 Cookie 这两种方式一起合作来实现跟踪用户状态的,而 Session 用于服务器端,Cookie 用于客户端。
|
||||||
|
|
||||||
**????????? Cookie ?????**
|
**浏览器禁用 Cookie 的情况**
|
||||||
|
|
||||||
????? URL ??д???????? URL ??????? sid=xxx ??
|
会使用 URL 重写技术,在 URL 后面加上 sid=xxx 。
|
||||||
|
|
||||||
**??? Cookie ????????????????????д**
|
**使用 Cookie 实现用户名和密码的自动填写**
|
||||||
|
|
||||||
????????????? Cookie ?ж????????????????????????д??
|
网站脚本会自动从 Cookie 中读取用户名和密码,从而实现自动填写。
|
||||||
|
|
||||||
## ????
|
## 缓存
|
||||||
|
|
||||||
????????淽?????????????????л??????????????????л??档
|
有两种缓存方法:让代理服务器进行缓存和让客户端浏览器进行缓存。
|
||||||
|
|
||||||
Cache-Control ????????????????
|
Cache-Control 用于控制缓存的行为。
|
||||||
|
|
||||||
Cache-Control: no-cache ????????壬?????????????????????????????к??и???????????????????????????????????????????????????????????к??и???????????????????????????л??档
|
Cache-Control: no-cache 有两种含义,如果是客户端向缓存服务器发送的请求报文中含有该指令,表示客户端不想要缓存的资源;如果是源服务器向缓存服务器发送的响应报文中含有该指令,表示缓存服务器不能对资源进行缓存。
|
||||||
|
|
||||||
Expires ??ο????????????????????????????????????????? Cache-Control ????? max-age ???????????????? Expires??????????? max-age ??䶮
|
Expires 字段可以用于告知缓存服务器该资源什么时候会过期。当首部字段 Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处理 max-age 指令。
|
||||||
|
|
||||||
## ???????
|
## 持久连接
|
||||||
|
|
||||||
?????????????????????????? HTML ????????????????? HTML ?????????????????????????????????? HTTP ??????????? TCP ?????????????????????????**???????** ??????????? TCP ?????????ж?? HTTP ????HTTP/1.1????????е??????????????????
|
当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源,如果每进行一次 HTTP 通信就要断开一次 TCP 连接,连接建立和断开的开销会很大。**持久连接** 只需要进行一次 TCP 连接就能进行多次 HTTP 通信。HTTP/1.1开始,所有的连接默认都是持久连接。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c73a0b78-5f46-4d2d-a009-dab2a999b5d8.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c73a0b78-5f46-4d2d-a009-dab2a999b5d8.jpg)
|
||||||
|
|
||||||
????????????? Connection ?????ν??й???HTTP/1.1 ???HTTP ????????????????????? TCP ??????????????????????????????????? Connection: close ??????HTTP/1.1?????????????????????????????????????? Keep-Alive??
|
持久连接需要使用 Connection 首部字段进行管理。HTTP/1.1 开始HTTP 默认是持久化连接的,如果要断开 TCP 连接,需要由客户端或者服务器端提出断开,使用 Connection: close ;而在HTTP/1.1之前默认是非持久化连接的,如果要维持持续连接,需要使用 Keep-Alive。
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????
|
管线化方式可以同时发送多个请求和响应,而不需要发送一个请求然后等待响应之后再发下一个请求。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6943e2af-5a70-4004-8bee-b33d60f39da3.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6943e2af-5a70-4004-8bee-b33d60f39da3.jpg)
|
||||||
|
|
||||||
## ????
|
## 编码
|
||||||
|
|
||||||
????Encoding???????????????????????????????У?gzip??compress??deflate??identity?????? identity ????????????????????
|
编码(Encoding)主要是为了对实体进行压缩。常用的编码有:gzip、compress、deflate、identity,其中 identity 表示不执行压缩的编码格式。
|
||||||
|
|
||||||
## ??鴫??
|
## 分块传输
|
||||||
|
|
||||||
??鴫??Chunked Transfer Coding???????????????飬??????????????档
|
分块传输(Chunked Transfer Coding)可以把数据分割成多块,让浏览器逐步显示页面。
|
||||||
|
|
||||||
## ????????
|
## 多部分对象集合
|
||||||
|
|
||||||
???????????????ж???????????????????????????? boundary ??ζ???????????з???????????????????????Ρ?
|
一份报文主体内可含有多类型的实体同时发送,每个部分之间用 boundary 字段定义的分隔符进行分隔;每个部分都可以有首部字段。
|
||||||
|
|
||||||
???磬???????????????????·????
|
例如,上传多个表单时可以使用如下方式:
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/decb0936-e83c-4a55-840a-fe8aa101ac61.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/decb0936-e83c-4a55-840a-fe8aa101ac61.png)
|
||||||
|
|
||||||
## ??Χ????
|
## 范围请求
|
||||||
|
|
||||||
???????????ж???????????????????????????Χ???????????????????δ????????????????????????????????·????????????
|
如果网络出现中断,服务器只发送了一部分数据,范围请求使得客户端能够只请求未发送的那部分数据,从而避免服务器端重新发送所有数据。
|
||||||
|
|
||||||
???????????????? Range ??Σ?????????????Χ?????? Range : bytes = 5001-10000????????????????????? 206 Partial Content ????
|
在请求报文首部中添加 Range 字段,然后指定请求的范围,例如 Range : bytes = 5001-10000。请求成功的话服务器发送 206 Partial Content 状态。
|
||||||
|
|
||||||
## ????Э??
|
## 内容协商
|
||||||
|
|
||||||
???????Э???????????????????????????????????????????????滹???????档
|
通过内容协商返回最合适的内容,例如根据浏览器的默认语言选择返回中文界面还是英文界面。
|
||||||
|
|
||||||
?漰?????????Σ?Accept??Accept-Charset??Accept-Encoding??Accept-Language??Content-Language??
|
涉及以下首部字段:Accept、Accept-Charset、Accept-Encoding、Accept-Language、Content-Language。
|
||||||
|
|
||||||
## ????????
|
## 虚拟主机
|
||||||
|
|
||||||
??????????????????????????????ж???????????????????????????????????
|
使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器。
|
||||||
|
|
||||||
## ??????????
|
## 通信数据转发
|
||||||
|
|
||||||
**????**
|
**代理**
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????? URL??
|
代理服务器接受客户端的请求,并且转发给其它服务器。代理服务器一般是透明的,不会改变 URL。
|
||||||
|
|
||||||
???????????????????桢?????????????????????????
|
使用代理的主要目的是:缓存、网络访问控制以及记录访问日志。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c07035c3-a9ba-4508-8e3c-d8ae4c6ee9ee.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c07035c3-a9ba-4508-8e3c-d8ae4c6ee9ee.jpg)
|
||||||
|
|
||||||
**????**
|
**网关**
|
||||||
|
|
||||||
????????????????????????????? HTTP ????????Э?????????????????? HTTP ???????????
|
与代理服务器不同的是,网关服务器会将 HTTP 转化为其它协议进行通信,从而其它非 HTTP 服务器的服务。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81375888-6be1-476f-9521-42eea3e3154f.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81375888-6be1-476f-9521-42eea3e3154f.jpg)
|
||||||
|
|
||||||
**???**
|
**隧道**
|
||||||
|
|
||||||
??? SSL ???????Σ???????????????佨???????????????·??
|
使用 SSL 等加密手段,为客户端和服务器之间建立一条安全的通信线路。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/64b95403-d976-421a-8b45-bac89c0b5185.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/64b95403-d976-421a-8b45-bac89c0b5185.jpg)
|
||||||
|
|
||||||
# HTTPs
|
# HTTPs
|
||||||
|
|
||||||
HTTP ?????°????????
|
HTTP 有以下安全性问题:
|
||||||
|
|
||||||
1. ?????????????????????????
|
1. 通信使用明文,内容可能会被窃听;
|
||||||
2. ???????????????????п???????α???
|
2. 不验证通信方的身份,因此有可能遭遇伪装;
|
||||||
3. ???????????????????????п??????????
|
3. 无法证明报文的完整性,所以有可能已遭篡改。
|
||||||
|
|
||||||
HTTPs ????????Э?飬???? HTTP ??? SSL??Secure Socket Layer?????????? SSL ?? TCP ?????????? SSL??HTTPs ????????????????????????
|
HTTPs 并不是新协议,而是 HTTP 先和 SSL(Secure Socket Layer)通信,再由 SSL 和 TCP 通信。通过使用 SSL,HTTPs 提供了加密、认证和完整性保护。
|
||||||
|
|
||||||
## ????
|
## 加密
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????ù?????????м??????????????????????????????????
|
有两种加密方式:对称密钥加密和公开密钥加密。对称密钥加密的加密和解密使用同一密钥,而公开密钥加密使用一对密钥用于加密和解密,分别为公开密钥和私有密钥。公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????
|
对称密钥加密的缺点:无法安全传输密钥;公开密钥加密的缺点:相对来说更耗时。
|
||||||
|
|
||||||
HTTPs ???? **??????????**????ù????????????????????????????????????????????????????У??????????????????
|
HTTPs 采用 **混合的加密机制**,使用公开密钥加密用于传输对称密钥,之后使用对称密钥加密进行通信。(下图中,共享密钥即对称密钥)
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/110b1a9b-87cd-45c3-a21d-824623715b33.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/110b1a9b-87cd-45c3-a21d-824623715b33.jpg)
|
||||||
|
|
||||||
## ???
|
## 认证
|
||||||
|
|
||||||
?????? **???** ???????????????????????й????????????????????????????????????????????????????????????????
|
通过使用 **证书** 来对通信方进行认证。证书中有公开密钥数据,如果可以验证公开密钥的确属于通信方的,那么就可以确定通信方是可靠的。
|
||||||
|
|
||||||
????????????????CA??Certificate
|
数字证书认证机构(CA,Certificate
|
||||||
Authority??????????????飬??????? CA ????????????
|
Authority)颁发的公开密钥证书,可以通过 CA 对其进行验证。
|
||||||
|
|
||||||
???? HTTPs ?????????????????鷢????????????????????е????????????????????????
|
进行 HTTPs 通信时,服务器会把证书发送给客户端,客户端取得其中的公开密钥之后,就可以开始加密过程。
|
||||||
|
|
||||||
??? OpenSSL ?????????????????????????????????????????????????????????????????顣??????????÷????????????????????????????????????????????????????????????
|
使用 OpenSSL 这套开源程序,每个人都可以构建一套属于自己的认证机构,从而自己给自己颁发服务器证书。浏览器在访问该服务器时,会显示“无法确认连接安全性”或“该网站的安全证书存在问题”等警告消息。
|
||||||
|
|
||||||
?????????????????а????????????????????????????????????飬???????????С?
|
客户端证书需要用户自行安装,只有在业务需要非常高安全性时才使用客户端证书,例如网上银行。
|
||||||
|
|
||||||
## ??????
|
## 完整性
|
||||||
|
|
||||||
SSL ????????????????????
|
SSL 提供摘要功能来验证完整性。
|
||||||
|
|
||||||
|
|
642
notes/JVM.md
642
notes/JVM.md
|
@ -1,166 +1,166 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [??????](#??????)
|
* [内存模型](#内存模型)
|
||||||
* [1. ?????????](#1-?????????)
|
* [1. 程序计数器](#1-程序计数器)
|
||||||
* [2. Java ??????](#2-java-??????)
|
* [2. Java 虚拟机栈](#2-java-虚拟机栈)
|
||||||
* [3. ????????](#3-????????)
|
* [3. 本地方法栈](#3-本地方法栈)
|
||||||
* [4. Java ??](#4-java-??)
|
* [4. Java 堆](#4-java-堆)
|
||||||
* [5. ??????](#5-??????)
|
* [5. 方法区](#5-方法区)
|
||||||
* [6. ???????????](#6-???????????)
|
* [6. 运行时常量池](#6-运行时常量池)
|
||||||
* [7. ??????](#7-??????)
|
* [7. 直接内存](#7-直接内存)
|
||||||
* [???????](#???????)
|
* [垃圾收集](#垃圾收集)
|
||||||
* [1. ?ж???????????????](#1-?ж???????????????)
|
* [1. 判断一个对象是否可回收](#1-判断一个对象是否可回收)
|
||||||
* [1.1 ???ü???](#11-???ü???)
|
* [1.1 引用计数](#11-引用计数)
|
||||||
* [1.2 ?????](#12-?????)
|
* [1.2 可达性](#12-可达性)
|
||||||
* [1.3 ????????](#13-????????)
|
* [1.3 引用类型](#13-引用类型)
|
||||||
* [1.3.1 ?????](#131-?????)
|
* [1.3.1 强引用](#131-强引用)
|
||||||
* [1.3.2 ??????](#132-??????)
|
* [1.3.2 软引用](#132-软引用)
|
||||||
* [1.3.3 ??????](#133-??????)
|
* [1.3.3 弱引用](#133-弱引用)
|
||||||
* [1.3.4 ??????](#134-??????)
|
* [1.3.4 虚引用](#134-虚引用)
|
||||||
* [1.3 ???????????](#13-???????????)
|
* [1.3 方法区的回收](#13-方法区的回收)
|
||||||
* [1.4 finalize()](#14-finalize)
|
* [1.4 finalize()](#14-finalize)
|
||||||
* [2. ?????????](#2-?????????)
|
* [2. 垃圾收集算法](#2-垃圾收集算法)
|
||||||
* [2.1 ??? - ?????](#21-???---?????)
|
* [2.1 标记 - 清除算法](#21-标记---清除算法)
|
||||||
* [2.2 ??????](#22-??????)
|
* [2.2 复制算法](#22-复制算法)
|
||||||
* [2.3 ??? - ??????](#23-???---??????)
|
* [2.3 标记 - 整理算法](#23-标记---整理算法)
|
||||||
* [2.4 ????????](#24-????????)
|
* [2.4 分代收集算法](#24-分代收集算法)
|
||||||
* [3. ?????????](#3-?????????)
|
* [3. 垃圾收集器](#3-垃圾收集器)
|
||||||
* [3.1 Serial ?????](#31-serial-?????)
|
* [3.1 Serial 收集器](#31-serial-收集器)
|
||||||
* [3.2 ParNew ?????](#32-parnew-?????)
|
* [3.2 ParNew 收集器](#32-parnew-收集器)
|
||||||
* [3.3 Parallel Scavenge ?????](#33-parallel-scavenge-?????)
|
* [3.3 Parallel Scavenge 收集器](#33-parallel-scavenge-收集器)
|
||||||
* [3.4 Serial Old ?????](#34-serial-old-?????)
|
* [3.4 Serial Old 收集器](#34-serial-old-收集器)
|
||||||
* [3.5 Parallel Old ?????](#35-parallel-old-?????)
|
* [3.5 Parallel Old 收集器](#35-parallel-old-收集器)
|
||||||
* [3.6 CMS ?????](#36-cms-?????)
|
* [3.6 CMS 收集器](#36-cms-收集器)
|
||||||
* [3.7 G1 ?????](#37-g1-?????)
|
* [3.7 G1 收集器](#37-g1-收集器)
|
||||||
* [3.8 ?????????????????](#38-?????????????????)
|
* [3.8 七种垃圾收集器的比较](#38-七种垃圾收集器的比较)
|
||||||
* [4. ??????????????](#4-??????????????)
|
* [4. 内存分配与回收策略](#4-内存分配与回收策略)
|
||||||
* [4.1 ?????? Eden ????](#41-??????-eden-????)
|
* [4.1 优先在 Eden 分配](#41-优先在-eden-分配)
|
||||||
* [4.2 ????????????????](#42-????????????????)
|
* [4.2 大对象直接进入老年代](#42-大对象直接进入老年代)
|
||||||
* [4.3 ??????????????????](#43-??????????????????)
|
* [4.3 长期存活的对象进入老年代](#43-长期存活的对象进入老年代)
|
||||||
* [4.4 ????????????ж?](#44-????????????ж?)
|
* [4.4 动态对象年龄判定](#44-动态对象年龄判定)
|
||||||
* [4.5 ????????](#45-????????)
|
* [4.5 空间分配担保](#45-空间分配担保)
|
||||||
* [4.6 Full GC ?????????](#46-full-gc-?????????)
|
* [4.6 Full GC 的触发条件](#46-full-gc-的触发条件)
|
||||||
* [4.6.1 ???? System.gc()](#461-????-systemgc)
|
* [4.6.1 调用 System.gc()](#461-调用-systemgc)
|
||||||
* [4.6.2 ??????????](#462-??????????)
|
* [4.6.2 老年代空间不足](#462-老年代空间不足)
|
||||||
* [4.6.3 ???????????](#463-???????????)
|
* [4.6.3 空间分配担保失败](#463-空间分配担保失败)
|
||||||
* [4.6.4 JDK 1.7 ?????????????????](#464-jdk-17-?????????????????)
|
* [4.6.4 JDK 1.7 及以前的永久代空间不足](#464-jdk-17-及以前的永久代空间不足)
|
||||||
* [4.6.5 Concurrent Mode Failure](#465-concurrent-mode-failure)
|
* [4.6.5 Concurrent Mode Failure](#465-concurrent-mode-failure)
|
||||||
* [????????](#????????)
|
* [类加载机制](#类加载机制)
|
||||||
* [1 ???????????](#1-???????????)
|
* [1 类的生命周期](#1-类的生命周期)
|
||||||
* [2. ?????????](#2-?????????)
|
* [2. 类初始化时机](#2-类初始化时机)
|
||||||
* [3. ????????](#3-????????)
|
* [3. 类加载过程](#3-类加载过程)
|
||||||
* [3.1 ????](#31-????)
|
* [3.1 加载](#31-加载)
|
||||||
* [3.2 ???](#32-???)
|
* [3.2 验证](#32-验证)
|
||||||
* [3.3 ???](#33-???)
|
* [3.3 准备](#33-准备)
|
||||||
* [3.4 ????](#34-????)
|
* [3.4 解析](#34-解析)
|
||||||
* [3.5 ?????](#35-?????)
|
* [3.5 初始化](#35-初始化)
|
||||||
* [4. ???????](#4-???????)
|
* [4. 类加载器](#4-类加载器)
|
||||||
* [4.1 ???????????](#41-???????????)
|
* [4.1 类与类加载器](#41-类与类加载器)
|
||||||
* [4.2 ???????????](#42-???????????)
|
* [4.2 类加载器分类](#42-类加载器分类)
|
||||||
* [4.3 ?????????](#43-?????????)
|
* [4.3 双亲委派模型](#43-双亲委派模型)
|
||||||
* [JVM ????](#jvm-????)
|
* [JVM 参数](#jvm-参数)
|
||||||
* [GC ???????](#gc-???????)
|
* [GC 优化配置](#gc-优化配置)
|
||||||
* [GC ????????](#gc-????????)
|
* [GC 类型设置](#gc-类型设置)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ??????
|
# 内存模型
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dc695f48-4189-4fc7-b950-ed25f6c80f82.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dc695f48-4189-4fc7-b950-ed25f6c80f82.jpg)
|
||||||
|
|
||||||
????????????????е??????????????????
|
注:白色区域为线程私有的,蓝色区域为线程共享的。
|
||||||
|
|
||||||
## 1. ?????????
|
## 1. 程序计数器
|
||||||
|
|
||||||
?????????е????????????????????????????е??? Native ????????????
|
记录正在执行的虚拟机字节码指令的地址(如果正在执行的是 Native 方法则为空)。
|
||||||
|
|
||||||
## 2. Java ??????
|
## 2. Java 虚拟机栈
|
||||||
|
|
||||||
??? Java ????????е????????????????洢???????????????????????????????????????????????????????????????????????????????? Java ?????????????????????
|
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
|
||||||
|
|
||||||
????????????????????
|
该区域可能抛出以下异常:
|
||||||
|
|
||||||
1. ???????????????????????????? StackOverflowError ????
|
1. 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常;
|
||||||
2. ????ж????????????????????棬????? OutOfMemoryError ????
|
2. 栈进行动态扩展时如果无法申请导足够内存,会抛出 OutOfMemoryError 异常。
|
||||||
|
|
||||||
## 3. ????????
|
## 3. 本地方法栈
|
||||||
|
|
||||||
?? Java ?????????????????????????????????????????????????
|
与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
|
||||||
|
|
||||||
## 4. Java ??
|
## 4. Java 堆
|
||||||
|
|
||||||
???ж???????????????????档
|
所有对象实例都在这里分配内存。
|
||||||
|
|
||||||
??????????????????????????????"GC ?? "???????????????????????÷?????????Java ??????????????????????????????????????? Eden ???From Survivor ???To Survivor ???????
|
这块区域是垃圾收集器管理的主要区域("GC 堆 ")。现在收集器基本都是采用分代收集算法,Java 堆还可以分成:新生代和老年代(新生代还可以分成 Eden 空间、From Survivor 空间、To Survivor 空间等)。
|
||||||
|
|
||||||
???????????棬??????? -Xmx ?? -Xms ???????????????С?????????????????? OutOfMemoryError ????
|
不需要连续内存,可以通过 -Xmx 和 -Xms 来控制动态扩展内存大小,如果动态扩展失败会抛出 OutOfMemoryError 异常。
|
||||||
|
|
||||||
## 5. ??????
|
## 5. 方法区
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????
|
用于存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
|
||||||
|
|
||||||
?? Java ??????????????????棬??????????????????????????????? OutOfMemoryError ????
|
和 Java 堆一样不需要连续的内存,并且可以动态扩展,动态扩展失败一样会抛出 OutOfMemoryError 异常。
|
||||||
|
|
||||||
????????????????????????????????????????????ж??????????????????HotSpot ?????????????????????????????????
|
对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现,HotSpot 虚拟机把它当成永久代来进行垃圾回收。
|
||||||
|
|
||||||
## 6. ???????????
|
## 6. 运行时常量池
|
||||||
|
|
||||||
??????????????????????????
|
运行时常量池是方法区的一部分。
|
||||||
|
|
||||||
??????Class ????е???????????????????????????????????????????????????????
|
类加载后,Class 文件中的常量池(用于存放编译期生成的各种字面量和符号引用)就会被放到这个区域。
|
||||||
|
|
||||||
???????????????ù? String ??? intern() ?????????????????????
|
在运行期间也可以用过 String 类的 intern() 方法将新的常量放入该区域。
|
||||||
|
|
||||||
## 7. ??????
|
## 7. 直接内存
|
||||||
|
|
||||||
?? JDK 1.4 ????????? NIO ???????????????????Channel??????????Buffer???? I/O ?????????????? Native ?????????????????棬??????????洢?? Java ????? DirectByteBuffer ????????????????????в??????????????Щ????????????????????????????? Java ??? Native ????????????????
|
在 JDK 1.4 中新加入了 NIO 类,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
|
||||||
|
|
||||||
# ???????
|
# 垃圾收集
|
||||||
|
|
||||||
?????????????????????????????????????????????е????????????????????????????????????????????????????????????????????????
|
程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收。
|
||||||
|
|
||||||
???????????????? Java ???????????С?
|
垃圾回收主要是针对 Java 堆和方法区进行。
|
||||||
|
|
||||||
## 1. ?ж???????????????
|
## 1. 判断一个对象是否可回收
|
||||||
|
|
||||||
### 1.1 ???ü???
|
### 1.1 引用计数
|
||||||
|
|
||||||
???????????????ü????????????????????????????????? 1???????Ч????????? 1??
|
给对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。
|
||||||
|
|
||||||
???ü???? 0 ????????????
|
引用计数为 0 的对象可被回收。
|
||||||
|
|
||||||
?????????????????????????????ü??????????? 0?????? GC ?????????????
|
两个对象会出现循环引用问题,此时引用计数器永远不为 0,导致 GC 收集器无法回收。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
objA.instance = objB;
|
objA.instance = objB;
|
||||||
objB.instance = objA;
|
objB.instance = objA;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1.2 ?????
|
### 1.2 可达性
|
||||||
|
|
||||||
??? GC Roots ???????????????????????????????????????????????????????
|
通过 GC Roots 作为起始点进行搜索,能够到达到的对象都是都是可用的,不可达的对象可被回收。
|
||||||
|
|
||||||
GC Roots ???????????????
|
GC Roots 一般包含以下内容:
|
||||||
|
|
||||||
1. ????????????????
|
1. 虚拟机栈中引用的对象
|
||||||
2. ???????????????????????
|
2. 方法区中类静态属性引用的对象
|
||||||
3. ???????е????????????
|
3. 方法区中的常量引用的对象
|
||||||
4. ??????????????????
|
4. 本地方法栈中引用的对象
|
||||||
|
|
||||||
### 1.3 ????????
|
### 1.3 引用类型
|
||||||
|
|
||||||
????????????ü??????ж?????????????????????????????????ж?????????????????ж???????????????á??й??
|
无论是通过引用计算算法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判定独享是否存活都与“引用”有关。
|
||||||
|
|
||||||
#### 1.3.1 ?????
|
#### 1.3.1 强引用
|
||||||
|
|
||||||
????????????????????????????????????????????
|
只要强引用存在,垃圾回收器永远不会回收调掉被引用的对象。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Object obj = new Object();
|
Object obj = new Object();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 1.3.2 ??????
|
#### 1.3.2 软引用
|
||||||
|
|
||||||
|
|
||||||
?????????????????????л????
|
非必须引用,内存溢出之前进行回收。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Object obj = new Object();
|
Object obj = new Object();
|
||||||
|
@ -169,14 +169,14 @@ obj = null;
|
||||||
sf.get();
|
sf.get();
|
||||||
```
|
```
|
||||||
|
|
||||||
sf ??? obj ??????????????? sf.get() ??????????????????????????????????????????????????? null??
|
sf 是对 obj 的一个软引用,通过 sf.get() 方法可以取到这个对象,当然,当这个对象被标记为需要回收的对象时,则返回 null;
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????????????????????????????治???????????????????????????????????????Щ?????
|
软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。
|
||||||
|
|
||||||
|
|
||||||
#### 1.3.3 ??????
|
#### 1.3.3 弱引用
|
||||||
|
|
||||||
??????浽???????????????????????????????????????????????????????????????
|
只能生存到下一次垃圾收集发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会被回收。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Object obj = new Object();
|
Object obj = new Object();
|
||||||
|
@ -186,9 +186,9 @@ wf.get();
|
||||||
wf.isEnQueued();
|
wf.isEnQueued();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 1.3.4 ??????
|
#### 1.3.4 虚引用
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????乹??????????????????????????????????????????????????ù?????Ψ????????????????????????????????????????
|
又称为幽灵引用或者幻影引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Object obj = new Object();
|
Object obj = new Object();
|
||||||
|
@ -198,367 +198,367 @@ pf.get();
|
||||||
pf.isEnQueued();
|
pf.isEnQueued();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1.3 ???????????
|
### 1.3 方法区的回收
|
||||||
|
|
||||||
???????????????????????????ж???
|
在方法区主要是对常量池的回收和对类的卸载。
|
||||||
|
|
||||||
?????????????ж???????????
|
常量池的回收和堆中对象回收类似。
|
||||||
|
|
||||||
???ж????????????????????????????????????????????????ж???
|
类的卸载条件很多,需要满足以下三个条件,并且满足了也不一定会被卸载:
|
||||||
|
|
||||||
1. ???????е????????????????????? Java ???в??????????κ??????
|
1. 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
|
||||||
2. ???????? ClassLoader ??????????
|
2. 加载该类的 ClassLoader 已经被回收。
|
||||||
3. ???????? java.lang.Class ??????????κε??????????????????κε???????????????????
|
3. 该类对应的 java.lang.Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
|
||||||
|
|
||||||
??????? -Xnoclassgc ???????????????????ж???
|
可以通过 -Xnoclassgc 参数来控制是否对类进行卸载。
|
||||||
|
|
||||||
???????÷??????????CGLib ?? ByteCode ??????????? JSP ??? OSGo ???????????? ClassLoader ????????????????????ж?????????????????????????
|
在大量使用反射、动态代理、CGLib 等 ByteCode 框架、动态生成 JSP 以及 OSGo 这类频繁自定义 ClassLoader 的场景都需要虚拟机具备类卸载功能,以保证不会出现内存溢出。
|
||||||
|
|
||||||
### 1.4 finalize()
|
### 1.4 finalize()
|
||||||
|
|
||||||
???????????????????????????б????? finalize() ????????????п???????????÷?????????????±????????????????
|
当一个对象可被回收时,如果该对象有必要执行 finalize() 方法,那么就有可能可能通过在该方法中让对象重新被引用,从而实现自救。
|
||||||
|
|
||||||
finalize() ???? C++ ???鹹??????????????????????????????? try-finally ????????????????????÷??????д?????????????????????????????????????????ò????á?
|
finalize() 类似 C++ 的虚构函数,用来做关闭外部资源等工作。但是 try-finally 等方式可以做的更好,并且该方法运行代价高昂,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。
|
||||||
|
|
||||||
## 2. ?????????
|
## 2. 垃圾收集算法
|
||||||
|
|
||||||
### 2.1 ??? - ?????
|
### 2.1 标记 - 清除算法
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg)
|
||||||
|
|
||||||
???????????????б???????????
|
将需要回收的对象进行标记,然后清除。
|
||||||
|
|
||||||
????
|
不足:
|
||||||
|
|
||||||
1. ???????????Ч???????
|
1. 标记和清除过程效率都不高
|
||||||
2. ????????????
|
2. 会产生大量碎片
|
||||||
|
|
||||||
???????????????????и????
|
之后的算法都是基于该算法进行改进。
|
||||||
|
|
||||||
### 2.2 ??????
|
### 2.2 复制算法
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg)
|
||||||
|
|
||||||
????滮?????С???????飬?????????????飬??????????????????????????????????????棬????????ù??????????????????
|
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
|
||||||
|
|
||||||
??????????????????????
|
主要不足是只使用了内存的一半。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????滮?????С???????飬???????????? Eden ?????????С?? Survior ????????? Eden ??????????? Survivor???????????? Eden ?? Survivor ?л???????????????????????? Survivor ????????????? Eden ?? Survivor??HotSpot ??????? Eden ?? Survivor ???С???????? 8:1?????????????????? 90 %???????λ????ж??? 10% ????????????? Survivor ?????????????????????????????з????????????????????????
|
现在的商业虚拟机都采用这种收集算法来回收新生代,但是并不是将内存划分为大小相等的两块,而是分为一块较大的 Eden 空间和两块较小的 Survior 空间,每次使用 Eden 空间和其中一块 Survivor。在回收时,将 Eden 和 Survivor 中还存活着的对象一次性复制到另一块 Survivor 空间上,最后清理 Eden 和 Survivor。HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了内存的利用率达到 90 %。如果每次回收有多于 10% 的对象存活,那么一块 Survivor 空间就不够用了,需要依赖于老年代进行分配担保,也就是借用老年代的空间。
|
||||||
|
|
||||||
### 2.3 ??? - ??????
|
### 2.3 标记 - 整理算法
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg)
|
||||||
|
|
||||||
?????д??????????????????????????????????????档
|
让所有存活的对象都向一段移动,然后直接清理掉端边界以外的内存。
|
||||||
|
|
||||||
### 2.4 ????????
|
### 2.4 分代收集算法
|
||||||
|
|
||||||
????????????????÷?????????????????????????????????????????????????滮??????飬????????????????????
|
现在的商业虚拟机采用分代收集算法,它使用了前面介绍的几种收集算法,根据对象存活周期将内存划分为几块,不同块采用适当的收集算法。
|
||||||
|
|
||||||
??? Java ???????????????????
|
一般将 Java 堆分为新生代和老年代。
|
||||||
|
|
||||||
1. ????????????????
|
1. 新生代使用:复制算法
|
||||||
2. ???????????? - ???? ???? ??? - ???? ????
|
2. 老年代使用:标记 - 清理 或者 标记 - 整理 算法。
|
||||||
|
|
||||||
## 3. ?????????
|
## 3. 垃圾收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg)
|
||||||
|
|
||||||
?????? HotSpot ??????е? 7 ?????????????????????????????????????á?
|
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
|
||||||
|
|
||||||
### 3.1 Serial ?????
|
### 3.1 Serial 收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg)
|
||||||
|
|
||||||
??????????????????????ζ????????????????????????????????????????????????????????????????????????????????????????????????
|
它是单线程的收集器,不仅意味着只会使用一个线程进行垃圾收集工作,更重要的是它在进行垃圾收集时,必须暂停所有其他工作线程,往往造成过长的等待时间。
|
||||||
|
|
||||||
???????????Ч????????? CPU ??????????????????????????????????????????????Ч???
|
它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率。
|
||||||
|
|
||||||
?? Client ??ó????У?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
在 Client 应用场景中,分配给虚拟机管理的内存一般来说不会很大,该收集器收集几十兆甚至一两百兆的新生代停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿是可以接受的。
|
||||||
|
|
||||||
### 3.2 ParNew ?????
|
### 3.2 ParNew 收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg)
|
||||||
|
|
||||||
???? Serial ???????????汾??
|
它是 Serial 收集器的多线程版本。
|
||||||
|
|
||||||
?? Server ??????????????????????????????????????????????????? Serial ???????????????? CMS ?????????????
|
是 Server 模式下的虚拟机首选新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作。
|
||||||
|
|
||||||
???????????????? CPU ???????????????? -XX:ParallelGCThreads ?????????????????
|
默认开始的线程数量与 CPU 数量相同,可以使用 -XX:ParallelGCThreads 参数来设置线程数。
|
||||||
|
|
||||||
### 3.3 Parallel Scavenge ?????
|
### 3.3 Parallel Scavenge 收集器
|
||||||
|
|
||||||
????е????????????
|
是并行的多线程收集器。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? CPU ??????????????????????????????
|
其它收集器关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,它被称为“吞吐量优先”收集器。这里的吞吐量指 CPU 用于运行用户代码的时间占总时间的比值。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????顣????????????????Ч??????? CPU ?????????????????????????????????????????????????????
|
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????? -XX:MaxGCPauseMillis ??????????????????????С?? -XX:GCTimeRatio ???????????? 0 ??С?? 100 ???????????????????????????????????????????????????????????????С????????????????????????????????
|
提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间 -XX:MaxGCPauseMillis 参数以及直接设置吞吐量大小的 -XX:GCTimeRatio 参数(值为大于 0 且小于 100 的整数)。缩短停顿时间是以牺牲吞吐量和新生代空间来换取的:新生代空间变小,垃圾回收变得频繁,导致吞吐量下降。
|
||||||
|
|
||||||
????????????? -XX:+UseAdaptiveSizePolicy?????????????????????????????????????????????С??-Xmn????Eden ?? Survivor ?????????-XX:SurvivorRatio?????????????????????-XX:PretenureSizeThreshold???????????????????????????????????????????????????????????Щ???????????????????????????????????????????? GC ??????????????GC Ergonomics??????????????????????? ParNew ?????????????????
|
还提供了一个参数 -XX:+UseAdaptiveSizePolicy,这是一个开关参数,打开参数后,就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种方式称为 GC 自适应的调节策略(GC Ergonomics)。自适应调节策略也是它与 ParNew 收集器的一个重要区别。
|
||||||
|
|
||||||
### 3.4 Serial Old ?????
|
### 3.4 Serial Old 收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg)
|
||||||
|
|
||||||
Serial Old ?? Serial ?????????????汾?????? Client ????????????á???????? Server ??????????????????
|
Serial Old 是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途:
|
||||||
|
|
||||||
1. ?? JDK 1.5 ??????汾??Parallel Old ????????????? Parallel Scavenge ???????????á?
|
1. 在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。
|
||||||
2. ??? CMS ????????????????????????? Concurrent Mode Failure ???á?
|
2. 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。
|
||||||
|
|
||||||
### 3.5 Parallel Old ?????
|
### 3.5 Parallel Old 收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg)
|
||||||
|
|
||||||
?? Parallel Scavenge ?????????????汾??
|
是 Parallel Scavenge 收集器的老年代版本。
|
||||||
|
|
||||||
?????????????? CPU ??????е?????????????????? Parallel Scavenge ?? Parallel Old ???????
|
在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。
|
||||||
|
|
||||||
### 3.6 CMS ?????
|
### 3.6 CMS 收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg)
|
||||||
|
|
||||||
CMS??Concurrent Mark Sweep?????? Mark Sweep ?????????????? ??? - ??? ???????
|
CMS(Concurrent Mark Sweep),从 Mark Sweep 可以知道它是基于 标记 - 清除 算法实现的。
|
||||||
|
|
||||||
??????????????????
|
特点:并发收集、低停顿。
|
||||||
|
|
||||||
???????????????
|
分为以下四个流程:
|
||||||
|
|
||||||
1. ??????????????????? GC Roots ???????????????????????????
|
1. 初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿。
|
||||||
2. ???????????? GC Roots Tracing ??????????????????????к???????????????
|
2. 并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿。
|
||||||
3. ???±?????????????????????????????????????????±?????????????????????????????????
|
3. 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿。
|
||||||
4. ??????????????????
|
4. 并发清除:不需要停顿。
|
||||||
|
|
||||||
???????????к????????????????????????У??????????????????????????????????????????
|
在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。
|
||||||
|
|
||||||
???????????
|
具有以下缺点:
|
||||||
|
|
||||||
1. ?? CPU ??????С?CMS ??????????????????? (CPU ???? + 3) / 4???? CPU ???? 4 ?????CMS ??????????????????ú????????? CPU ???????????????????????????????????????????????????????????????????? 50%?????????????????????????????????????????????????????? CPU ?????????
|
1. 对 CPU 资源敏感。CMS 默认启动的回收线程数是 (CPU 数量 + 3) / 4,当 CPU 不足 4 个时,CMS 对用户程序的影响就可能变得很大,如果本来 CPU 负载就比较大,还要分出一半的运算能力去执行收集器线程,就可能导致用户程序的执行速度忽然降低了 50%,其实也让人无法接受。并且低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率变低。
|
||||||
|
|
||||||
2. ??????????????????????????????????????????????????????????????????????????????????????????????????????????CMS ????????????д????????????????????? GC ?????????????????????????????????????????????????????????????????????????У??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????á???????? -XX:CMSInitiatingOccupancyFraction ???????????????????????????????JDK 1.5 ???????????? 68?????????????????? 68% ?????????????????????????????????????????????????????棬????????? Concurrent Mode Failure?????????????????????????????? Serial Old ??????????????????????????????
|
2. 无法处理浮动垃圾。由于并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生。这一部分垃圾出现在标记过程之后,CMS 无法在当次收集中处理掉它们,只好留到下一次 GC 时再清理掉,这一部分垃圾就被称为“浮动垃圾”。也是由于在垃圾收集阶段用户线程还需要运行,那也就还需要预留有足够的内存空间给用户线程使用,因此它不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。可以使用 -XX:CMSInitiatingOccupancyFraction 的值来改变触发收集器工作的内存占用百分比,JDK 1.5 默认设置下该值为 68,也就是当老年代使用了 68% 的空间之后会触发收集器工作。如果该值设置的太高,导致浮动垃圾无法保存,那么就会出现 Concurrent Mode Failure,此时虚拟机将启动后备预案:临时启用 Serial Old 收集器来重新进行老年代的垃圾收集。
|
||||||
|
|
||||||
3. ??? - ??????????????????????????????????鷳?????????????????????????????????????????????????????ò??????????? Full GC??
|
3. 标记 - 清除算法导致的空间碎片,给大对象分配带来很大麻烦,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前出发一次 Full GC。
|
||||||
|
|
||||||
### 3.7 G1 ?????
|
### 3.7 G1 收集器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg)
|
||||||
|
|
||||||
G1??Garbage-First??????????????????????????????????????????????????????????????????HotSpot ?????????????????????????????δ???????滻?? JDK 1.5 ?з????? CMS ???????
|
G1(Garbage-First)收集器是当今收集器技术发展最前沿的成果之一,它是一款面向服务端应用的垃圾收集器,HotSpot 开发团队赋予它的使命是(在比较长期的)未来可以替换掉 JDK 1.5 中发布的 CMS 收集器。
|
||||||
|
|
||||||
??????????
|
具备如下特点:
|
||||||
|
|
||||||
- ??????????????????? CPU ???????????????????? CPU ????????????
|
- 并行与并发:能充分利用多 CPU 环境下的硬件优势,使用多个 CPU 来缩短停顿时间;
|
||||||
- ??????????????????????????????????????????????????????????????? GC ?????????????ò?????????????????????????????????????? GC ???????????????????Ч????
|
- 分代收集:分代概念依然得以保留,虽然它不需要其它收集器配合就能独立管理整个 GC 堆,但它能够采用不同方式去处理新创建的对象和已存活一段时间、熬过多次 GC 的旧对象来获取更好的收集效果。
|
||||||
- ????????????????????????? - ??????????????????????????? Region ???????????????????????????????ζ????????????????????????
|
- 空间整合:整体来看是基于“标记 - 整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片。
|
||||||
- ??????????????????? CMS ?????????????????????? G1 ?? CMS ??????????? G1 ???????????????????????????????????????????????????????????? M ???????????????????? GC ???????ó??? N ??????????????? Java??RTSJ??????????????????????
|
- 可预测的停顿:这是它相对 CMS 的一大优势,降低停顿时间是 G1 和 CMS 共同的关注点,但 G1 除了降低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在 GC 上的时间不得超过 N 毫秒,这几乎已经是实时 Java(RTSJ)的垃圾收集器的特征了。
|
||||||
|
|
||||||
?? G1 ???????????????????????Χ???????????????????????????? G1 ????????????Java ?????沼??????????????к??????????? Java ???????????С???????????Region?????????????????????????????????????????????????????????????????????????? Region???????????????????
|
在 G1 之前的其他收集器进行收集的范围都是整个新生代或者老生代,而 G1 不再是这样,Java 堆的内存布局与其他收集器有很大区别,将整个 Java 堆划分为多个大小相等的独立区域(Region)。虽然还保留新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,而都是一部分 Region(不需要连续)的集合。
|
||||||
|
|
||||||
??????????????????????????????????????м????????????? Java ???н??????????????????????????? Region ??????????????????С???????????????С??????????????????????????????????????б???θ??????????????????????????? Region????????? Garbage-First ??????????????????? Region ???????????????????????????????????????????????????????????????????Ч???
|
之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个 Java 堆中进行全区域的垃圾收集。它跟踪各个 Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region(这也就是 Garbage-First 名称的来由)。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了它在有限的时间内可以获取尽可能高的收集效率。
|
||||||
|
|
||||||
Region ????????????????????????????? Region ?У??????????? Java ???????????????ù?????????????????????????????????????????? Java ???????????????????? GC Ч???????????????????????????????? Region ?????????????????? Remembered Set????????????????? Reference ????????????д??????????????? Write Barrier ????ж?д????????? Reference ????????????????? Region ??У???????????? CardTable ???????????????????????????????? Region ?? Remembered Set ??С?????????????????? GC ??????????Χ?м??? Remembered Set ????????????????????????????
|
Region 不可能是孤立的,一个对象分配在某个 Region 中,可以与整个 Java 堆任意的对象发生引用关系。在做可达性分析确定对象是否存活的时候,需要扫描整个 Java 堆才能保证准确性,这显然是对 GC 效率的极大伤害。为了避免全堆扫描的发生,每个 Region 都维护了一个与之对应的 Remembered Set。虚拟机发现程序在对 Reference 类型的数据进行写操作时,会产生一个 Write Barrier 暂时中断写操作,检查 Reference 引用的对象是否处于不同的 Region 之中,如果是,便通过 CardTable 把相关引用信息记录到被引用对象所属的 Region 的 Remembered Set 之中。当进行内存回收时,在 GC 根节点的枚举范围中加入 Remembered Set 即可保证不对全堆扫描也不会有遗漏。
|
||||||
|
|
||||||
???????????? Remembered Set ???????G1 ??????????????????????????????裺
|
如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:
|
||||||
|
|
||||||
1. ??????
|
1. 初始标记
|
||||||
2. ???????
|
2. 并发标记
|
||||||
3. ??????????????????????????????????????????????±??????????????????????????????????????仯????????? Remembered Set Logs ???棬????????????? Remembered Set Logs ?????????? Remembered Set ?С?????????????????????????С?
|
3. 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。
|
||||||
4. ??????????????? Region ?е???????????????????????????????? GC ????????????????????????????????????????????????????У?????????????????? Region??????????????????????????????????????????Ч???
|
4. 筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿是时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。
|
||||||
|
|
||||||
### 3.8 ?????????????????
|
### 3.8 七种垃圾收集器的比较
|
||||||
|
|
||||||
| ????? | ???С????? or ???? | ?????? / ????? | ?? | ??? | ???ó??? |
|
| 收集器 | 串行、并行 or 并发 | 新生代 / 老年代 | 算法 | 目标 | 适用场景 |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| **Serial** | ???? | ?????? | ?????? | ?????????? | ?? CPU ??????? Client ?? |
|
| **Serial** | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单 CPU 环境下的 Client 模式 |
|
||||||
| **Serial Old** | ???? | ????? | ??? - ???? | ?????????? | ?? CPU ??????? Client ????CMS ?????? |
|
| **Serial Old** | 串行 | 老年代 | 标记 - 整理 | 响应速度优先 | 单 CPU 环境下的 Client 模式、CMS 的后备预案 |
|
||||||
| **ParNew** | ???? | ?????? | ?????? | ?????????? | ?? CPU ??????? Server ?????? CMS ??? |
|
| **ParNew** | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多 CPU 环境时在 Server 模式下与 CMS 配合 |
|
||||||
| **Parallel Scavenge** | ???? | ?????? | ?????? | ?????????? | ????????????????????????? |
|
| **Parallel Scavenge** | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
|
||||||
| **Parallel Old** | ???? | ????? | ??? - ???? | ?????????? | ????????????????????????? |
|
| **Parallel Old** | 并行 | 老年代 | 标记 - 整理 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
|
||||||
| **CMS** | ???? | ????? | ??? - ??? | ?????????? | ?????????????? B/S ?????????? Java ??? |
|
| **CMS** | 并发 | 老年代 | 标记 - 清除 | 响应速度优先 | 集中在互联网站或 B/S 系统服务端上的 Java 应用 |
|
||||||
| **G1** | ???? | both | ??? - ???? + ?????? | ?????????? | ?????????????????滻 CMS |
|
| **G1** | 并发 | both | 标记 - 整理 + 复制算法 | 响应速度优先 | 面向服务端应用,将来替换 CMS |
|
||||||
|
|
||||||
## 4. ??????????????
|
## 4. 内存分配与回收策略
|
||||||
|
|
||||||
### 4.1 ?????? Eden ????
|
### 4.1 优先在 Eden 分配
|
||||||
|
|
||||||
??????????????????????? Eden ???????? Eden ?????????????? Minor GC??
|
大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC;
|
||||||
|
|
||||||
### 4.2 ????????????????
|
### 4.2 大对象直接进入老年代
|
||||||
|
|
||||||
?? -XX:PretenureSizeThreshold ????????????????????????????????????? Eden ???? Survivor ???????????渴???
|
提供 -XX:PretenureSizeThreshold 参数,大于此值的对象直接在老年代分配,避免在 Eden 区和 Survivor 区之间的大量内存复制;
|
||||||
### 4.3 ??????????????????
|
### 4.3 长期存活的对象进入老年代
|
||||||
|
|
||||||
JVM ?????????????????????? Minor GC ????????? Survivor ????????????? Survivor ????????? 1?????????? Minor GC ??????????????? 1???????????????????????????????? 15 ????? -XX:MaxTenuringThreshold ???????
|
JVM 为对象定义年龄计数器,经过 Minor GC 依然存活且被 Survivor 区容纳的,移动到 Survivor 区,年龄加 1,每经历一次 Minor GC 不被清理则年龄加 1,增加到一定年龄则移动到老年区(默认 15 岁,通过 -XX:MaxTenuringThreshold 设置);
|
||||||
|
|
||||||
|
|
||||||
### 4.4 ????????????ж?
|
### 4.4 动态对象年龄判定
|
||||||
|
|
||||||
?? Survivor ????????????ж????С?????? Survivor ???????????????????????????????????????????
|
若 Survivor 区中同年龄所有对象大小总和大于 Survivor 空间一半,则年龄大于等于该年龄的对象可以直接进入老年代;
|
||||||
|
|
||||||
### 4.5 ????????
|
### 4.5 空间分配担保
|
||||||
|
|
||||||
????? Minor GC ????JVM ?????????????????????????????????????ж?????????????? Minor GC ???????????????????????????????????????????????ν????????????????????С???????????? Minor GC??С???????? Full GC??
|
在发生 Minor GC 之前,JVM 先检查老年代最大可用连续空间是否大于新生代所有对象总空间,成立的话 Minor GC 确认是安全的;否则继续检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,大于的话进行 Minor GC,小于的话进行 Full GC。
|
||||||
|
|
||||||
## 4.6 Full GC ?????????
|
## 4.6 Full GC 的触发条件
|
||||||
|
|
||||||
???? Minor GC?????????????????? Eden ???????????????????? Minor GC???? Full GC ?????????????????????
|
对于 Minor GC,其触发条件非常简单,当 Eden 区空间满时,就将触发一次 Minor GC。而 Full GC 则相对复杂,有以下条件:
|
||||||
|
|
||||||
### 4.6.1 ???? System.gc()
|
### 4.6.1 调用 System.gc()
|
||||||
|
|
||||||
??????????????? JVM ???? Full GC??????????????????????????????????? Full GC????????? Full GC ????????????????Ъ???????????????????????????????????????????????????????????棬????? -XX:+ DisableExplicitGC ????? RMI ???? System.gc()??
|
此方法的调用是建议 JVM 进行 Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加 Full GC 的频率,也即增加了间歇性停顿的次数。因此强烈建议能不使用此方法就不要使用,让虚拟机自己去管理它的内存,可通过 -XX:+ DisableExplicitGC 来禁止 RMI 调用 System.gc()。
|
||||||
|
|
||||||
### 4.6.2 ??????????
|
### 4.6.2 老年代空间不足
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????? Full GC ??????????????????????? Java.lang.OutOfMemoryError: Java heap space ????????????????????? Full GC??????????????????????? Minor GC ??α????????????????????????????估??????????????????顣
|
老年代空间不足的常见场景为前文所讲的大对象直接进入老年代、长期存活的对象进入老年代等,当执行 Full GC 后空间仍然不足,则抛出如下错误: Java.lang.OutOfMemoryError: Java heap space 为避免以上两种状况引起的 Full GC,调优时应尽量做到让对象在 Minor GC 阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
|
||||||
|
|
||||||
### 4.6.3 ???????????
|
### 4.6.3 空间分配担保失败
|
||||||
|
|
||||||
?????????? Minor GC ???????????????????????????????? HandlePromotionFailure ????????????? Full GC??
|
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果出现了 HandlePromotionFailure 担保失败,则会触发 Full GC。
|
||||||
|
|
||||||
### 4.6.4 JDK 1.7 ?????????????????
|
### 4.6.4 JDK 1.7 及以前的永久代空间不足
|
||||||
|
|
||||||
?? JDK 1.7 ???????HotSpot ??????е??????????????????????????д?????Щ class ??????????????????????????????????????????????????????????????Permanet Generation ????????????δ????????? CMS GC ????????????? Full GC????????? Full GC ?????????????? JVM ?????????????????java.lang.OutOfMemoryError: PermGen space ????? PermGen ?????? Full GC ????????????????? PermGen ????????? CMS GC??
|
在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 class 的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation 可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么 JVM 会抛出如下错误信息:java.lang.OutOfMemoryError: PermGen space 为避免 PermGen 占满造成 Full GC 现象,可采用的方法为增大 PermGen 空间或转为使用 CMS GC。
|
||||||
|
|
||||||
?? JDK 1.8 ?????????滻?????????????????????????????????棬??????????? Full GC ????????????
|
在 JDK 1.8 中用元空间替换了永久代作为方法区的实现,元空间是本地内存,因此减少了一种 Full GC 触发的可能性。
|
||||||
|
|
||||||
### 4.6.5 Concurrent Mode Failure
|
### 4.6.5 Concurrent Mode Failure
|
||||||
|
|
||||||
??? CMS GC ??????????ж????????????????????????????????????????? CMS GC ??????????????????????????????? Full GC??????? Concurrent Mode Failure ????????? Full GC??
|
执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足(有时候“空间不足”是 CMS GC 时当前的浮动垃圾过多导致暂时性的空间不足触发 Full GC),便会报 Concurrent Mode Failure 错误,并触发 Full GC。
|
||||||
|
|
||||||
# ????????
|
# 类加载机制
|
||||||
|
|
||||||
????????????????????
|
类是在运行期间动态加载的。
|
||||||
|
|
||||||
## 1 ???????????
|
## 1 类的生命周期
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg)
|
||||||
|
|
||||||
???????? 7 ????Σ?
|
包括以下 7 个阶段:
|
||||||
|
|
||||||
- **?????Loading??**
|
- **加载(Loading)**
|
||||||
- **?????Verification??**
|
- **验证(Verification)**
|
||||||
- **?????Preparation??**
|
- **准备(Preparation)**
|
||||||
- **??????Resolution??**
|
- **解析(Resolution)**
|
||||||
- **???????Initialization??**
|
- **初始化(Initialization)**
|
||||||
- ????Using??
|
- 使用(Using)
|
||||||
- ж???Unloading??
|
- 卸载(Unloading)
|
||||||
|
|
||||||
???н??????????Щ???????????????????????????????????? Java ???????
|
其中解析过程在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 的动态绑定。
|
||||||
|
|
||||||
## 2. ?????????
|
## 2. 类初始化时机
|
||||||
|
|
||||||
??????淶?в????????????????м????????淶???涨?????????????????????????????г??????( ???????????????????????? )
|
虚拟机规范中并没有强制约束何时进行加载,但是规范严格规定了有且只有下列五种情况必须对类进行初始化:( 加载、验证、准备都会随着发生 )
|
||||||
|
|
||||||
1. ???? new??getstatic??putstatic??invokestatic ????????????????????????н??й?????????????????????????????????????? 4 ??????????????? new ????????????????????????????????????Σ??? final ???Ρ???????????????????????????γ????????????????????????????????
|
1. 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则必须先触发其初始化。最常见的生成这 4 条指令的场景是:使用 new 关键字实例化对象的时候;读取或设置一个类的静态字段(被 final 修饰、已在编译器把结果放入常量池的静态字段除外)的时候;以及调用一个类的静态方法的时候。
|
||||||
|
|
||||||
2. ??? java.lang.reflect ?????????????з?????????????????н??г????????????????????????
|
2. 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。
|
||||||
|
|
||||||
3. ????????????????????????丸????н??й???????????????????丸?????????
|
3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
|
||||||
|
|
||||||
4. ?????????????????????????????е????????? main() ?????????????????????????????????
|
4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),虚拟机会先初始化这个主类;
|
||||||
|
|
||||||
5. ????? jdk1.7 ???????????????????? java.lang.invoke.MethodHandle ?????????????? REF_getStatic, REF_putStatic, REF_invokeStatic ???????????????????????????????????н??й??????????????????????????
|
5. 当使用 jdk1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果为 REF_getStatic, REF_putStatic, REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化;
|
||||||
|
|
||||||
???? 5 ??????е????????????????????????á??????????????????????????????????????????????á??????????????????????
|
以上 5 种场景中的行为称为对一个类进行主动引用。除此之外,所有引用类的方式都不会触发初始化,称为被动引用。被动引用的常见例子包括:
|
||||||
|
|
||||||
1\. ???????????????????Σ?????????????????
|
1\. 通过子类引用父类的静态字段,不会导致子类初始化。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
System.out.println(SubClass.value); // value ????? SuperClass ?ж???
|
System.out.println(SubClass.value); // value 字段在 SuperClass 中定义
|
||||||
```
|
```
|
||||||
|
|
||||||
2\. ??????鶨????????????????????????????ù?????????????г???????????????????????????????????????? Object ?????????а????????????????????
|
2\. 通过数组定义来引用类,不会触发此类的初始化。该过程会对数组类进行初始化,数组类是一个由虚拟机自动生成的、直接继承自 Object 的子类,其中包含了数组的属性和方法。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
SuperClass[] sca = new SuperClass[10];
|
SuperClass[] sca = new SuperClass[10];
|
||||||
```
|
```
|
||||||
|
|
||||||
3\. ??????????λ????????????????У??????????????????????峣?????????????????峣?????????????
|
3\. 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
System.out.println(ConstClass.HELLOWORLD);
|
System.out.println(ConstClass.HELLOWORLD);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. ????????
|
## 3. 类加载过程
|
||||||
|
|
||||||
???????????????????????????????? 5 ????Ρ?
|
包含了加载、验证、准备、解析和初始化这 5 个阶段。
|
||||||
|
|
||||||
### 3.1 ????
|
### 3.1 加载
|
||||||
|
|
||||||
?????????????????Σ???????????
|
加载是类加载的一个阶段,注意不要混淆。
|
||||||
|
|
||||||
?????????????????????
|
加载过程完成以下三件事:
|
||||||
|
|
||||||
1. ????????????????????????????????????????
|
1. 通过一个类的全限定名来获取定义此类的二进制字节流。
|
||||||
2. ????????????????????洢????????????????????洢????
|
2. 将这个字节流所代表的静态存储结构转化为方法区的运行时存储结构。
|
||||||
3. ???????????????????????? Class ??????????????????????????????????
|
3. 在内存中生成一个代表这个类的 Class 对象,作为方法区这个类的各种数据的访问入口。
|
||||||
|
|
||||||
???ж??????????????????·???л????
|
其中二进制字节流可以从以下方式中获取:
|
||||||
|
|
||||||
- ?? ZIP ???????????????????????? JAR??EAR??WAR ??????????
|
- 从 ZIP 包读取,这很常见,最终成为日后 JAR、EAR、WAR 格式的基础。
|
||||||
- ???????л?????????????????????? Applet??
|
- 从网络中获取,这种场景最典型的应用是 Applet。
|
||||||
- ???????????????????????????????????????????? java.lang.reflect.Proxy ?У????????? ProxyGenerator.generateProxyClass ????????????????????
|
- 运行时计算生成,这种场景使用得最多得就是动态代理技术,在 java.lang.reflect.Proxy 中,就是用了 ProxyGenerator.generateProxyClass 的代理类的二进制字节流。
|
||||||
- ??????????????????????? JSP ???????? JSP ??????????? Class ??
|
- 由其他文件生成,典型场景是 JSP 应用,即由 JSP 文件生成对应的 Class 类。
|
||||||
- ????????????????????????????????Щ?м???????????? SAP Netweaver?????????????????????????????????????????????
|
- 从数据库读取,这种场景相对少见,例如有些中间件服务器(如 SAP Netweaver)可以选择把程序安装到数据库中来完成程序代码在集群间的分发。
|
||||||
...
|
...
|
||||||
|
|
||||||
### 3.2 ???
|
### 3.2 验证
|
||||||
|
|
||||||
??? Class ???????????а??????????????????????????????Σ????????????????
|
确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
|
||||||
|
|
||||||
????????? 4 ????Σ?
|
主要有以下 4 个阶段:
|
||||||
|
|
||||||
1. ?????????
|
1. 文件格式验证
|
||||||
2. ???????????????????????????????????????
|
2. 元数据验证(对字节码描述的信息进行语义分析)
|
||||||
3. ??????????????????????????????????????????????????????????????????????????У???????
|
3. 字节码验证(通过数据流和控制流分析,确保程序语义是合法、符合逻辑的,将对类的方法体进行校验分析)
|
||||||
4. ???????????
|
4. 符号引用验证
|
||||||
|
|
||||||
### 3.3 ???
|
### 3.3 准备
|
||||||
|
|
||||||
???????? static ???ε????????????????????????沢???ó????????????????????档
|
类变量是被 static 修饰的变量,准备阶段为类变量分配内存并设置初始值,使用的是方法区的内存。
|
||||||
|
|
||||||
????????????????η?????棬???????????????????????????????? Java ???С?
|
实例变量不会在这阶段分配内存,它将会在对象实例化时随着对象一起分配在 Java 堆中。
|
||||||
|
|
||||||
???????? 0 ????????????????? value ???????? 0 ?????? 123??
|
初始值一般为 0 值,例如下面的类变量 value 被初始化为 0 而不是 123。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static int value = 123;
|
public static int value = 123;
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????????????????г??????????????? 0??
|
如果类变量是常量,那么会按照表达式来进行初始化,而不是赋值为 0。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static final int value = 123;
|
public static final int value = 123;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.4 ????
|
### 3.4 解析
|
||||||
|
|
||||||
?????????????????滻?????????????
|
将常量池的符号引用替换为直接引用的过程。
|
||||||
|
|
||||||
### 3.5 ?????
|
### 3.5 初始化
|
||||||
|
|
||||||
???????μ??????????????? <clinit>() ??????????
|
初始化阶段即虚拟机执行类构造器 <clinit>() 方法的过程。
|
||||||
|
|
||||||
???????Σ?????????????????????????????????????Σ?????????????????????????????????????????????????
|
在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
|
||||||
|
|
||||||
<clinit>() ???????????????
|
<clinit>() 方法具有以下特点:
|
||||||
|
|
||||||
- ???????????????????????????????????????????飨static{} ?飩?е???????????????????????????????????????г??????????????????????????????????????????????????????????????????????????????????????????????????
|
- 是由编译器自动收集类中所有类变量的赋值动作和静态语句块(static{} 块)中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Test {
|
public class Test {
|
||||||
static {
|
static {
|
||||||
i = 0; // ????????????????????????
|
i = 0; // 给变量赋值可以正常编译通过
|
||||||
System.out.print(i); // ????????????????????????á?
|
System.out.print(i); // 这句编译器会提示“非法向前引用”
|
||||||
}
|
}
|
||||||
static int i = 1;
|
static int i = 1;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- ?????????????????????????? <init>()??????????????????????????????????????????????????? <clinit>() ????????????????? <clinit>() ?????????н??????????????е??????? <clinit>() ??????????? java.lang.Object??
|
- 与类的构造函数(或者说实例构造器 <init>())不同,不需要显式的调用父类的构造器。虚拟机会自动保证在子类的 <clinit>() 方法运行之前,父类的 <clinit>() 方法已经执行结束。因此虚拟机中第一个执行 <clinit>() 方法的类肯定为 java.lang.Object。
|
||||||
|
|
||||||
- ???????? <clinit>() ????????У??????ζ??????ж???????????????????????????????????????????
|
- 由于父类的 <clinit>() 方法先执行,也就意味着父类中定义的静态语句块要优于子类的变量赋值操作。例如以下代码:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
static class Parent {
|
static class Parent {
|
||||||
|
@ -573,53 +573,53 @@ static class Sub extends Parent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println(Sub.B); // ????????????е???????? A??????? 2
|
System.out.println(Sub.B); // 输出结果是父类中的静态变量值 A,也就是 2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- <clinit>() ??????????????????????????????в???????????飬???ж???????????????????????????????????? <clinit>() ??????
|
- <clinit>() 方法对于类或接口不是必须的,如果一个类中不包含静态语句块,也没有对类变量的赋值操作,编译器可以不为该类生成 <clinit>() 方法。
|
||||||
|
|
||||||
- ????в?????????????飬??????????????????????????????????????????????? <clinit>() ???????????????????????н??? <clinit>() ?????????????и????? <clinit>() ????????е???????ж????????????????????????????????????????????????????????н??? <clinit>() ??????
|
- 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 <clinit>() 方法。但接口与类不同的是,执行接口的 <clinit>() 方法不需要先执行父接口的 <clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 <clinit>() 方法。
|
||||||
|
|
||||||
- ?????????????? <clinit>() ??????????????±????????????????????????????????????????????????????????? <clinit>() ???????????????????????????????????? <clinit>() ??????????????????? <clinit>() ???????к??????????????????????????????????????д????????????Ρ?
|
- 虚拟机会保证一个类的 <clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 <clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 <clinit>() 方法完毕。如果在一个类的 <clinit>() 方法中有耗时的操作,就可能造成多个进程阻塞,在实际过程中此种阻塞很隐蔽。
|
||||||
|
|
||||||
## 4. ???????
|
## 4. 类加载器
|
||||||
|
|
||||||
????????????????????е????????????????????????????????????????? ( ??????? )???????????? Java ???????????????????ó???????????????????????????????????????????????????????????
|
虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流 ( 即字节码 )”这个动作放到 Java 虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。
|
||||||
|
|
||||||
### 4.1 ???????????
|
### 4.1 类与类加载器
|
||||||
|
|
||||||
???????????????????????????????????????????????????? Java ??????е?Ψ??????????????????????????????????????????????????????????????????????????????????????? Class ????? equals() ??????isAssignableFrom() ??????isInstance() ????????????????????? instanceof() ????????????????????ж?????????????????????????????????????????????????????壬??????????????????????? Class ???????????????????????????????????????????????????????????????
|
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在 Java 虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。通俗而言:比较两个类是否“相等”(这里所指的“相等”,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果,也包括使用 instanceof() 关键字对做对象所属关系判定等情况),只有在这两个类时由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个 Class 文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。
|
||||||
|
|
||||||
### 4.2 ???????????
|
### 4.2 类加载器分类
|
||||||
|
|
||||||
?? Java ?????????????????????????????????????????
|
从 Java 虚拟机的角度来讲,只存在以下两种不同的类加载器:
|
||||||
|
|
||||||
??????????????????Bootstrap ClassLoader???????????????? C++ ??????????????????????????????????????????????????Щ???? Java ???????????????????????????????????? java.lang.ClassLoader??
|
一种是启动类加载器(Bootstrap ClassLoader),这个类加载器用 C++ 实现,是虚拟机自身的一部分;另一种就是所有其他类的加载器,这些类由 Java 实现,独立于虚拟机外部,并且全都继承自抽象类 java.lang.ClassLoader。
|
||||||
|
|
||||||
?? Java ??????????????????????????????????Щ??
|
从 Java 开发人员的角度看,类加载器可以划分得更细致一些:
|
||||||
|
|
||||||
- ?????????????Bootstrap ClassLoader?? ????????????????? <JAVA_HOME>\lib ???е??????? -Xbootclasspath ???????????·???е?????????????????????????????????? rt.jar???????????????????? lib ??????????????????????????????С? ???????????????? Java ??????????????????д????????????????????????????????????????????????????? null ???漴?ɡ?
|
- 启动类加载器(Bootstrap ClassLoader) 此类加载器负责将存放在 <JAVA_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。 启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给引导类加载器,直接使用 null 代替即可。
|
||||||
|
|
||||||
- ????????????Extension ClassLoader?? ?????????????? ExtClassLoader??sun.misc.Launcher$ExtClassLoader????????????? <Java_Home>/lib/ext ????? java.ext.dir ???????????·???е????????????????У????????????????????????????
|
- 扩展类加载器(Extension ClassLoader) 这个类加载器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将 <Java_Home>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。
|
||||||
|
|
||||||
- ??ó????????????Application ClassLoader?? ?????????????? AppClassLoader??sun.misc.Launcher$AppClassLoader??????????????????????? ClassLoader ?е? getSystemClassLoader() ?????????????????????????????????????????????·????ClassPath??????????????????????????????????????????????ó?????????????????????????????????????????????????????????????
|
- 应用程序类加载器(Application ClassLoader) 这个类加载器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般称为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
|
||||||
|
|
||||||
### 4.3 ?????????
|
### 4.3 双亲委派模型
|
||||||
|
|
||||||
??ó?????????????????????????м?????????б?????????????????????????????????????????????????ι??????????????????????????Parents Delegation Model??????????????????????????????????????????????????????????????????????????????????????????????Composition??????????????????????У?Inheritance??????????
|
应用程序都是由三种类加载器相互配合进行加载的,如果有必要,还可以加入自己定义的类加载器。下图展示的类加载器之间的层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器,这里类加载器之间的父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)的关系实现。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2cdc3ce2-fa82-4c22-baaa-000c07d10473.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2cdc3ce2-fa82-4c22-baaa-000c07d10473.jpg)
|
||||||
|
|
||||||
**????????**
|
**工作过程**
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????????????????ε?????????????????ε?飬??????е?????????????????????????????????????У???е??????????????????????????????????????Χ?????????????????????????????????????
|
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器,每一个层次的加载器都是如此,依次递归,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成此加载请求(它搜索范围中没有找到所需类)时,子加载器才会尝试自己加载。
|
||||||
|
|
||||||
**???**
|
**好处**
|
||||||
|
|
||||||
??????????????????????????????????? Java ??????????????????????????????????????ι?????????? java.lang.Object????????? rt.jar ?У??????????????????????????????????????????????????????????????м??????? Object ???????????????????????ж????????????????????????????????????????????м???????????????д??????????java.lang.Object ?????????????? ClassPath ?У??????н????????????? Object ????????????????????????????д????? rt.jar ????????????????? Java ??????????????????????????????????????С?
|
使用双亲委派模型来组织类加载器之间的关系,使得 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类 java.lang.Object,它存放再 rt.jar 中,无论哪个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此 Object 类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型,由各个类加载器自行加载的话,如果用户编写了一个称为`java.lang.Object 的类,并放在程序的 ClassPath 中,那系统中将会出现多个不同的 Object 类,程序将变得一片混乱。如果开发者尝试编写一个与 rt.jar 类库中已有类重名的 Java 类,将会发现可以正常编译,但是永远无法被加载运行。
|
||||||
|
|
||||||
**???**
|
**实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
|
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
|
||||||
|
@ -646,27 +646,27 @@ protected synchronized Class<?> loadClass(String name, boolean resolve) throws C
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# JVM ????
|
# JVM 参数
|
||||||
|
|
||||||
## GC ???????
|
## GC 优化配置
|
||||||
|
|
||||||
| ???? | ???? |
|
| 配置 | 描述 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| -Xms | ???????????С |
|
| -Xms | 初始化堆内存大小 |
|
||||||
| -Xmx | ????????? |
|
| -Xmx | 堆内存最大值 |
|
||||||
| -Xmn | ????????С |
|
| -Xmn | 新生代大小 |
|
||||||
| -XX:PermSize | ????????????С |
|
| -XX:PermSize | 初始化永久代大小 |
|
||||||
| -XX:MaxPermSize | ???????????? |
|
| -XX:MaxPermSize | 永久代最大容量 |
|
||||||
|
|
||||||
## GC ????????
|
## GC 类型设置
|
||||||
|
|
||||||
| ???? | ???? |
|
| 配置 | 描述 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| -XX:+UseSerialGC | ?????????????? |
|
| -XX:+UseSerialGC | 串行垃圾回收器 |
|
||||||
| -XX:+UseParallelGC | ?????????????? |
|
| -XX:+UseParallelGC | 并行垃圾回收器 |
|
||||||
| -XX:+UseConcMarkSweepGC | ???????????????????? |
|
| -XX:+UseConcMarkSweepGC | 并发标记扫描垃圾回收器 |
|
||||||
| -XX:ParallelCMSThreads= | ???????????????????? = ???????????? |
|
| -XX:ParallelCMSThreads= | 并发标记扫描垃圾回收器 = 为使用的线程数量 |
|
||||||
| -XX:+UseG1GC | G1 ?????????? |
|
| -XX:+UseG1GC | G1 垃圾回收器 |
|
||||||
|
|
||||||
```java
|
```java
|
||||||
java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar java-application.jar
|
java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar java-application.jar
|
||||||
|
|
282
notes/Java IO.md
282
notes/Java IO.md
|
@ -1,129 +1,129 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [????](#????)
|
* [概览](#概览)
|
||||||
* [???????](#???????)
|
* [磁盘操作](#磁盘操作)
|
||||||
* [??????](#??????)
|
* [字节操作](#字节操作)
|
||||||
* [???????](#???????)
|
* [字符操作](#字符操作)
|
||||||
* [???????](#???????)
|
* [对象操作](#对象操作)
|
||||||
* [???????](#???????)
|
* [网络操作](#网络操作)
|
||||||
* [1. InetAddress](#1-inetaddress)
|
* [1. InetAddress](#1-inetaddress)
|
||||||
* [2. URL](#2-url)
|
* [2. URL](#2-url)
|
||||||
* [3. Sockets](#3-sockets)
|
* [3. Sockets](#3-sockets)
|
||||||
* [4. Datagram](#4-datagram)
|
* [4. Datagram](#4-datagram)
|
||||||
* [NIO](#nio)
|
* [NIO](#nio)
|
||||||
* [1. ?????](#1-?????)
|
* [1. 流与块](#1-流与块)
|
||||||
* [2. ?????????](#2-?????????)
|
* [2. 通道与缓冲区](#2-通道与缓冲区)
|
||||||
* [2.1 ???](#21-???)
|
* [2.1 通道](#21-通道)
|
||||||
* [2.2 ??????](#22-??????)
|
* [2.2 缓冲区](#22-缓冲区)
|
||||||
* [3. ????????????](#3-????????????)
|
* [3. 缓冲区状态变量](#3-缓冲区状态变量)
|
||||||
* [4. ??§Õ??????](#4-??§Õ??????)
|
* [4. 读写文件实例](#4-读写文件实例)
|
||||||
* [5. ???????????](#5-???????????)
|
* [5. 阻塞与非阻塞](#5-阻塞与非阻塞)
|
||||||
* [5.1 ????? I/O](#51-?????-io)
|
* [5.1 阻塞式 I/O](#51-阻塞式-io)
|
||||||
* [5.2 ??????? I/O](#52-???????-io)
|
* [5.2 非阻塞式 I/O](#52-非阻塞式-io)
|
||||||
* [6. ????????](#6-????????)
|
* [6. 套接字实例](#6-套接字实例)
|
||||||
* [6.1 ServerSocketChannel](#61-serversocketchannel)
|
* [6.1 ServerSocketChannel](#61-serversocketchannel)
|
||||||
* [6.2 Selectors](#62-selectors)
|
* [6.2 Selectors](#62-selectors)
|
||||||
* [6.3 ?????](#63-?????)
|
* [6.3 主循环](#63-主循环)
|
||||||
* [6.4 ??????????](#64-??????????)
|
* [6.4 监听新连接](#64-监听新连接)
|
||||||
* [6.5 ???????????](#65-???????????)
|
* [6.5 接受新的连接](#65-接受新的连接)
|
||||||
* [6.6 ?????????? SelectionKey](#66-??????????-selectionkey)
|
* [6.6 删除处理过的 SelectionKey](#66-删除处理过的-selectionkey)
|
||||||
* [6.7 ????? I/O](#67-?????-io)
|
* [6.7 传入的 I/O](#67-传入的-io)
|
||||||
* [?¦Ï?????](#?¦Ï?????)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ????
|
# 概览
|
||||||
|
|
||||||
Java ?? I/O ???????????????
|
Java 的 I/O 大概可以分成以下几类
|
||||||
|
|
||||||
1. ?????????File
|
1. 磁盘操作:File
|
||||||
2. ????????InputStream ?? OutputStream
|
2. 字节操作:InputStream 和 OutputStream
|
||||||
3. ?????????Reader ?? Writer
|
3. 字符操作:Reader 和 Writer
|
||||||
4. ?????????Serializable
|
4. 对象操作:Serializable
|
||||||
5. ?????????Socket
|
5. 网络操作:Socket
|
||||||
6. ??????? IO??NIO
|
6. 非阻塞式 IO:NIO
|
||||||
|
|
||||||
# ???????
|
# 磁盘操作
|
||||||
|
|
||||||
File ????????????????????????????????????????????????????????????
|
File 类可以用于表示文件和目录,但是它只用于表示文件的信息,而不表示文件的内容。
|
||||||
|
|
||||||
# ??????
|
# 字节操作
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8143787f-12eb-46ea-9bc3-c66d22d35285.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8143787f-12eb-46ea-9bc3-c66d22d35285.jpg)
|
||||||
|
|
||||||
Java I/O ???????????????????? InputStream ?????InputStream ??????????FileInputStream ?? InputStream ??????????????????????????????????????FilterInputStream ????????????????????????????????????????????????? BufferedInputStream ? FileInputStream ??????????????????????§Ý??œ¤????????????????????? FileInputStream ????????????? BufferedInputStream ????¨À?
|
Java I/O 使用了装饰者模式来实现。以 InputStream 为例,InputStream 是抽象组件,FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作。FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能,例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||||
```
|
```
|
||||||
|
|
||||||
DataInputStream ?????????????????????????????????????? int??double ??????????
|
DataInputStream 装饰者提供了对更多数据类型进行输入的操作,比如 int、double 等基本类型。
|
||||||
|
|
||||||
????????????§Ö???????????????
|
批量读入文件中的内容到字节数组中
|
||||||
|
|
||||||
```java
|
```java
|
||||||
byte[] buf = new byte[20*1024];
|
byte[] buf = new byte[20*1024];
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
// ????? buf.length ????????????????????????????? -1 ??????????? eof???????¦Â
|
// 最多读取 buf.length 个字节,返回的是实际读取的个数,返回 -1 的时候表示读到 eof,即文件尾
|
||||||
while((bytes = in.read(buf, 0 , buf.length)) != -1) {
|
while((bytes = in.read(buf, 0 , buf.length)) != -1) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# ???????
|
# 字符操作
|
||||||
|
|
||||||
???????????????×Ï????§³??›¥?????????????????????????? I/O ????????????????????????????????§Ó??????????????????????????????????????§Ó??????????
|
不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符,所以 I/O 操作的都是字节而不是字符。但是在程序中操作的数据通常是字符形式,因此需要提供对字符进行操作的方法。
|
||||||
|
|
||||||
InputStreamReader ?????????????????????????????OutputStreamWriter ??????????????????????????????????????? Reader ?? Writer??
|
InputStreamReader 实现从文本文件的字节流解码成字符流;OutputStreamWriter 实现字符流编码成为文本文件的字节流。它们都继承自 Reader 和 Writer。
|
||||||
|
|
||||||
????????????????????????????????????????????
|
编码就是把字符转换为字节,而解码是把字节重新组合成字符。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
byte[] bytes = str.getBytes(encoding); // ????
|
byte[] bytes = str.getBytes(encoding); // 编码
|
||||||
String str = new String(bytes, encoding)?? // ????
|
String str = new String(bytes, encoding); // 解码
|
||||||
```
|
```
|
||||||
|
|
||||||
GBK ?????§µ?????? 2 ?????????? 1 ??????UTF-8 ?????§µ?????? 3 ?????????? 1 ??????Java ?????????? UTF-16be???????????? 2 ??????
|
GBK 编码中,中文占 2 个字节,英文占 1 个字节;UTF-8 编码中,中文占 3 个字节,英文占 1 个字节;Java 使用双字节编码 UTF-16be,中文和英文都占 2 个字节。
|
||||||
|
|
||||||
????????????????¨°??????????????????????
|
如果编码和解码过程使用不同的编码方式那么就出现了乱码。
|
||||||
|
|
||||||
# ???????
|
# 对象操作
|
||||||
|
|
||||||
???§Ý????????????????????????§µ?????›¥?????
|
序列化就是将一个对象转换成字节序列,方便存储和传输。
|
||||||
|
|
||||||
???§Ý???ObjectOutputStream.writeObject()
|
序列化:ObjectOutputStream.writeObject()
|
||||||
|
|
||||||
?????§Ý???ObjectInputStream.readObject()
|
反序列化:ObjectInputStream.readObject()
|
||||||
|
|
||||||
???§Ý??????????? Serializable ?????????????????????¦Ê¦Ç??????????
|
序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现。
|
||||||
|
|
||||||
transient ??????????§»??????????§Ý???
|
transient 关键字可以使一些属性不会被序列化。
|
||||||
|
|
||||||
**ArrayList ???§Ý???????§Ý??????**??ArrayList ?§Õ›¥????????????? transient ???¦Å???????????????????????????????§Ö????????????????????§Ö???????????§Ý????????§Õ???§Ý???????§Ý?????????????????§Ý????????????????????????
|
**ArrayList 序列化和反序列化的实现**:ArrayList 中存储数据的数组是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。
|
||||||
|
|
||||||
```
|
```
|
||||||
private transient Object[] elementData;
|
private transient Object[] elementData;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ???????
|
# 网络操作
|
||||||
|
|
||||||
Java ?§Ö?????????
|
Java 中的网络支持:
|
||||||
|
|
||||||
1. InetAddress????????????????????????? IP ?????
|
1. InetAddress:用于表示网络上的硬件资源,即 IP 地址;
|
||||||
2. URL?????????¦Ë??????? URL ?????????????§Õ??????????????
|
2. URL:统一资源定位符,通过 URL 可以直接读取或者写入网络上的数据;
|
||||||
3. Sockets????? TCP §¿?????????????
|
3. Sockets:使用 TCP 协议实现网络通信;
|
||||||
4. Datagram????? UDP §¿?????????????
|
4. Datagram:使用 UDP 协议实现网络通信。
|
||||||
|
|
||||||
## 1. InetAddress
|
## 1. InetAddress
|
||||||
|
|
||||||
??§Û??§Û??????????????????????????????????? InetAddress.getByName(String host)??InetAddress.getByAddress(byte[] addr)??
|
没有公有构造函数,只能通过静态方法来创建实例,比如 InetAddress.getByName(String host)、InetAddress.getByAddress(byte[] addr)。
|
||||||
|
|
||||||
## 2. URL
|
## 2. URL
|
||||||
|
|
||||||
???????? URL ?§Ø???????????
|
可以直接从 URL 中读取字节流数据
|
||||||
|
|
||||||
```java
|
```java
|
||||||
URL url = new URL("http://www.baidu.com");
|
URL url = new URL("http://www.baidu.com");
|
||||||
InputStream is = url.openStream(); // ?????
|
InputStream is = url.openStream(); // 字节流
|
||||||
InputStreamReader isr = new InputStreamReader(is, "utf-8"); // ?????
|
InputStreamReader isr = new InputStreamReader(is, "utf-8"); // 字符流
|
||||||
BufferedReader br = new BufferedReader(isr);
|
BufferedReader br = new BufferedReader(isr);
|
||||||
String line = br.readLine();
|
String line = br.readLine();
|
||||||
while (line != null) {
|
while (line != null) {
|
||||||
|
@ -137,56 +137,56 @@ is.close();
|
||||||
|
|
||||||
## 3. Sockets
|
## 3. Sockets
|
||||||
|
|
||||||
Socket ??????
|
Socket 通信模型
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fa4101d7-19ce-4a69-a84f-20bbe64320e5.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fa4101d7-19ce-4a69-a84f-20bbe64320e5.jpg)
|
||||||
|
|
||||||
- ServerSocket????????????
|
- ServerSocket:服务器端类
|
||||||
- Socket?????????
|
- Socket:客户端类
|
||||||
|
|
||||||
??????????????? InputStream ?? OutputStream ?????????????
|
服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
|
||||||
|
|
||||||
## 4. Datagram
|
## 4. Datagram
|
||||||
|
|
||||||
- DatagramPacket?????????
|
- DatagramPacket:数据包类
|
||||||
- DatagramSocket???????
|
- DatagramSocket:通信类
|
||||||
|
|
||||||
# NIO
|
# NIO
|
||||||
|
|
||||||
NIO ???????? I/O ???? ( ??????????????? ) ?????????????? ??????????????????????????????????
|
NIO 将最耗时的 I/O 操作 ( 即填充和提取缓冲区 ) 转移回操作系统,因而 不需要程序员去控制就可以极大地提高运行速度。
|
||||||
|
|
||||||
## 1. ?????
|
## 1. 流与块
|
||||||
|
|
||||||
I/O ?? NIO ?????????????????????????????????????????I/O ??????????????????? NIO ???????????????
|
I/O 与 NIO 最重要的区别是数据打包和传输的方式。正如前面提到的,I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
|
||||||
|
|
||||||
???????? I/O ???????????§Õ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? I/O ?????????
|
面向流的 I/O 一次一个字节进行处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。
|
||||||
|
|
||||||
????????? I/O ??????????????????????????????????§Ó??????????????????î•???ø„????????????????????????????????? I/O ????§»???????? I/O ?????§Ö????????????
|
一个面向块的 I/O 系统以块的形式处理数据,每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按流处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。
|
||||||
|
|
||||||
I/O ???? NIO ?????????????java.io.\* ????? NIO ????????????????????????????????? NIO ???§»????????íà java.io.\* ???§Ö??§»??????????????§Õ??????????????¨¹????????????????§µ??????????????
|
I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重新实现了,所以现在它可以利用 NIO 的一些特性。例如, java.io.\* 包中的一些类包含以块的形式读写数据的方法,这使得即使在更面向流的系统中,处理速度也会更快。
|
||||||
|
|
||||||
## 2. ?????????
|
## 2. 通道与缓冲区
|
||||||
|
|
||||||
### 2.1 ???
|
### 2.1 通道
|
||||||
|
|
||||||
??? Channel ???? I/O ???§Ö??????????????????????§Õ???????
|
通道 Channel 是对原 I/O 包中的流的模拟,可以通过它读取和写入数据。
|
||||||
|
|
||||||
????????????????????????????????????????(??????????? InputStream ???? OutputStream ??????)?? ???????????????????????§Õ???????????§Õ??
|
通道与流的不同之处在于,流只能在一个方向上移动,(一个流必须是 InputStream 或者 OutputStream 的子类), 而通道是双向的,可以用于读、写或者同时用于读写。
|
||||||
|
|
||||||
????????????????
|
通道包括以下类型:
|
||||||
|
|
||||||
- FileChannel????????§Ø?§Õ?????
|
- FileChannel:从文件中读写数据;
|
||||||
- DatagramChannel????? UDP ??§Õ???????????
|
- DatagramChannel:通过 UDP 读写网络中数据;
|
||||||
- SocketChannel????? TCP ??§Õ???????????
|
- SocketChannel:通过 TCP 读写网络中数据;
|
||||||
- ServerSocketChannel???????????????? TCP ?????????????????????????????? SocketChannel??
|
- ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
|
||||||
|
|
||||||
### 2.2 ??????
|
### 2.2 缓冲区
|
||||||
|
|
||||||
????????????????§Ø???????????????????§µ?????????????§Ø?????¦Ê??????????????????§³???????????????????????§Ø?§Õ??????????????????????
|
发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是先经过缓冲区。
|
||||||
|
|
||||||
???????????????????ï…??????????????????î•?????????????????????????????????????????/§Õ?????
|
缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
|
||||||
|
|
||||||
???????????????????
|
缓冲区包括以下类型:
|
||||||
|
|
||||||
- ByteBuffer
|
- ByteBuffer
|
||||||
- CharBuffer
|
- CharBuffer
|
||||||
|
@ -197,50 +197,50 @@ I/O ???? NIO ?????????????java.io.\* ????? NIO ?????????????????????????????????
|
||||||
- DoubleBuffer
|
- DoubleBuffer
|
||||||
|
|
||||||
|
|
||||||
## 3. ????????????
|
## 3. 缓冲区状态变量
|
||||||
|
|
||||||
- capacity???????????
|
- capacity:最大容量;
|
||||||
- position??????????§Õ?????????
|
- position:当前已经读写的字节数;
|
||||||
- limit?????????§Õ?????????
|
- limit:还可以读写的字节数。
|
||||||
|
|
||||||
??????????????
|
状态变量的改变过程:
|
||||||
|
|
||||||
1\. ????????§³? 8 ???????????????? position ? 0???? limit == capacity == 9??capacity ???????????????????????????
|
1\. 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit == capacity == 9。capacity 变量不会改变,下面的讨论会忽略它。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png)
|
||||||
|
|
||||||
2\. ??????????§Ø?? 3 ?????????§Õ???????§µ???? position ?????? 3??limit ???????
|
2\. 从输入通道中读取 3 个字节数据写入缓冲区中,此时 position 移动设为 3,limit 保持不变。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4628274c-25b6-4053-97cf-d1239b44c43d.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4628274c-25b6-4053-97cf-d1239b44c43d.png)
|
||||||
|
|
||||||
3\. ???????????????§Õ???????????????????? flip() ??????????????? limit ???????? position?????? position ????? 0??
|
3\. 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png)
|
||||||
|
|
||||||
4\. ?????????? 4 ??????????????§µ???? position ??? 4??
|
4\. 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png)
|
||||||
|
|
||||||
5\. ?????????? clear() ??????????????????? position ?? limit ????????????¦Ë?¨¢?
|
5\. 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png)
|
||||||
|
|
||||||
## 4. ??§Õ??????
|
## 4. 读写文件实例
|
||||||
|
|
||||||
1\. ?????????????? FileInputStream???????? FileInputStream ??????? FileChannel??
|
1\. 为要读取的文件创建 FileInputStream,之后通过 FileInputStream 获取输入 FileChannel;
|
||||||
|
|
||||||
```java
|
```java
|
||||||
FileInputStream fin = new FileInputStream("readandshow.txt");
|
FileInputStream fin = new FileInputStream("readandshow.txt");
|
||||||
FileChannel fic = fin.getChannel();
|
FileChannel fic = fin.getChannel();
|
||||||
```
|
```
|
||||||
|
|
||||||
2\. ???????????? 1024 ?? Buffer
|
2\. 创建一个容量为 1024 的 Buffer
|
||||||
|
|
||||||
```java
|
```java
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||||
```
|
```
|
||||||
|
|
||||||
3\. ??????????? FileChannel §Õ?? Buffer ?§µ??????????????? read() ???????? -1
|
3\. 将数据从输入 FileChannel 写入到 Buffer 中,如果没有数据的话, read() 方法会返回 -1
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int r = fcin.read(buffer);
|
int r = fcin.read(buffer);
|
||||||
|
@ -249,86 +249,86 @@ if (r == -1) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
4\. ??§Õ?????????? FileOutputStream???????? FileOutputStream ?????? FileChannel
|
4\. 为要写入的文件创建 FileOutputStream,之后通过 FileOutputStream 获取输出 FileChannel
|
||||||
|
|
||||||
```java
|
```java
|
||||||
FileOutputStream fout = new FileOutputStream("writesomebytes.txt");
|
FileOutputStream fout = new FileOutputStream("writesomebytes.txt");
|
||||||
FileChannel foc = fout.getChannel();
|
FileChannel foc = fout.getChannel();
|
||||||
```
|
```
|
||||||
|
|
||||||
5\. ???? flip() ?§Ý???§Õ
|
5\. 调用 flip() 切换读写
|
||||||
|
|
||||||
```java
|
```java
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
```
|
```
|
||||||
|
|
||||||
6\. ?? Buffer ?§Ö???????????? FileChannel ??
|
6\. 把 Buffer 中的数据读取到输出 FileChannel 中
|
||||||
|
|
||||||
```java
|
```java
|
||||||
foc.write(buffer);
|
foc.write(buffer);
|
||||||
```
|
```
|
||||||
|
|
||||||
7\. ?????? clear() ?????????
|
7\. 最后调用 clear() 重置缓冲区
|
||||||
|
|
||||||
```java
|
```java
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. ???????????
|
## 5. 阻塞与非阻塞
|
||||||
|
|
||||||
??????FileChannel ?????§Ý?????????????????? Channel ?????
|
应当注意,FileChannel 不能切换到非阻塞模式,套接字 Channel 可以。
|
||||||
|
|
||||||
### 5.1 ????? I/O
|
### 5.1 阻塞式 I/O
|
||||||
|
|
||||||
????? I/O ????? InputStream.read() ?????????????????????????????????????? ServerSocket.accept() ???????????????????§á??????????????????????????????????????????????????????????????
|
阻塞式 I/O 在调用 InputStream.read() 方法时会一直等到数据到来时(或超时)才会返回,在调用 ServerSocket.accept() 方法时,也会一直阻塞到有客户端连接才会返回,每个客户端连接过来后,服务端都会启动一个线程去处理该客户端的请求。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/edc23f99-c46c-4200-b64e-07516828720d.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/edc23f99-c46c-4200-b64e-07516828720d.jpg)
|
||||||
|
|
||||||
### 5.2 ??????? I/O
|
### 5.2 非阻塞式 I/O
|
||||||
|
|
||||||
?????????????????????§Ö? I/O ???????????????
|
由一个专门的线程来处理所有的 I/O 事件,并负责分发。
|
||||||
|
|
||||||
??????????????????????????????????????????????
|
事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
|
||||||
|
|
||||||
???????????????? wait()??notify() ?????????????????????§Ý???????????????????¦Í??????§Ý???
|
线程通信:线程之间通过 wait()、notify() 等方式通信,保证每次上下文切换都是有意义的,减少无谓的线程切换。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7fcb2fb0-2cd9-4396-bc2d-282becf963c3.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7fcb2fb0-2cd9-4396-bc2d-282becf963c3.jpg)
|
||||||
|
|
||||||
## 6. ????????
|
## 6. 套接字实例
|
||||||
|
|
||||||
### 6.1 ServerSocketChannel
|
### 6.1 ServerSocketChannel
|
||||||
|
|
||||||
???????????????? ServerSocketChannel ?????????????
|
每一个端口都需要有一个 ServerSocketChannel 用来监听连接。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
ServerSocketChannel ssc = ServerSocketChannel.open();
|
||||||
ssc.configureBlocking(false); // ???????????
|
ssc.configureBlocking(false); // 设置为非阻塞
|
||||||
|
|
||||||
ServerSocket ss = ssc.socket();
|
ServerSocket ss = ssc.socket();
|
||||||
InetSocketAddress address = new InetSocketAddress(ports[i]);
|
InetSocketAddress address = new InetSocketAddress(ports[i]);
|
||||||
ss.bind(address); // ?????
|
ss.bind(address); // 绑定端口号
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.2 Selectors
|
### 6.2 Selectors
|
||||||
|
|
||||||
?? I/O ??? Selector ??????? I/O ???????? ?D ?????????????????????????????????????????????????????????
|
异步 I/O 通过 Selector 注册对特定 I/O 事件的兴趣 ― 可读的数据的到达、新的套接字连接等等,在发生这样的事件时,系统将会发送通知。
|
||||||
|
|
||||||
???? Selectors ?????????????????????? register() ??????register() ????????????????? Selector????????????? OP_ACCEPT?????????????????????? accept ????????????????????????????????????
|
创建 Selectors 之后,就可以对不同的通道对象调用 register() 方法。register() 的第一个参数总是这个 Selector。第二个参数是 OP_ACCEPT,这里它指定我们想要监听 accept 事件,也就是在新的连接建立时所发生的事件。
|
||||||
|
|
||||||
SelectionKey ????????????? Selector ?????????????? Selector ????????????????????????????????????? SelectionKey ?????§Ö??SelectionKey ?????????????????????
|
SelectionKey 代表这个通道在此 Selector 上的这个注册。当某个 Selector 通知您某个传入事件时,它是通过提供对应于该事件的 SelectionKey 来进行的。SelectionKey 还可以用于取消通道的注册。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Selector selector = Selector.open();
|
Selector selector = Selector.open();
|
||||||
SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
|
SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.3 ?????
|
### 6.3 主循环
|
||||||
|
|
||||||
???????????? Selector ?? select() ??????????????????????????????????????????????????????????????????????? select() ?????????????????????????????
|
首先,我们调用 Selector 的 select() 方法。这个方法会阻塞,直到至少有一个已注册的事件发生。当一个或者更多的事件发生时, select() 方法将返回所发生的事件的数量。
|
||||||
|
|
||||||
??????????????? Selector ?? selectedKeys() ?????????????????????? SelectionKey ???????? ???? ??
|
接下来,我们调用 Selector 的 selectedKeys() 方法,它返回发生了事件的 SelectionKey 对象的一个 集合 。
|
||||||
|
|
||||||
??????????? SelectionKeys ?????¦Ä?????? SelectionKey ??????????????????? SelectionKey????????????????????? I/O ???????????????????§» I/O ????
|
我们通过迭代 SelectionKeys 并依次处理每个 SelectionKey 来处理事件。对于每一个 SelectionKey,您必须确定发生的是什么 I/O 事件,以及这个事件影响哪些 I/O 对象。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
int num = selector.select();
|
int num = selector.select();
|
||||||
|
@ -342,9 +342,9 @@ while (it.hasNext()) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.4 ??????????
|
### 6.4 监听新连接
|
||||||
|
|
||||||
??????§Ö??????????????? ServerSocketChannel??????????????????????????????????????? SelectionKey ???? readyOps() ??????????ú€????????????????
|
程序执行到这里,我们仅注册了 ServerSocketChannel,并且仅注册它们“接收”事件。为确认这一点,我们对 SelectionKey 调用 readyOps() 方法,并检查发生了什么类型的事件:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
if ((key.readyOps() & SelectionKey.OP_ACCEPT)
|
if ((key.readyOps() & SelectionKey.OP_ACCEPT)
|
||||||
|
@ -354,39 +354,39 @@ if ((key.readyOps() & SelectionKey.OP_ACCEPT)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????? readOps() ??????????????????????????
|
可以肯定地说, readOps() 方法告诉我们该事件是新的连接。
|
||||||
|
|
||||||
### 6.5 ???????????
|
### 6.5 接受新的连接
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????? accept() ????????????
|
因为我们知道这个服务器套接字上有一个传入连接在等待,所以可以安全地接受它;也就是说,不用担心 accept() 操作会阻塞:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
|
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
|
||||||
SocketChannel sc = ssc.accept();
|
SocketChannel sc = ssc.accept();
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????? SocketChannel ??????????????????????????????????????????????????????????????????????? SocketChannel ??? Selector????????????
|
下一步是将新连接的 SocketChannel 配置为非阻塞的。而且由于接受这个连接的目的是为了读取来自套接字的数据,所以我们还必须将 SocketChannel 注册到 Selector上,如下所示:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
sc.configureBlocking( false );
|
sc.configureBlocking( false );
|
||||||
SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ );
|
SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ );
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????? register() ?? OP_READ ???????? SocketChannel ??????? ??? ?????? ???? ???????
|
注意我们使用 register() 的 OP_READ 参数,将 SocketChannel 注册用于 读取 而不是 接受 新连接。
|
||||||
|
|
||||||
### 6.6 ?????????? SelectionKey
|
### 6.6 删除处理过的 SelectionKey
|
||||||
|
|
||||||
????? SelectionKey ???????????????????????????????????????????????? SelectionKey ????????????????????????????????????????????????????????????????????????????????????????????¦Ä????????????????????? remove() ???????????????? SelectionKey??
|
在处理 SelectionKey 之后,我们几乎可以返回主循环了。但是我们必须首先将处理过的 SelectionKey 从选定的键集合中删除。如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键出现,这会导致我们尝试再次处理它。我们调用迭代器的 remove() 方法来删除处理过的 SelectionKey:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
it.remove();
|
it.remove();
|
||||||
```
|
```
|
||||||
|
|
||||||
???????????????????????????????????§Õ????????(???????????? I/O ???)???
|
现在我们可以返回主循环并接受从一个套接字中传入的数据(或者一个传入的 I/O 事件)了。
|
||||||
|
|
||||||
### 6.7 ????? I/O
|
### 6.7 传入的 I/O
|
||||||
|
|
||||||
?????????????????????????????????? I/O ??????????????????§Ö??? Selector.select()????????????????? I/O ?????????¦²? SelectionKey ???????? OP_READ ??????????????
|
当来自一个套接字的数据到达时,它会触发一个 I/O 事件。这会导致在主循环中调用 Selector.select(),并返回一个或者多个 I/O 事件。这一次, SelectionKey 将被标记为 OP_READ 事件,如下所示:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
} else if ((key.readyOps() & SelectionKey.OP_READ)
|
} else if ((key.readyOps() & SelectionKey.OP_READ)
|
||||||
|
@ -398,9 +398,9 @@ it.remove();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# ?¦Ï?????
|
# 参考资料
|
||||||
|
|
||||||
- Eckel B, ????? , ??? , ?? . Java ?????? [M]. ??§Ö????????? , 2002.
|
- Eckel B, 埃克尔 , 昊鹏 , 等 . Java 编程思想 [M]. 机械工业出版社 , 2002.
|
||||||
- [IBM: NIO ????](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)
|
- [IBM: NIO 入门](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)
|
||||||
- [ ??????? Java I/O ????????? ](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html)
|
- [ 深入分析 Java I/O 的工作机制 ](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html)
|
||||||
- [NIO ??? IO ?????? ](http://blog.csdn.net/shimiso/article/details/24990499)
|
- [NIO 与传统 IO 的区别 ](http://blog.csdn.net/shimiso/article/details/24990499)
|
||||||
|
|
|
@ -1,140 +1,140 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [????](#????)
|
* [基础](#基础)
|
||||||
* [ final](#-final)
|
* [ final](#-final)
|
||||||
* [????????](#????????)
|
* [初始化顺序](#初始化顺序)
|
||||||
* [???????](#???????)
|
* [访问权限](#访问权限)
|
||||||
* [????](#????)
|
* [容器](#容器)
|
||||||
* [Set](#set)
|
* [Set](#set)
|
||||||
* [Queue](#queue)
|
* [Queue](#queue)
|
||||||
* [Map](#map)
|
* [Map](#map)
|
||||||
* [????](#????)
|
* [反射](#反射)
|
||||||
* [??](#??)
|
* [异常](#异常)
|
||||||
* [?¦Ï?????](#?¦Ï?????)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ????
|
# 基础
|
||||||
|
|
||||||
## final
|
## final
|
||||||
|
|
||||||
**final ????**
|
**final 数据**
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????
|
声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
|
||||||
|
|
||||||
????????????final ???????????????????final ????¨°?????????????????????????????????????????????
|
对于基本类型,final 使数值不变;对于引用对象,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
|
||||||
|
|
||||||
**final ????**
|
**final 方法**
|
||||||
|
|
||||||
????????????????????
|
声明方法不能被子类覆盖。
|
||||||
|
|
||||||
private ?????????????? final????????????§Ø?????????????§Ö???? private ????????????????????????????????????????????????
|
private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是覆盖基类方法,而是重载了。
|
||||||
|
|
||||||
**final ??**
|
**final 类**
|
||||||
|
|
||||||
????????????§³?
|
声明类不允许被继承。
|
||||||
|
|
||||||
## ????????
|
## 初始化顺序
|
||||||
|
|
||||||
static ??????????????????????????????????????????????????¦²??????????????????????
|
static 声明的静态数据在内存中只存在一份,只在类第一次实例化时初始化一次,优先于其它数据的初始化。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static String staticField = "???????";
|
public static String staticField = "静态变量";
|
||||||
```
|
```
|
||||||
|
|
||||||
static ????? static ???????????????????????????¦²?????????????????????????????§Ö????
|
static 语句块和 static 数据一样在类第一次实例化时运行一次,具体哪个先运行取决于它们在代码中的顺序。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
static {
|
static {
|
||||||
System.out.println("??????????");
|
System.out.println("静态初始化块");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????????????????????????????????
|
普通数据和普通语句块的初始化在静态数据和静态语句块初始化结束之后。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public String field = "????";
|
public String field = "变量";
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
{
|
{
|
||||||
System.out.println("???????");
|
System.out.println("初始化块");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
????????????§Ö???????§Ô????
|
最后才是构造函数中的数据进行初始化
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public InitialOrderTest()
|
public InitialOrderTest()
|
||||||
{
|
{
|
||||||
System.out.println("??????");
|
System.out.println("构造器");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
?????§Ö??????????????????
|
存在继承的情况下,初始化顺序为:
|
||||||
|
|
||||||
1. ??????????????????ï‚
|
1. 父类(静态数据、静态语句块)
|
||||||
2. ??????????????????ï‚
|
2. 子类(静态数据、静态语句块)
|
||||||
3. ????????????ï‚
|
3. 父类(数据、语句块)
|
||||||
4. ????????????
|
4. 父类(构造器)
|
||||||
5. ????????????ï‚
|
5. 子类(数据、语句块)
|
||||||
6. ????????????
|
6. 子类(构造器)
|
||||||
|
|
||||||
## ???????
|
## 访问权限
|
||||||
|
|
||||||
Java ??????????????????¦Ç???private??protected ??? public???????????????¦Ç???????????????
|
Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。
|
||||||
|
|
||||||
???????????§Ö???????????????????????????¦Ç??????????????????????¨®?????????????????¨®????????????????????????????????????????????§Ö??????????????????????????????????
|
可以对类或类中的成员(字段以及方法)加上访问修饰符。成员可见表示其它类可以用成员所在类的对象访问到该成员;类可见表示其它类可以用这个类创建对象,可以把类当做包中的一个成员,然后包表示一个类,这样就好理解了。
|
||||||
|
|
||||||
protected ???????¦Ã???????????????§Ô????????????????????????????¦Ç?????????????ÈÉ???????§Þ???????
|
protected 用于修饰成员,表示在继承体系中成员对于子类可见。但是这个访问修饰符对于类没有意义,因为包没有继承体系。
|
||||||
|
|
||||||
# ????
|
# 容器
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/114c49a6-72e3-4264-ae07-c564127094ac.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/114c49a6-72e3-4264-ae07-c564127094ac.png)
|
||||||
|
|
||||||
??????????? Collection ?? Map ?????Collection ??????? List??Set ??? Queue??
|
容器主要包括 Collection 和 Map 两种,Collection 又包含了 List、Set 以及 Queue。
|
||||||
|
|
||||||
## Set
|
## Set
|
||||||
|
|
||||||
- HashSet????? Hash ???????????????????????????
|
- HashSet:使用 Hash 实现,支持快速查找,但是失去有序性;
|
||||||
|
|
||||||
- TreeSet?????????????????????????§¹????? HashSet??
|
- TreeSet:使用树实现,保持有序,但是查找效率不如 HashSet;
|
||||||
|
|
||||||
- LinkedListHashSet?????? HashSet ?????§¹?????????????????????????????????????????
|
- LinkedListHashSet:具有 HashSet 的查找效率,且内部使用链表维护元素的插入顺序,因此具有有序性。
|
||||||
|
|
||||||
## Queue
|
## Queue
|
||||||
|
|
||||||
???????????LinkedList ?? PriorityQueue?????? LinkedList ????????§³?
|
只有两个实现:LinkedList 和 PriorityQueue,其中 LinkedList 支持双向队列。
|
||||||
|
|
||||||
## Map
|
## Map
|
||||||
|
|
||||||
- HashMap????? Hash ???
|
- HashMap:使用 Hash 实现
|
||||||
|
|
||||||
- LinkedHashMap???????????????????????????????????LRU?????
|
- LinkedHashMap:保持有序,顺序为插入顺序或者最近最少使用(LRU)顺序
|
||||||
|
|
||||||
- TreeMap?????????????
|
- TreeMap:基于红黑树实现
|
||||||
|
|
||||||
- ConcurrentHashMap??????? Map?????<3F>p???????
|
- ConcurrentHashMap:线程安全 Map,不涉及同步加锁
|
||||||
|
|
||||||
# ????
|
# 反射
|
||||||
|
|
||||||
?????????? **Class** ??????????????§Û???????????????????????????????????? .class ??????????????????? Class ????
|
每个类都有一个 **Class** 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
|
||||||
|
|
||||||
????????? Class ?????????????????????????????? JVM ?§µ???????? Class.forName('com.mysql.jdbc.Driver.class') ????????????????????¡Â?????????? Class ????
|
类加载相当于 Class 对象的加载。类在第一次使用时才动态加载到 JVM 中,可以使用 Class.forName('com.mysql.jdbc.Driver.class') 这种方式来控制类的加载,该方法会返回一个 Class 对象。
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????? .class ???????????????????
|
反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。
|
||||||
|
|
||||||
Class ?? java.lang.reflect ???????????????java.lang.reflect ???????? **Field**??**Method** ??? **Constructor** ????????? get() ?? set() ???????????? Field ???????????¦²???????? invoke() ?????????? Method ???????????????????? Constructor ??????????
|
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库包含了 **Field**、**Method** 以及 **Constructor** 类。可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段,可以使用 invoke() 方法调用与 Method 对象关联的方法,可以用 Constructor 创建新的对象。
|
||||||
|
|
||||||
IDE ??¡Â???????????????????????????????????????????¦±??????????????????§Ô???????????
|
IDE 使用反射机制获取类的信息,在使用一个类的对象时,能够把类的字段、方法和构造函数等信息列出来供用户选择。
|
||||||
|
|
||||||
# ??
|
# 异常
|
||||||
|
|
||||||
Throwable ????????????¦Ê¦Ï???????????????????????**Error** ?? **Exception**?????? Error ??????????????????
|
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种:**Error** 和 **Exception**,其中 Error 用来表示编译时系统错误。
|
||||||
|
|
||||||
Exception ????????**?????** ?? **???????**???????????? try...catch... ???????§Õ??????????????§Ý?????????????????????????????? 0 ?????? Arithmetic Exception???????????????????????
|
Exception 分为两种:**受检异常** 和 **非受检异常**。受检异常需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;非受检异常是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序奔溃并且无法恢复。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/48f8f98e-8dfd-450d-8b5b-df4688f0d377.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/48f8f98e-8dfd-450d-8b5b-df4688f0d377.jpg)
|
||||||
|
|
||||||
# ?¦Ï?????
|
# 参考资料
|
||||||
|
|
||||||
- Eckel B, ????? , ??? , ?? . Java ?????? [M]. ??§Ö????????? , 2002.
|
- Eckel B, 埃克尔 , 昊鹏 , 等 . Java 编程思想 [M]. 机械工业出版社 , 2002.
|
||||||
- [Java ????????? ](https://segmentfault.com/a/1190000004527951)
|
- [Java 类初始化顺序 ](https://segmentfault.com/a/1190000004527951)
|
||||||
|
|
140
notes/Java 容器.md
140
notes/Java 容器.md
|
@ -1,78 +1,78 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [????](#????)
|
* [概览](#概览)
|
||||||
* [1. List](#1-list)
|
* [1. List](#1-list)
|
||||||
* [2. Set](#2-set)
|
* [2. Set](#2-set)
|
||||||
* [3. Queue](#3-queue)
|
* [3. Queue](#3-queue)
|
||||||
* [4. Map](#4-map)
|
* [4. Map](#4-map)
|
||||||
* [5. Java 1.0/1.1 ????](#5-java-1011-????)
|
* [5. Java 1.0/1.1 容器](#5-java-1011-容器)
|
||||||
* [?????快??????](#?????快??????)
|
* [容器中的设计模式](#容器中的设计模式)
|
||||||
* [1. ????????](#1-????????)
|
* [1. 迭代器模式](#1-迭代器模式)
|
||||||
* [2. ????????](#2-????????)
|
* [2. 适配器模式](#2-适配器模式)
|
||||||
* [???](#???)
|
* [散列](#散列)
|
||||||
* [??????](#??????)
|
* [源码分析](#源码分析)
|
||||||
* [1. ArraList](#1-arralist)
|
* [1. ArraList](#1-arralist)
|
||||||
* [2. Vector ?? Stack](#2-vector-??-stack)
|
* [2. Vector 与 Stack](#2-vector-与-stack)
|
||||||
* [3. LinkedList](#3-linkedlist)
|
* [3. LinkedList](#3-linkedlist)
|
||||||
* [4. TreeMap](#4-treemap)
|
* [4. TreeMap](#4-treemap)
|
||||||
* [5. HashMap](#5-hashmap)
|
* [5. HashMap](#5-hashmap)
|
||||||
* [6. LinkedHashMap](#6-linkedhashmap)
|
* [6. LinkedHashMap](#6-linkedhashmap)
|
||||||
* [7. ConcurrentHashMap](#7-concurrenthashmap)
|
* [7. ConcurrentHashMap](#7-concurrenthashmap)
|
||||||
* [?羊?????](#?羊?????)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ????
|
# 概览
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ebf03f56-f957-4435-9f8f-0f605661484d.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ebf03f56-f957-4435-9f8f-0f605661484d.jpg)
|
||||||
|
|
||||||
??????????? Collection ?? Map ?????Collection ??????? List??Set ??? Queue??
|
容器主要包括 Collection 和 Map 两种,Collection 又包含了 List、Set 以及 Queue。
|
||||||
|
|
||||||
## 1. List
|
## 1. List
|
||||||
|
|
||||||
- ArrayList???????????????????????????
|
- ArrayList:基于动态数组实现,支持随机访问;
|
||||||
|
|
||||||
- LinkedList????????????????????????????????????????????????技????????????????????LinkedList ????????????????抗??????妊?
|
- LinkedList:基于双向循环链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双端队列。
|
||||||
|
|
||||||
## 2. Set
|
## 2. Set
|
||||||
|
|
||||||
- HashSet?????? Hash ???????????????????????????
|
- HashSet:基于 Hash 实现,支持快速查找,但是失去有序性;
|
||||||
|
|
||||||
- TreeSet????????????????????????????完????? HashSet??
|
- TreeSet:基于红黑树实现,保持有序,但是查找效率不如 HashSet;
|
||||||
|
|
||||||
- LinkedListHashSet?????? HashSet ?????完?????????????????????????????????????????
|
- LinkedListHashSet:具有 HashSet 的查找效率,且内部使用链表维护元素的插入顺序,因此具有有序性。
|
||||||
|
|
||||||
## 3. Queue
|
## 3. Queue
|
||||||
|
|
||||||
???????????LinkedList ?? PriorityQueue?????? LinkedList ????????孝?PriorityQueue ???????????
|
只有两个实现:LinkedList 和 PriorityQueue,其中 LinkedList 支持双向队列,PriorityQueue 是基于堆结构实现。
|
||||||
|
|
||||||
## 4. Map
|
## 4. Map
|
||||||
|
|
||||||
- HashMap?????? Hash ???
|
- HashMap:基于 Hash 实现
|
||||||
|
|
||||||
- LinkedHashMap??????????????????????????????????????????????LRU?????
|
- LinkedHashMap:使用链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序
|
||||||
|
|
||||||
- TreeMap?????????????
|
- TreeMap:基于红黑树实现
|
||||||
|
|
||||||
- ConcurrentHashMap??????? Map?????纟?????? HashTable ?????????
|
- ConcurrentHashMap:线程安全 Map,不涉及类似于 HashTable 的同步加锁
|
||||||
|
|
||||||
## 5. Java 1.0/1.1 ????
|
## 5. Java 1.0/1.1 容器
|
||||||
|
|
||||||
??????????????????????????????????????????????
|
对于旧的容器,我们决不应该使用它们,只需要对它们进行了解。
|
||||||
|
|
||||||
- Vector???? ArrayList ??????????????????
|
- Vector:和 ArrayList 类似,但它是线程安全的
|
||||||
|
|
||||||
- HashTable???? HashMap ??????????????????
|
- HashTable:和 HashMap 类似,但它是线程安全的
|
||||||
|
|
||||||
# ?????快??????
|
# 容器中的设计模式
|
||||||
|
|
||||||
## 1. ????????
|
## 1. 迭代器模式
|
||||||
|
|
||||||
????????????????????????????? Iterator ??????????????????????????????????快?????
|
从概览图可以看到,每个集合类都有一个 Iterator 对象,可以通过这个迭代器对象来遍历集合中的元素。
|
||||||
|
|
||||||
[Java ?快???????? ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#92-java-%E5%86%85%E7%BD%AE%E7%9A%84%E8%BF%AD%E4%BB%A3%E5%99%A8)
|
[Java 中的迭代器模式 ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#92-java-%E5%86%85%E7%BD%AE%E7%9A%84%E8%BF%AD%E4%BB%A3%E5%99%A8)
|
||||||
|
|
||||||
## 2. ????????
|
## 2. 适配器模式
|
||||||
|
|
||||||
java.util.Arrays#asList() ????????????????? List ?????
|
java.util.Arrays#asList() 可以把数组类型转换为 List 类型。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
List list = Arrays.asList(1, 2, 3);
|
List list = Arrays.asList(1, 2, 3);
|
||||||
|
@ -80,44 +80,44 @@ java.util.Arrays#asList() ????????????????? List ?????
|
||||||
list = Arrays.asList(arr);
|
list = Arrays.asList(arr);
|
||||||
```
|
```
|
||||||
|
|
||||||
# ???
|
# 散列
|
||||||
|
|
||||||
??? hasCode() ??????????????????????????
|
使用 hasCode() 来返回散列值,使用的是对象的地址。
|
||||||
|
|
||||||
?? equals() ???????忪??????????????????????????????????????????????????????????????????????
|
而 equals() 是用来判断两个对象是否相等的,相等的两个对象散列值一定要相同,但是散列值相同的两个对象不一定相等。
|
||||||
|
|
||||||
??????????????????????
|
相等必须满足以下五个性质:
|
||||||
|
|
||||||
1. ?????
|
1. 自反性
|
||||||
2. ?????
|
2. 对称性
|
||||||
3. ??????
|
3. 传递性
|
||||||
4. ????????汍??? x.equals(y)?????????
|
4. 一致性(多次调用 x.equals(y),结果不变)
|
||||||
5. ???百汕??? null ????? x ???? x.equals(nul) ?????? false
|
5. 对任何不是 null 的对象 x 调用 x.equals(nul) 结果都为 false
|
||||||
|
|
||||||
# ??????
|
# 源码分析
|
||||||
|
|
||||||
????????? [ ?? - ???? ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E7%AC%AC%E4%B8%89%E7%AB%A0-%E6%9F%A5%E6%89%BE) ????????????????????抗???????
|
建议先阅读 [ 算法 - 查找 ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E7%AC%AC%E4%B8%89%E7%AB%A0-%E6%9F%A5%E6%89%BE) 部分,对集合类源码的理解有很大帮助。
|
||||||
|
|
||||||
????????[OpenJDK 1.7](http://download.java.net/openjdk/jdk7)
|
源码下载:[OpenJDK 1.7](http://download.java.net/openjdk/jdk7)
|
||||||
|
|
||||||
## 1. ArraList
|
## 1. ArraList
|
||||||
|
|
||||||
[ArraList.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/ArrayList.java)
|
[ArraList.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/ArrayList.java)
|
||||||
|
|
||||||
????? RandomAccess ??????????????????????????????????? ArrayList ??????????????
|
实现了 RandomAccess 接口,因此支持随机访问,这是理所当然的,因为 ArrayList 是基于数组实现的。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class ArrayList<E> extends AbstractList<E>
|
public class ArrayList<E> extends AbstractList<E>
|
||||||
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
|
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????????????? transient ???曳?????????????礵???????竹????????????????????????????????抖????????忱 writeObject() ?? readObject()??
|
基于数组实现,保存元素的数组使用 transient 修饰,这是因为该数组不一定所有位置都占满元素,因此也就没必要全部都进行序列化。需要重写 writeObject() 和 readObject()。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private transient Object[] elementData;
|
private transient Object[] elementData;
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????妊? 10
|
数组的默认大小为 10
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ArrayList(int initialCapacity) {
|
public ArrayList(int initialCapacity) {
|
||||||
|
@ -132,7 +132,7 @@ public ArrayList() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????? System.arraycopy() ???????我?????????????????????????????????????????????妊????????????????忱?????
|
删除元素时调用 System.arraycopy() 对元素进行复制,因此删除操作成本很高,最好在创建时就指定大概的容量大小,减少复制操作的执行次数。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public E remove(int index) {
|
public E remove(int index) {
|
||||||
|
@ -150,9 +150,9 @@ public E remove(int index) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????? ensureCapacity() ????????????????????????????????????????????????????????? 1.5 ????
|
添加元素时使用 ensureCapacity() 方法来保证容量足够,如果不够时,需要进行扩容,使得新容量为旧容量的 1.5 倍。
|
||||||
|
|
||||||
modCount ??????? ArrayList ?????<3F>?????????????????? add() ?? addAll() ?????????? ensureCapacity()?????????? ensureCapacity() ?忪? modCount ????????
|
modCount 用来记录 ArrayList 发生变化的次数,因为每次在进行 add() 和 addAll() 时都需要调用 ensureCapacity(),因此直接在 ensureCapacity() 中对 modCount 进行修改。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public void ensureCapacity(int minCapacity) {
|
public void ensureCapacity(int minCapacity) {
|
||||||
|
@ -190,7 +190,7 @@ private static int hugeCapacity(int minCapacity) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
????????抖???????????????????????????? modCount ??????????????????? ConcurrentModificationException??
|
在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private void writeObject(java.io.ObjectOutputStream s)
|
private void writeObject(java.io.ObjectOutputStream s)
|
||||||
|
@ -213,20 +213,20 @@ private void writeObject(java.io.ObjectOutputStream s)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**?? Vector ??????**
|
**和 Vector 的区别**
|
||||||
|
|
||||||
1. Vector ?? ArrayList ???????????????朵??????????? Vector ????????????????? ArrayList ????????????????? ArrayList ?????? Vector???????????????????????????????
|
1. Vector 和 ArrayList 几乎是完全相同的,唯一的区别在于 Vector 是同步的,因此开销就比 ArrayList 要大,访问要慢。最好使用 ArrayList 而不是 Vector,因为同步完全可以由程序员自己来控制;
|
||||||
2. Vector ??????????????妊?? 2 ??????? ArrayList ?? 1.5 ????
|
2. Vector 每次扩容请求其大小的 2 倍空间,而 ArrayList 是 1.5 倍。
|
||||||
|
|
||||||
????????????? ArrayList????????? Collections.synchronizedList(new ArrayList<>()); ?????????????? ArrayList?????????? concurrent ????????? CopyOnWriteArrayList ??
|
为了使用线程安全的 ArrayList,可以使用 Collections.synchronizedList(new ArrayList<>()); 返回一个线程安全的 ArrayList,也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类;
|
||||||
|
|
||||||
**?? LinkedList ??????**
|
**和 LinkedList 的区别**
|
||||||
|
|
||||||
1. ArrayList ??????????????LinkedList ??????????????????
|
1. ArrayList 基于动态数组实现,LinkedList 基于双向循环链表实现;
|
||||||
2. ArrayList ???????????LinkedList ??????
|
2. ArrayList 支持随机访问,LinkedList 不支持;
|
||||||
3. LinkedList ??????竹??????????????
|
3. LinkedList 在任意位置添加删除元素更快。
|
||||||
|
|
||||||
## 2. Vector ?? Stack
|
## 2. Vector 与 Stack
|
||||||
|
|
||||||
[Vector.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/Vector.java)
|
[Vector.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/Vector.java)
|
||||||
|
|
||||||
|
@ -242,13 +242,13 @@ private void writeObject(java.io.ObjectOutputStream s)
|
||||||
|
|
||||||
[HashMap.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/HashMap.java)
|
[HashMap.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/HashMap.java)
|
||||||
|
|
||||||
???????????????????
|
使用拉链法来解决冲突。
|
||||||
|
|
||||||
??????? capacity ? 16????????????????????? 2 ??灰??????????? Entry[] table ?????????size ?????????????????
|
默认容量 capacity 为 16,需要注意的是容量必须保证为 2 的次方。容量就是 Entry[] table 数组的长度,size 是数组的实际使用量。
|
||||||
|
|
||||||
threshold ?梀????? size ????????size ????妊?? threshold??????????????????????????????
|
threshold 规定了一个 size 的临界值,size 必须小于 threshold,如果大于等于,就必须进行扩容操作。
|
||||||
|
|
||||||
threshold = capacity * load_factor?????? load_factor ? table ????????????????load_factor ????????????????????????????完????????????
|
threshold = capacity * load_factor,其中 load_factor 为 table 数组能够使用的比例,load_factor 过大会导致聚簇的出现,从而影响查询和插入的效率,详见算法笔记。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
static final int DEFAULT_INITIAL_CAPACITY = 16;
|
static final int DEFAULT_INITIAL_CAPACITY = 16;
|
||||||
|
@ -268,7 +268,7 @@ final float loadFactor;
|
||||||
transient int modCount;
|
transient int modCount;
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????扭?????????????????????? capacity ????????????
|
从下面的添加元素代码中可以看出,当需要扩容时,令 capacity 为原来的两倍。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
void addEntry(int hash, K key, V value, int bucketIndex) {
|
void addEntry(int hash, K key, V value, int bucketIndex) {
|
||||||
|
@ -279,7 +279,7 @@ void addEntry(int hash, K key, V value, int bucketIndex) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Entry ??????????????????????快? next ????????抖??????芍?
|
Entry 用来表示一个键值对元素,其中的 next 指针在序列化时会使用。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
static class Entry<K,V> implements Map.Entry<K,V> {
|
static class Entry<K,V> implements Map.Entry<K,V> {
|
||||||
|
@ -290,7 +290,7 @@ static class Entry<K,V> implements Map.Entry<K,V> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
get() ???????????????????key ? null ?? ??? null?????扭?????? HashMap ??????? null ???????
|
get() 操作需要分成两种情况,key 为 null 和 不为 null,从中可以看出 HashMap 允许插入 null 作为键。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public V get(Object key) {
|
public V get(Object key) {
|
||||||
|
@ -306,7 +306,7 @@ public V get(Object key) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
put() ???????????? key ???? null ????????????????????????????? key ? null ??????????????? key ? null ???????????????????? 0 竹?????????? null ??????? hash ??????????????¯?????????????
|
put() 操作也需要根据 key 是否为 null 做不同的处理,需要注意的是如果本来没有 key 为 null 的键值对,新插入一个 key 为 null 的键值对时默认是放在数组的 0 位置,这是因为 null 不能计算 hash 值,也就无法知道应该放在哪个链表上。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public V put(K key, V value) {
|
public V put(K key, V value) {
|
||||||
|
@ -354,8 +354,8 @@ private V putForNullKey(V value) {
|
||||||
|
|
||||||
[ConcurrentHashMap.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/HashMap.java)
|
[ConcurrentHashMap.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/HashMap.java)
|
||||||
|
|
||||||
[ ??? ConcurrentHashMap ?????????????? ](https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/)
|
[ 探索 ConcurrentHashMap 高并发性的实现机制 ](https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/)
|
||||||
|
|
||||||
# ?羊?????
|
# 参考资料
|
||||||
|
|
||||||
- Java ??????
|
- Java 编程思想
|
||||||
|
|
1220
notes/Leetcode 题解.md
1220
notes/Leetcode 题解.md
File diff suppressed because it is too large
Load Diff
852
notes/Linux.md
852
notes/Linux.md
File diff suppressed because it is too large
Load Diff
396
notes/MySQL.md
396
notes/MySQL.md
|
@ -1,226 +1,226 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [?𣸑????](#?𣸑????)
|
* [存储引擎](#存储引擎)
|
||||||
* [1. InnoDB](#1-innodb)
|
* [1. InnoDB](#1-innodb)
|
||||||
* [2. MyISAM](#2-myisam)
|
* [2. MyISAM](#2-myisam)
|
||||||
* [3. InnoDB ?? MyISAM ????](#3-innodb-??-myisam-????)
|
* [3. InnoDB 与 MyISAM 的比较](#3-innodb-与-myisam-的比较)
|
||||||
* [????????](#????????)
|
* [数据类型](#数据类型)
|
||||||
* [1. ????](#1-????)
|
* [1. 整型](#1-整型)
|
||||||
* [2. ??????](#2-??????)
|
* [2. 浮点数](#2-浮点数)
|
||||||
* [3. ?????](#3-?????)
|
* [3. 字符串](#3-字符串)
|
||||||
* [4. ????????](#4-????????)
|
* [4. 时间和日期](#4-时间和日期)
|
||||||
* [????](#????)
|
* [索引](#索引)
|
||||||
* [1. ????????](#1-????????)
|
* [1. 索引分类](#1-索引分类)
|
||||||
* [1.1 B-Tree ????](#11-b-tree-????)
|
* [1.1 B-Tree 索引](#11-b-tree-索引)
|
||||||
* [1.2 ???????](#12-???????)
|
* [1.2 哈希索引](#12-哈希索引)
|
||||||
* [1.3. ????????????R-Tree??](#13-????????????r-tree??)
|
* [1.3. 空间索引数据(R-Tree)](#13-空间索引数据r-tree)
|
||||||
* [1.4 ???????](#14-???????)
|
* [1.4 全文索引](#14-全文索引)
|
||||||
* [2. ?????????](#2-?????????)
|
* [2. 索引的优点](#2-索引的优点)
|
||||||
* [3. ???????](#3-???????)
|
* [3. 索引优化](#3-索引优化)
|
||||||
* [3.1 ????????](#31-????????)
|
* [3.1 独立的列](#31-独立的列)
|
||||||
* [3.2 ??????](#32-??????)
|
* [3.2 前缀索引](#32-前缀索引)
|
||||||
* [3.3 ????????](#33-????????)
|
* [3.3 多列索引](#33-多列索引)
|
||||||
* [3.4 ?????快????](#34-?????快????)
|
* [3.4 索引列的顺序](#34-索引列的顺序)
|
||||||
* [3.5 ???????](#35-???????)
|
* [3.5 聚簇索引](#35-聚簇索引)
|
||||||
* [3.6 ????????](#36-????????)
|
* [3.6 覆盖索引](#36-覆盖索引)
|
||||||
* [4. B-Tree ?? B+Tree ???](#4-b-tree-??-b+tree-???)
|
* [4. B-Tree 和 B+Tree 原理](#4-b-tree-和-b+tree-原理)
|
||||||
* [4. 1 B-Tree](#4-1-b-tree)
|
* [4. 1 B-Tree](#4-1-b-tree)
|
||||||
* [4.2 B+Tree](#42-b+tree)
|
* [4.2 B+Tree](#42-b+tree)
|
||||||
* [4.3 ?????????????? B+Tree](#43-??????????????-b+tree)
|
* [4.3 带有顺序访问指针的 B+Tree](#43-带有顺序访问指针的-b+tree)
|
||||||
* [4.4 ?????? B-Tree ?? B+Tree](#44-??????-b-tree-??-b+tree)
|
* [4.4 为什么使用 B-Tree 和 B+Tree](#44-为什么使用-b-tree-和-b+tree)
|
||||||
* [??????????](#??????????)
|
* [查询性能优化](#查询性能优化)
|
||||||
* [1. Explain](#1-explain)
|
* [1. Explain](#1-explain)
|
||||||
* [2. ??????????](#2-??????????)
|
* [2. 减少返回的列](#2-减少返回的列)
|
||||||
* [3. ??????????](#3-??????????)
|
* [3. 减少返回的行](#3-减少返回的行)
|
||||||
* [4. ????? DELETE ?? INSERT ???](#4-?????-delete-??-insert-???)
|
* [4. 拆分大的 DELETE 或 INSERT 语句](#4-拆分大的-delete-或-insert-语句)
|
||||||
* [???????](#???????)
|
* [分库与分表](#分库与分表)
|
||||||
* [?????????????](#?????????????)
|
* [故障转移和故障恢复](#故障转移和故障恢复)
|
||||||
* [1. ???????](#1-???????)
|
* [1. 故障转移](#1-故障转移)
|
||||||
* [2. ??????](#2-??????)
|
* [2. 故障恢复](#2-故障恢复)
|
||||||
* [?羊?????](#?羊?????)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ?𣸑????
|
# 存储引擎
|
||||||
|
|
||||||
## 1. InnoDB
|
## 1. InnoDB
|
||||||
|
|
||||||
InnoDB ?? MySQL ??????????????秄???????? InnoDB ??????????????????????????𣸑???紫
|
InnoDB 是 MySQL 的默认事务型引擎,只有在需要 InnoDB 不支持的特性时,才考虑使用其它存储引擎。
|
||||||
|
|
||||||
???? MVCC ?????????????????????????????????????????????????
|
采用 MVCC 来支持高并发,并且实现了四个标准的隔离级别,默认级别是可重复读。
|
||||||
|
|
||||||
?????????????????????????????????????抗?????????
|
表是基于聚簇索引建立的,它对主键的查询性能有很高的提升。
|
||||||
|
|
||||||
????????????????????????????????????????????????????????忱??? hash ??????????????????????????????????????????????????????????
|
内部做了很多优化,包括从磁盘读取数据时采用的可预测性读,能够自动在内存中创建 hash 索引以加速读操作的自适应哈希索引,以及能够加速插入操作的插入缓冲区等。
|
||||||
|
|
||||||
????宏???????????????????????
|
通过一些机制和工具支持真正的热备份。
|
||||||
|
|
||||||
## 2. MyISAM
|
## 2. MyISAM
|
||||||
|
|
||||||
MyISAM ??????????????????????????????????<3F>????GIS??????? MyISAM ???????????技?????????????????????????
|
MyISAM 提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等。但 MyISAM 不支持事务和行级锁,而且奔溃后无法安全恢复。
|
||||||
|
|
||||||
????????????????????????妊?
|
只能对整张表加锁,而不是针对行。
|
||||||
|
|
||||||
????????????????技??????????????????????????????????????????????宏????????????????????????????
|
可以手工或者自动执行检查和修复操作,但是和事务恢复以及奔溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。
|
||||||
|
|
||||||
???????????????????妊?
|
可以包含动态或者静态的行。
|
||||||
|
|
||||||
???????? DELAY_KEY_WRITE ??????????????????????????????????????????忱???????????忱??????快??????????????????????????????????????????????????忱????????????????????????忱?????????????????????????????????????????????????????????
|
如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机奔溃时会造成索引损坏,需要执行修复操作。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????? MyISAM ?????
|
如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表适合采用 MyISAM 压缩表。
|
||||||
|
|
||||||
???????????????????妊?????????????????????????????????? MyISAM??
|
对于只读数据,或者表比较小、可以容忍修复操作,则依然可以继续使用 MyISAM。
|
||||||
|
|
||||||
MyISAM ?????????????????𣸑?????????宏???????????芍?
|
MyISAM 设计简单,数据以紧密格式存储,所以在某些场景下性能很好。
|
||||||
|
|
||||||
## 3. InnoDB ?? MyISAM ????
|
## 3. InnoDB 与 MyISAM 的比较
|
||||||
|
|
||||||
**????**
|
**事务**
|
||||||
|
|
||||||
InnoDB ??????????
|
InnoDB 是事务型的。
|
||||||
|
|
||||||
**????**
|
**备份**
|
||||||
|
|
||||||
InnoDB ?????????????
|
InnoDB 支持在线热备份。
|
||||||
|
|
||||||
**???????**
|
**奔溃恢复**
|
||||||
|
|
||||||
MyISAM ??????????????? InnoDB ??????????????????????
|
MyISAM 奔溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
|
||||||
|
|
||||||
**????**
|
**并发**
|
||||||
|
|
||||||
MyISAM ??????????? InnoDB ??????技?????
|
MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
|
||||||
|
|
||||||
**????????**
|
**其它特性**
|
||||||
|
|
||||||
MyISAM ????????????????????????
|
MyISAM 支持全文索引,地理空间索引;
|
||||||
|
|
||||||
# ????????
|
# 数据类型
|
||||||
|
|
||||||
## 1. ????
|
## 1. 整型
|
||||||
|
|
||||||
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT ?????? 8, 16, 24, 64 竹?𣸑????????????妊??????芍?
|
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 64 位存储空间,一般情况下越小的列越好。
|
||||||
|
|
||||||
INT(11) ?快????????梀??????????????????????????𣸑???????????????????
|
INT(11) 中的数字只是规定了交互工具显示字符的个数,对于存储和计算来说是没有意义的。
|
||||||
|
|
||||||
## 2. ??????
|
## 2. 浮点数
|
||||||
|
|
||||||
FLOAT ?? DOUBLE ??????????DECIMAL ??????妊???????CPU ????????????????????? DECIMAl ??????????? DECIMAL ?????????????????????????
|
FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型。CPU 原生支持浮点运算,但是不支持 DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需要更高的代价。
|
||||||
|
|
||||||
FLOAT??DOUBLE ?? DECIMAL ??????????扭????? DECIMAL(18, 9) ?????? 18 竹??? 9 竹?𣸑妊?????????? 9 竹?𣸑?????????
|
FLOAT、DOUBLE 和 DECIMAL 都可以指定列宽,例如 DECIMAL(18, 9) 表示总共 18 位,取 9 位存储小数部分,剩下 9 位存储整数部分。
|
||||||
|
|
||||||
## 3. ?????
|
## 3. 字符串
|
||||||
|
|
||||||
????? CHAR ?? VARCHAR ?????????????????????????????
|
主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。
|
||||||
|
|
||||||
VARCHAR ??????????????????????????𣸑??????????????????? UPDATE ????????忌??????????????????????????????妊????????忪?????????MyISAM ???志????????汛𣸑???? InnoDB ??????????????戒??????
|
VARCHAR 这种变长类型能够节省空间,因为只需要存储必要的内容。但是在执行 UPDATE 时可能会使行变得比原来长,当超出一个页所能容纳的大小时,就要执行额外的操作,MyISAM 会将行拆成不同的片段存储,而 InnoDB 则需要分裂页来使行放进页内。
|
||||||
|
|
||||||
VARCHAR ??????????汕????? CHAR ???????
|
VARCHAR 会保留字符串末尾的空格,而 CHAR 会删除。
|
||||||
|
|
||||||
## 4. ????????
|
## 4. 时间和日期
|
||||||
|
|
||||||
MySQL ?????????????????????????DATATIME ?? TIMESTAMP??
|
MySQL 提供了两种相似的日期时间类型:DATATIME 和 TIMESTAMP。
|
||||||
|
|
||||||
**DATATIME**
|
**DATATIME**
|
||||||
|
|
||||||
???????? 1001 ?? 9999 ????????????????????? 8 ????𣸑???
|
能够保存从 1001 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。
|
||||||
|
|
||||||
???????????
|
它与时区无关。
|
||||||
|
|
||||||
?????????MySQL ???????????????????????? DATATIME ??????<3F>2008-01016 22:37:08???????? ANSI ????????????????????????
|
默认情况下,MySQL 以一种可排序的、无歧义的格式显示 DATATIME 值,例如“2008-01016 22:37:08”,这是 ANSI 标准定义的日期和时间表示方法。
|
||||||
|
|
||||||
**TIMESTAMP**
|
**TIMESTAMP**
|
||||||
|
|
||||||
?? UNIX ?????????????? 1970 ?? 1 ?? 1 ????????????????????????????????? 4 ????????????? 1970 ?? ?? 2038 ??
|
和 UNIX 时间戳相同,保存从 1970 年 1 月 1 日午夜(格林威治时间)以来的秒数,使用 4 个字节,只能表示从 1970 年 到 2038 年。
|
||||||
|
|
||||||
????????抄??
|
它和时区有关。
|
||||||
|
|
||||||
MySQL ???? FROM_UNIXTIME() ?????? Unxi ??????????????????? UNIX_TIMESTAMP() ?????????????? Unix ??????
|
MySQL 提供了 FROM_UNIXTIME() 函数把 Unxi 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 Unix 时间戳。
|
||||||
|
|
||||||
??????????????????????? TIMESTAMP ?快?????????????????????
|
默认情况下,如果插入时没有指定 TIMESTAMP 列的值,会将这个值设置为当前时间。
|
||||||
|
|
||||||
????????? TIMESTAMP????????? DATETIME ???完??????
|
应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。
|
||||||
|
|
||||||
# ????
|
# 索引
|
||||||
|
|
||||||
????????𣸑?????????????????????????????????????𣸑??????志?????????????????
|
索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。
|
||||||
|
|
||||||
???????????????????????????????????
|
索引能够轻易将查询性能提升几个数量级。
|
||||||
|
|
||||||
??????妊???????????????????????????????完???????快?????????????????完????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¯?????????
|
对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效。对于中到大型的表,索引就非常有效。但是对于特大型的表,建立和使用索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。
|
||||||
|
|
||||||
## 1. ????????
|
## 1. 索引分类
|
||||||
|
|
||||||
### 1.1 B-Tree ????
|
### 1.1 B-Tree 索引
|
||||||
|
|
||||||
B-Tree ?????????? MySQL ?𣸑?????????????????
|
B-Tree 索引是大多数 MySQL 存储引擎的默认索引类型。
|
||||||
|
|
||||||
???????????????????屔?????????????????????????????????
|
因为不再需要进行全表扫描,只需要对树进行搜索即可,因此查找速度快很多。
|
||||||
|
|
||||||
????????????????????孝?????????抄????????B-Tree ?????????????????????朱?????????????技?????????????????????????
|
可以指定多个列作为索引列,多个索引列共同组成键。B-Tree 索引适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。
|
||||||
|
|
||||||
?????????????????????????????<3F>
|
除了用于查找,还可以用于排序和分组。
|
||||||
|
|
||||||
???????????????快??????志??????????????????
|
如果不是按照索引列的顺序进行查找,则无法使用索引。
|
||||||
|
|
||||||
### 1.2 ???????
|
### 1.2 哈希索引
|
||||||
|
|
||||||
????????????????????????
|
基于哈希表实现,优点是查找非常快。
|
||||||
|
|
||||||
?? MySQL ????? Memory ??????????????????
|
在 MySQL 中只有 Memory 引擎显式支持哈希索引。
|
||||||
|
|
||||||
InnoDB ?????????????????妊????????????????????????????????????????????? B-Tree ???????????????????????????????? B-Tree ???????抄?????????宏??????????????????
|
InnoDB 引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B-Tree 索引之上再创建一个哈希索引,这样就让 B-Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。
|
||||||
|
|
||||||
?????????????????????????????????𣸑?????????????????????快???????????妊???????????????快??快???????????????????????????????????????????????????????????????????????????????朱??????????????????????????迆?????
|
限制:哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能影响并不明显;无法用于分组与排序;只支持精确查找,无法用于部分查找和范围查找;如果哈希冲突很多,查找速度会变得很慢。
|
||||||
|
|
||||||
### 1.3. ????????????R-Tree??
|
### 1.3. 空间索引数据(R-Tree)
|
||||||
|
|
||||||
MyISAM ?𣸑??????????????????????????????𣸑??
|
MyISAM 存储引擎支持空间索引,可以用于地理数据存储。
|
||||||
|
|
||||||
??????????????????????????????????完?????????????????????????
|
空间索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。
|
||||||
|
|
||||||
### 1.4 ???????
|
### 1.4 全文索引
|
||||||
|
|
||||||
MyISAM ?𣸑???????????????????????????快??????????????????????快????
|
MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较索引中的值。
|
||||||
|
|
||||||
??? MATCH AGAINST????????????? WHERE??
|
使用 MATCH AGAINST,而不是普通的 WHERE。
|
||||||
|
|
||||||
## 2. ?????????
|
## 2. 索引的优点
|
||||||
|
|
||||||
- ????????????????????????????
|
- 大大减少了服务器需要扫描的数据量;
|
||||||
|
|
||||||
- ??????????????????????????????
|
- 帮助服务器避免进行排序和创建临时表;
|
||||||
|
|
||||||
- ????? I/O ?????? I/O??
|
- 将随机 I/O 变为顺序 I/O。
|
||||||
|
|
||||||
## 3. ???????
|
## 3. 索引优化
|
||||||
|
|
||||||
### 3.1 ????????
|
### 3.1 独立的列
|
||||||
|
|
||||||
????志??????????志?????????????????????????????????????????????????
|
在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。
|
||||||
|
|
||||||
?????????????????? actor_id ?快???????
|
例如下面的查询不能使用 actor_id 列的索引:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;
|
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 ??????
|
### 3.2 前缀索引
|
||||||
|
|
||||||
???? BLOB??TEXT ?? VARCHAR ??????孝??????????????????????????????????
|
对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。
|
||||||
|
|
||||||
???????????????????? **?????????** ?????????????????????????????????????????????完???????????? 1 ???????????????朵???????????????
|
对于前缀长度的选取需要根据 **索引选择性** 来确定:不重复的索引值和记录总数的比值。选择性越高,查询效率也越高。最大值为 1 ,此时每个记录都有唯一的索引与其对应。
|
||||||
|
|
||||||
### 3.3 ????????
|
### 3.3 多列索引
|
||||||
|
|
||||||
??????????????????????志????????????????????????????????????芍??????????????孝????? actor_id ?? file_id ???????????????
|
在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。例如下面的语句中,最好把 actor_id 和 file_id 设置为多列索引。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT file_id, actor_ id FROM sakila.film_actor
|
SELECT file_id, actor_ id FROM sakila.film_actor
|
||||||
WhERE actor_id = 1 OR film_id = 1;
|
WhERE actor_id = 1 OR film_id = 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.4 ?????快????
|
### 3.4 索引列的顺序
|
||||||
|
|
||||||
?????????????????戒?????秄????????????????? customer_id ???????? staff_id ???????????? customer_id ?戒??????????????紫
|
让选择性最强的索引列放在前面,例如下面显示的结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
|
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
|
||||||
|
@ -235,107 +235,107 @@ customer_id_selectivity: 0.0373
|
||||||
COUNT(*): 16049
|
COUNT(*): 16049
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.5 ???????
|
### 3.5 聚簇索引
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b9e9ae8c-e216-4c01-b267-a50dbeb98fa4.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b9e9ae8c-e216-4c01-b267-a50dbeb98fa4.jpg)
|
||||||
|
|
||||||
????????????????????????????????????𣸑?????
|
聚簇索引并不是一种索引类型,而是一种数据存储方式。
|
||||||
|
|
||||||
????????????????抗?????????????𣸑?????InnoDB ???????????????忱???? B-Tree ???????妊?
|
术语“聚簇”表示数据行和相邻的键值紧密地存储在一起,InnoDB 的聚簇索引的数据行存放在 B-Tree 的叶子页中。
|
||||||
|
|
||||||
?????????????忱???????????????????????????????????????????
|
因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
|
||||||
|
|
||||||
**???**
|
**优点**
|
||||||
|
|
||||||
1. ??????????????????????? I/O ??????
|
1. 可以把相关数据保存在一起,减少 I/O 操作;
|
||||||
2. ???????????? B-Tree ?孝??????????????
|
2. 因为数据保存在 B-Tree 中,因此数据访问更快。
|
||||||
|
|
||||||
**???**
|
**缺点**
|
||||||
|
|
||||||
1. ?????????????????? I/O ??????????????????????????????????秄????????????????
|
1. 聚簇索引最大限度提高了 I/O 密集型应用的性能,但是如果数据全部放在内存,就没必要用聚簇索引。
|
||||||
2. ???????????????????????????????????????????
|
2. 插入速度严重依赖于插入顺序,按主键的顺序插入是最快的。
|
||||||
3. ????????????????????????????忪???????????竹?芍?
|
3. 更新操作代价很高,因为每个被更新的行都会移动到新的位置。
|
||||||
4. ?????????????????孝??𣸑????????????????????????????孝????????㊣?????????????
|
4. 当插入到某个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行,页分裂会导致表占用更多的磁盘空间。
|
||||||
5. ????忌????屔????????????????????𣸑?????????????????????????????????????
|
5. 如果行比较稀疏,或者由于页分裂导致数据存储不连续时,聚簇索引可能导致全表扫描速度变慢。
|
||||||
|
|
||||||
### 3.6 ????????
|
### 3.6 覆盖索引
|
||||||
|
|
||||||
??????????????????????汍????
|
索引包含所有需要查询的字段的值。
|
||||||
|
|
||||||
## 4. B-Tree ?? B+Tree ???
|
## 4. B-Tree 和 B+Tree 原理
|
||||||
|
|
||||||
### 4. 1 B-Tree
|
### 4. 1 B-Tree
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg)
|
||||||
|
|
||||||
??????? B-Tree??????????????????????????? [key, data]??key ?????????data ????????? key ????????
|
为了描述 B-Tree,首先定义一条数据记录为一个二元组 [key, data],key 为记录的键,data 为数据记录除 key 外的数据。
|
||||||
|
|
||||||
B-Tree ???????????????????????
|
B-Tree 是满足下列条件的数据结构:
|
||||||
|
|
||||||
- ?????????????????????????? B-Tree ???????
|
- 所有叶节点具有相同的深度,也就是说 B-Tree 是平衡的;
|
||||||
- ???????快? key ????????????孝?
|
- 一个节点中的 key 从左到右非递减排列;
|
||||||
- ?????????????????? key ????? key<sub>i</sub> ?? key<sub>i+1</sub>?????? null?????????????????? key ???? key<sub>i</sub> ??妊?? key<sub>i+1</sub>??
|
- 如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null,则该指针指向节点的所有 key 大于 key<sub>i</sub> 且小于 key<sub>i+1</sub>。
|
||||||
|
|
||||||
?? B-Tree ?忘? key ?????????????????????????????忪?????????????????????? data????????????????????????????志????????????????? null ????????????????????????
|
在 B-Tree 中按 key 检索数据的算法非常直观:首先从根节点进行二分查找,如果找到则返回对应节点的 data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或找到 null 指针,前者查找成功,后者查找失败。
|
||||||
|
|
||||||
???????????????????????? B-Tree ????????????????????????????????????????????????????????? B-Tree ?????
|
由于插入删除新的数据记录会破坏 B-Tree 的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持 B-Tree 性质。
|
||||||
|
|
||||||
### 4.2 B+Tree
|
### 4.2 B+Tree
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg)
|
||||||
|
|
||||||
?? B-Tree ????B+Tree ??????????
|
与 B-Tree 相比,B+Tree 有以下不同点:
|
||||||
|
|
||||||
- ??????????????? 2d ?????? 2d+1??
|
- 每个节点的指针上限为 2d 而不是 2d+1;
|
||||||
- ?????𣸑 data????𣸑 key????????𣸑???
|
- 内节点不存储 data,只存储 key,叶子节点不存储指针。
|
||||||
|
|
||||||
### 4.3 ?????????????? B+Tree
|
### 4.3 带有顺序访问指针的 B+Tree
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg)
|
||||||
|
|
||||||
????????????????????????? B+Tree ????????? B+Tree ????????????????????????????????????????????????????????????????????????
|
一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 基础上进行了优化,在叶子节点增加了顺序访问指针,做这个优化的目的是为了提高区间访问的性能。
|
||||||
|
|
||||||
### 4.4 ?????? B-Tree ?? B+Tree
|
### 4.4 为什么使用 B-Tree 和 B+Tree
|
||||||
|
|
||||||
?????????????????????????????????????????????????????? B-/+Tree ???????????
|
红黑树等数据结构也可以用来实现索引,但是文件系统及数据库系统普遍采用 B-/+Tree 作为索引结构。
|
||||||
|
|
||||||
???????????𣸑????????<3F>?????????????????????????𣸑?????????????妊????<3F>????𣸑???????????????????孝?????妊???? 4k??????????????????竹?????????
|
页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为 4k),主存和磁盘以页为单位交换数据。
|
||||||
|
|
||||||
?????????????????????????????𣸑??????孝???????????????????????????𣸑????????????????? I/O?????????????????????????????汎?????????????????????????????????????????????????????????????????璨?????????????????????芍????????????????????????????????????????????妊?????????????????????????????? I/O ????????????B-Tree ????米????????? h-1 ?? I/O??????????𠯫???????????? O(h)=O(logdN)????????????孝????? d ??????????????????? 100????? h ???妊??????????? 3??????????????????h ????????????????????????????????????????????????????????完??????? B-Tree ????
|
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。为了减少磁盘 I/O,磁盘往往不是严格按需读取,而是每次都会预读。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次 I/O 就可以完全载入。B-Tree 中一次检索最多需要 h-1 次 I/O(根节点常驻内存),渐进复杂度为 O(h)=O(logdN)。一般实际应用中,出度 d 是非常大的数字,通常超过 100,因此 h 非常小(通常不超过 3)。而红黑树这种结构,h 明显要深的多。并且于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,效率明显比 B-Tree 差很多。
|
||||||
|
|
||||||
B+Tree ????????????????????????? d ?抄?????? B+Tree ????????? data ??????????我??????????我?????????
|
B+Tree 更适合外存索引,原因和内节点出度 d 有关。由于 B+Tree 内节点去掉了 data 域,因此可以拥有更大的出度,拥有更好的性能。
|
||||||
|
|
||||||
# ??????????
|
# 查询性能优化
|
||||||
|
|
||||||
## 1. Explain
|
## 1. Explain
|
||||||
|
|
||||||
???????? SQL ???????????忌???????????孝?
|
用来分析 SQL 语句,分析结果中比较重要的字段有:
|
||||||
|
|
||||||
- select_type : ?????????技?????????????????
|
- select_type : 查询类型,有简单查询、联合查询和子查询
|
||||||
|
|
||||||
- key : ????????
|
- key : 使用的索引
|
||||||
|
|
||||||
- rows : ????????
|
- rows : 扫描的行数
|
||||||
|
|
||||||
## 2. ??????????
|
## 2. 减少返回的列
|
||||||
|
|
||||||
???????????????????????????????????????????????????????妊?
|
慢查询主要是因为访问了过多数据,除了访问过多行之外,也包括访问过多列。
|
||||||
|
|
||||||
??辰????? SELECT * ???????????????????妊?
|
最好不要使用 SELECT * 语句,要根据需要选择查询的列。
|
||||||
|
|
||||||
## 3. ??????????
|
## 3. 减少返回的行
|
||||||
|
|
||||||
?????? LIMIT ???????????????宏?妊?
|
最好使用 LIMIT 语句来取出想要的那些行。
|
||||||
|
|
||||||
????????????????????????????????畟????????????????????????????????????????????屔???????????????<3F>?技?????????? Explain ???????????? rows ????????????????
|
还可以建立索引来减少条件语句的全表扫描。例如对于下面的语句,不适用索引的情况下需要进行全表扫描,而使用索引只需要扫描几行记录即可,使用 Explain 语句可以通过观察 rows 字段来看出这种差异。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT * FROM sakila.film_actor WHERE film_id = 1;
|
SELECT * FROM sakila.film_actor WHERE film_id = 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. ????? DELETE ?? INSERT ???
|
## 4. 拆分大的 DELETE 或 INSERT 语句
|
||||||
|
|
||||||
??????????快???????????????????????????????????????????????????????妊????????????
|
如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
DELEFT FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH);
|
DELEFT FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH);
|
||||||
|
@ -348,74 +348,74 @@ do {
|
||||||
} while rows_affected > 0
|
} while rows_affected > 0
|
||||||
```
|
```
|
||||||
|
|
||||||
# ???????
|
# 分库与分表
|
||||||
|
|
||||||
**1. ????????????**
|
**1. 分表与分区的不同**
|
||||||
|
|
||||||
????????????????妊????宏妊????志???????????????????????????????????<3F>??宏???????𣸑??????????????????𣸑???????????????????㊣????????????
|
分表,就是讲一张表分成多个小表,这些小表拥有不同的表名;而分区是将一张表的数据分为多个区块,这些区块可以存储在同一个磁盘上,也可以存储在不同的磁盘上,这种方式下表仍然只有一个。
|
||||||
|
|
||||||
**2. ??¯??????????**
|
**2. 使用分库与分表的原因**
|
||||||
|
|
||||||
??????????????????????快???????????????快?????????????????????忱????????????????????
|
随着时间和业务的发展,数据库中的表会越来越多,并且表中的数据量也会越来越大,那么读写操作的开销也会随着增大。
|
||||||
|
|
||||||
**3. ????戒?**
|
**3. 垂直切分**
|
||||||
|
|
||||||
??????????<3F>??????忍?????????????????????????縺??????????????? payDB?????????? userDB ???????????𣸑?????????抄??????????抄???
|
将表按功能模块、关系密切程度划分出来,部署到不同的库上。例如,我们会建立商品数据库 payDB、用户数据库 userDB 等,分别用来存储项目与商品有关的表和与用户有关的表。
|
||||||
|
|
||||||
**4. ???戒?**
|
**4. 水平切分**
|
||||||
|
|
||||||
????快??????????????𣸑??????????????孝????<3F> id ??????????????抖????
|
把表中的数据按照某种规则存储到多个结构相同的表中,例如按 id 的散列值、性别等进行划分,
|
||||||
|
|
||||||
**5. ????戒??????戒?????**
|
**5. 垂直切分与水平切分的选择**
|
||||||
|
|
||||||
?????????快???????????????????????????????????戒????????
|
如果数据库中的表太多,并且项目各项业务逻辑清晰,那么垂直切分是首选。
|
||||||
|
|
||||||
??????????????????????????????????????戒??
|
如果数据库的表不多,但是单表的数据量很大,应该选择水平切分。
|
||||||
|
|
||||||
**6. ???戒???????**
|
**6. 水平切分的实现方式**
|
||||||
|
|
||||||
????????? merge ?𣸑???紫
|
最简单的是使用 merge 存储引擎。
|
||||||
|
|
||||||
**7. ???????????????**
|
**7. 分库与分表存在的问题**
|
||||||
|
|
||||||
(1) ????????
|
(1) 事务问题
|
||||||
|
|
||||||
????戒???????????????𣸑??????????????????????????????????????????????????????????????????????????????????????????????車????尿????????污???????????????????????????????
|
在执行分库分表之后,由于数据存储到了不同的库上,数据库事务管理出现了困难。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价;如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
|
||||||
|
|
||||||
(2) ?????????????
|
(2) 跨库跨表连接问题
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????竹?????????????????????????????????????????汕????????????????????忪?汕?????阱?
|
在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上。这时,表的连接操作将受到限制,我们无法连接位于不同分库的表,也无法连接分表粒度不同的表,导致原本只需要一次查询就能够完成的业务需要进行多次才能完成。
|
||||||
|
|
||||||
# ?????????????
|
# 故障转移和故障恢复
|
||||||
|
|
||||||
?????????????抖???????????????????抖???????????????????????????????????????抖?????????????????????????
|
故障转移也叫做切换,当主库出现故障时就切换到备库,使备库成为主库。故障恢复顾名思义就是从故障中恢复过来,并且保证数据的正确性。
|
||||||
|
|
||||||
## 1. ???????
|
## 1. 故障转移
|
||||||
|
|
||||||
**1.1 ??????????抖????**
|
**1.1 提升备库或切换角色**
|
||||||
|
|
||||||
??????????????????????????-????????快?????????????????
|
提升一台备库为主库,或者在一个主-主复制结构中调整主动和被动角色。
|
||||||
|
|
||||||
**1.2 ???? IP ????? IP ?抄?**
|
**1.2 虚拟 IP 地址和 IP 托管**
|
||||||
|
|
||||||
? MySQL ???????????? IP ??????? MySQL ????完???????? IP ??????????? MySQL ?????????
|
为 MySQL 实例指定一个逻辑 IP 地址,当 MySQL 实例失效时,可以将 IP 地址转移到另一台 MySQL 服务器上。
|
||||||
|
|
||||||
**1.3 ?技?????????**
|
**1.3 中间件解决方案**
|
||||||
|
|
||||||
???????????﹞????????????????????????
|
通过代理,可以路由流量到可以使用的服务器上。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fabd5fa0-b75e-48d0-9e2c-31471945ceb9.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fabd5fa0-b75e-48d0-9e2c-31471945ceb9.jpg)
|
||||||
|
|
||||||
**1.4 ??????忱?????????**
|
**1.4 在应用中处理故障转移**
|
||||||
|
|
||||||
??????????????????扭???????????????????
|
将故障转移整合到应用中可能导致应用变得太过笨拙。
|
||||||
|
|
||||||
## 2. ??????
|
## 2. 故障恢复
|
||||||
|
|
||||||
|
|
||||||
# ?羊?????
|
# 参考资料
|
||||||
|
|
||||||
- ?????? MySQL
|
- 高性能 MySQL
|
||||||
- [MySQL ????????????????????? ](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
|
- [MySQL 索引背后的数据结构及算法原理 ](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
|
||||||
- [MySQL ???????????? ](http://www.runoob.com/w3cnote/mysql-index.html)
|
- [MySQL 索引优化全攻略 ](http://www.runoob.com/w3cnote/mysql-index.html)
|
||||||
- [20+ ?? MySQL ??????????????? ](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html)
|
- [20+ 条 MySQL 性能优化的最佳经验 ](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html)
|
||||||
|
|
500
notes/SQL 语法.md
500
notes/SQL 语法.md
|
@ -1,52 +1,52 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [????](#????)
|
* [基础](#基础)
|
||||||
* [???](#???)
|
* [查询](#查询)
|
||||||
* [????](#????)
|
* [排序](#排序)
|
||||||
* [????](#????)
|
* [过滤](#过滤)
|
||||||
* [????](#????)
|
* [通配符](#通配符)
|
||||||
* [???????](#???????)
|
* [计算字段](#计算字段)
|
||||||
* [????](#????)
|
* [函数](#函数)
|
||||||
* [???????](#???????)
|
* [文本处理](#文本处理)
|
||||||
* [??????????](#??????????)
|
* [日期和时间处理](#日期和时间处理)
|
||||||
* [???????](#???????)
|
* [数值处理](#数值处理)
|
||||||
* [????](#????)
|
* [汇总](#汇总)
|
||||||
* [????](#????)
|
* [分组](#分组)
|
||||||
* [????](#????)
|
* [子查询](#子查询)
|
||||||
* [????](#????)
|
* [连接](#连接)
|
||||||
* [??????](#??????)
|
* [内连接](#内连接)
|
||||||
* [??????](#??????)
|
* [自连接](#自连接)
|
||||||
* [???????](#???????)
|
* [自然连接](#自然连接)
|
||||||
* [??????](#??????)
|
* [外连接](#外连接)
|
||||||
* [?????](#?????)
|
* [组合查询](#组合查询)
|
||||||
* [????](#????)
|
* [插入](#插入)
|
||||||
* [????](#????)
|
* [更新](#更新)
|
||||||
* [???](#???)
|
* [删除](#删除)
|
||||||
* [??????](#??????)
|
* [创建表](#创建表)
|
||||||
* [????](#????)
|
* [修改表](#修改表)
|
||||||
* [???](#???)
|
* [视图](#视图)
|
||||||
* [?洢????](#?洢????)
|
* [存储过程](#存储过程)
|
||||||
* [?α?](#?α?)
|
* [游标](#游标)
|
||||||
* [??????](#??????)
|
* [触发器](#触发器)
|
||||||
* [??????](#??????)
|
* [事务处理](#事务处理)
|
||||||
* [?????](#?????)
|
* [字符集](#字符集)
|
||||||
* [??????](#??????)
|
* [权限管理](#权限管理)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ????
|
# 基础
|
||||||
|
|
||||||
????????????????δ洢???洢???????????????????η?????????????????????
|
模式:定义了数据如何存储、存储什么样的数据以及数据如何分解等信息,数据库和表都有模式。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????е?????????
|
主键的值不允许修改,也不允许复用(不能使用已经删除的主键值赋给新数据行的主键)。
|
||||||
|
|
||||||
SQL??Structured Query Language)????? SQL ?? ANSI ???????????????? ANSI SQL?????? DBMS ??????????????? PL/SQL??Transact-SQL ???
|
SQL(Structured Query Language),标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL,各个 DBMS 都有自己的实现,如 PL/SQL、Transact-SQL 等。
|
||||||
|
|
||||||
# ???
|
# 查询
|
||||||
|
|
||||||
SQL ????????Сд???????????????????????????????????????? DBMS ??????á?
|
SQL 语句不区分大小写,但是数据库表名、列名和值是否区分依赖于具体的 DBMS 以及配置。
|
||||||
|
|
||||||
**DISTINCT**
|
**DISTINCT**
|
||||||
|
|
||||||
????????????Ρ??????????????У????????????е????????????????
|
相同值只会出现一次。它作用于所有列,也就是说所有列的值都相同才算相同。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT DISTINCT col1, col2
|
SELECT DISTINCT col1, col2
|
||||||
|
@ -55,9 +55,9 @@ FROM mytable;
|
||||||
|
|
||||||
**LIMIT**
|
**LIMIT**
|
||||||
|
|
||||||
????????????????????????????????????????????У??? 0 ????????????????????????????
|
限制返回的行数。可以有两个参数,第一个参数为起始行,从 0 开始;第二个参数为返回的总行数。
|
||||||
|
|
||||||
????? 5 ?е? SQL??
|
返回前 5 行的 SQL:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -71,7 +71,7 @@ FROM mytable
|
||||||
LIMIT 0, 5;
|
LIMIT 0, 5;
|
||||||
```
|
```
|
||||||
|
|
||||||
????? 3 \~ 5 ?У?
|
返回第 3 \~ 5 行:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -79,22 +79,22 @@ FROM mytable
|
||||||
LIMIT 2, 3;
|
LIMIT 2, 3;
|
||||||
```
|
```
|
||||||
|
|
||||||
**???**
|
**注释**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
# ???
|
# 注释
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM mytable -- ???
|
FROM mytable -- 注释
|
||||||
/* ???1
|
/* 注释1
|
||||||
???2 */
|
注释2 */
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 排序
|
||||||
|
|
||||||
**ASC**??????????
|
**ASC**:升序(默认)
|
||||||
**DESC**??????
|
**DESC**:降序
|
||||||
|
|
||||||
?????????н???????
|
可以按多个列进行排序:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -102,9 +102,9 @@ FROM mytable
|
||||||
ORDER BY col1 DESC, col2 ASC;
|
ORDER BY col1 DESC, col2 ASC;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 过滤
|
||||||
|
|
||||||
????ò??????????????????????????????й?????????????????????紫??????????????????????????????
|
在应用层也可以过滤数据,但是不在服务器端进行过滤的数据非常大,导致通过网络传输了很多多余的数据,从而浪费了网络带宽。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -112,155 +112,155 @@ FROM mytable
|
||||||
WHERE col IS NULL;
|
WHERE col IS NULL;
|
||||||
```
|
```
|
||||||
|
|
||||||
?±?????? WHERE ????????????
|
下表显示了 WHERE 子句可用的操作符
|
||||||
|
|
||||||
| ?????? | ??? |
|
| 操作符 | 说明 |
|
||||||
| ------------ | ------------ |
|
| ------------ | ------------ |
|
||||||
| = < > | ???? С?? ???? |
|
| = < > | 等于 小于 大于 |
|
||||||
| <> != | ?????? |
|
| <> != | 不等于 |
|
||||||
| <= !> | С????? |
|
| <= !> | 小于等于 |
|
||||||
| >= !< | ??????? |
|
| >= !< | 大于等于 |
|
||||||
| BETWEEN | ?????????? |
|
| BETWEEN | 在两个值之间 |
|
||||||
| IS NULL | ?NULL? |
|
| IS NULL | 为NULL值 |
|
||||||
|
|
||||||
????????NULL ?? 0 ????????????????
|
应该注意到,NULL 与 0 、空字符串都不同。
|
||||||
|
|
||||||
**AND OR** ??????????????????????????? AND?????????????????漰????? AND ?? OR ????????? () ?????????????
|
**AND OR** 用于连接多个过滤条件。优先处理 AND,因此当一个过滤表达式涉及到多个 AND 和 OR 时,应当使用 () 来决定优先级。
|
||||||
|
|
||||||
**IN** ??????????????????????????????? SELECT ????????????????????????
|
**IN** 操作符用于匹配一组值,其后也可以接一个 SELECT 子句,从而匹配子查询得到的一组值。
|
||||||
|
|
||||||
**NOT** ????????????????????
|
**NOT** 操作符用于否定一个条件。
|
||||||
|
|
||||||
# ????
|
# 通配符
|
||||||
|
|
||||||
??????????????????У?????????????Ρ?
|
通配符也是用在过滤语句中,只能用于文本字段。
|
||||||
|
|
||||||
- **%** ??? >=0 ????????????????? \*??
|
- **%** 匹配 >=0 个任意字符,类似于 \*;
|
||||||
|
|
||||||
- **\_** ??? ==1 ????????????????? \.??
|
- **\_** 匹配 ==1 个任意字符,类似于 \.;
|
||||||
|
|
||||||
- **[ ]** ??????伯????????????????? ^ ?????????з?
|
- **[ ]** 可以匹配集合内的字符,用脱字符 ^ 可以对其进行否定
|
||||||
|
|
||||||
??? Like ?????????????
|
使用 Like 来进行通配符匹配。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM mytable
|
FROM mytable
|
||||||
WHERE col LIKE '[^AB]%' -- ????AB????????????
|
WHERE col LIKE '[^AB]%' -- 不以AB开头的任意文本
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????λ????????????????
|
不要滥用通配符,通配符位于开头处匹配会非常慢。
|
||||||
|
|
||||||
# ???????
|
# 计算字段
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????
|
在数据库服务器上完成数据的转换和格式化的工作往往比客户端上快得多,并且转换和格式化后的数据量更少的话可以减少网络通信量。
|
||||||
|
|
||||||
???????????????? **AS** ????????????????????????????????????
|
计算字段通常需要使用 **AS** 来取别名,否则输出的时候字段名为计算表达式。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT col1*col2 AS alias
|
SELECT col1*col2 AS alias
|
||||||
FROM mytable
|
FROM mytable
|
||||||
```
|
```
|
||||||
|
|
||||||
**Concat()** ??????????????Ρ?????????????????????????п?????????????????Щ???????????? **TRIM()** ?????????β???
|
**Concat()** 用于连接两个字段。许多数据库会使用空格把一个值填充为列宽,因此连接的结果会出现一些不必要的空格,使用 **TRIM()** 可以去除首尾空格。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT Concat(TRIM(col1), ' (', TRIM(col2), ')')
|
SELECT Concat(TRIM(col1), ' (', TRIM(col2), ')')
|
||||||
FROM mytable
|
FROM mytable
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 函数
|
||||||
|
|
||||||
???? DBMS ???????????????????????????
|
各个 DBMS 的函数都是不相同的,因此不可移植。
|
||||||
|
|
||||||
## ???????
|
## 文本处理
|
||||||
|
|
||||||
| ???? | ??? |
|
| 函数 | 说明 |
|
||||||
| ------------ | ------------ |
|
| ------------ | ------------ |
|
||||||
| LEFT() RIGHT() | ????????????? |
|
| LEFT() RIGHT() | 左边或者右边的字符 |
|
||||||
| LOWER() UPPER() | ????Сд?????д |
|
| LOWER() UPPER() | 转换为小写或者大写 |
|
||||||
| LTRIM() RTIM() | ??????????????? |
|
| LTRIM() RTIM() | 去除左边或者右边的空格 |
|
||||||
| LENGTH() | ???? |
|
| LENGTH() | 长度 |
|
||||||
| SUNDEX() | ????????? |
|
| SUNDEX() | 转换为语音值 |
|
||||||
|
|
||||||
???У?**SOUNDEX()** ????????????????????????????????????????????????????????????????????
|
其中,**SOUNDEX()** 是将一个字符串转换为描述其语音表示的字母数字模式的算法,它是根据发音而不是字母比较。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM mytable
|
FROM mytable
|
||||||
WHERE SOUNDEX(col1) = SOUNDEX('apple')
|
WHERE SOUNDEX(col1) = SOUNDEX('apple')
|
||||||
```
|
```
|
||||||
## ??????????
|
## 日期和时间处理
|
||||||
|
|
||||||
????????YYYY-MM-DD
|
日期格式:YYYY-MM-DD
|
||||||
|
|
||||||
???????HH:MM:SS
|
时间格式:HH:MM:SS
|
||||||
|
|
||||||
|?? ?? | ? ??|
|
|函 数 | 说 明|
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| AddDate() | ??????????????????|
|
| AddDate() | 增加一个日期(天、周等)|
|
||||||
| AddTime() | ?????????????????|
|
| AddTime() | 增加一个时间(时、分等)|
|
||||||
| CurDate() | ?????????? |
|
| CurDate() | 返回当前日期 |
|
||||||
| CurTime() | ????????? |
|
| CurTime() | 返回当前时间 |
|
||||||
|Date() |???????????????????|
|
|Date() |返回日期时间的日期部分|
|
||||||
|DateDiff() |???????????????|
|
|DateDiff() |计算两个日期之差|
|
||||||
|Date_Add() |?????????????????|
|
|Date_Add() |高度灵活的日期运算函数|
|
||||||
|Date_Format() |??????????????????????|
|
|Date_Format() |返回一个格式化的日期或时间串|
|
||||||
|Day()| ????????????????????|
|
|Day()| 返回一个日期的天数部分|
|
||||||
|DayOfWeek() |?????????????????????????|
|
|DayOfWeek() |对于一个日期,返回对应的星期几|
|
||||||
|Hour() |???????????С?????|
|
|Hour() |返回一个时间的小时部分|
|
||||||
|Minute() |?????????????????|
|
|Minute() |返回一个时间的分钟部分|
|
||||||
|Month() |?????????????·????|
|
|Month() |返回一个日期的月份部分|
|
||||||
|Now() |??????????????|
|
|Now() |返回当前日期和时间|
|
||||||
|Second() |???????????????|
|
|Second() |返回一个时间的秒部分|
|
||||||
|Time() |????????????????????|
|
|Time() |返回一个日期时间的时间部分|
|
||||||
|Year() |??????????????????|
|
|Year() |返回一个日期的年份部分|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
mysql> SELECT NOW();
|
mysql> SELECT NOW();
|
||||||
-> '2017-06-28 14:01:52'
|
-> '2017-06-28 14:01:52'
|
||||||
```
|
```
|
||||||
|
|
||||||
## ???????
|
## 数值处理
|
||||||
|
|
||||||
| ???? | ??? |
|
| 函数 | 说明 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| SIN() | ???? |
|
| SIN() | 正弦 |
|
||||||
|COS() | ???? |
|
|COS() | 余弦 |
|
||||||
| TAN() | ???? |
|
| TAN() | 正切 |
|
||||||
| ABS() | ????? |
|
| ABS() | 绝对值 |
|
||||||
| SQRT() | ?????|
|
| SQRT() | 平方根|
|
||||||
| MOD() | ????|
|
| MOD() | 余数|
|
||||||
| EXP() | ???|
|
| EXP() | 指数|
|
||||||
| PI() | ?????|
|
| PI() | 圆周率|
|
||||||
|RAND() | ?????|
|
|RAND() | 随机数|
|
||||||
|
|
||||||
## ????
|
## 汇总
|
||||||
|
|
||||||
|?? ?? |? ??|
|
|函 数 |说 明|
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|AVG() |??????е?????|
|
|AVG() |返回某列的平均值|
|
||||||
|COUNT()| ??????е?????|
|
|COUNT()| 返回某列的行数|
|
||||||
|MAX()| ??????е?????|
|
|MAX()| 返回某列的最大值|
|
||||||
|MIN()| ??????е???С?|
|
|MIN()| 返回某列的最小值|
|
||||||
|SUM() |???????????|
|
|SUM() |返回某列值之和|
|
||||||
|
|
||||||
AVG() ????? NULL ?С?
|
AVG() 会忽略 NULL 行。
|
||||||
|
|
||||||
DISTINCT ??????????????????
|
DISTINCT 关键字会只汇总不同的值。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT AVG(DISTINCT col1) AS avg_col
|
SELECT AVG(DISTINCT col1) AS avg_col
|
||||||
FROM mytable
|
FROM mytable
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 分组
|
||||||
|
|
||||||
?????????????????????????С?
|
分组就是把相同的数据放在同一组中。
|
||||||
|
|
||||||
????????????????????????д???????????????????????
|
可以对每组数据使用汇总函数进行处理,例如求每组数的平均值等。
|
||||||
|
|
||||||
?? col ????????????
|
按 col 排序并分组数据:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT col, COUNT(*) AS num
|
SELECT col, COUNT(*) AS num
|
||||||
|
@ -268,7 +268,7 @@ FROM mytable
|
||||||
GROUP BY col;
|
GROUP BY col;
|
||||||
```
|
```
|
||||||
|
|
||||||
WHERE ?????У?HAVING ??????飬?й?????????????????
|
WHERE 过滤行,HAVING 过滤分组,行过滤应当先与分组过滤;
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT col, COUNT(*) AS num
|
SELECT col, COUNT(*) AS num
|
||||||
|
@ -278,7 +278,7 @@ GROUP BY col
|
||||||
HAVING COUNT(*) >= 2;
|
HAVING COUNT(*) >= 2;
|
||||||
```
|
```
|
||||||
|
|
||||||
GROUP BY ???????????????Σ??? ORDER BY ??????????????????????
|
GROUP BY 的排序结果为分组字段,而 ORDER BY 也可以以聚集字段来进行排序。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT col, COUNT(*) AS num
|
SELECT col, COUNT(*) AS num
|
||||||
|
@ -287,18 +287,18 @@ GROUP BY col
|
||||||
ORDER BY num;
|
ORDER BY num;
|
||||||
```
|
```
|
||||||
|
|
||||||
????涨??
|
分组规定:
|
||||||
|
|
||||||
1. GROUP BY ???????? WHERE ??????ORDER BY ???????
|
1. GROUP BY 子句出现在 WHERE 子句之后,ORDER BY 子句之前;
|
||||||
2. ????????????????SELECT ????е????ж??????? GROUP BY ????и?????
|
2. 除了汇总计算语句之外,SELECT 语句中的每一列都必须在 GROUP BY 子句中给出;
|
||||||
3. NULL ???л????????飻
|
3. NULL 的行会单独分为一组;
|
||||||
4. ????? SQL ??????? GROUP BY ?о??п??????????????
|
4. 大多数 SQL 实现不支持 GROUP BY 列具有可变长度的数据类型。
|
||||||
|
|
||||||
# ????
|
# 子查询
|
||||||
|
|
||||||
????????????????С?
|
子查询中只能返回一个列。
|
||||||
|
|
||||||
???????????????? WHRER ?????????????
|
可以将子查询的结果作为 WHRER 语句的过滤条件:
|
||||||
|
|
||||||
```
|
```
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -307,7 +307,7 @@ WHERE col1 IN (SELECT col2
|
||||||
FROM mytable2);
|
FROM mytable2);
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????Σ?
|
下面的语句可以检索出客户的订单数量。子查询语句会对检索出的每个客户执行一次:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT cust_name, (SELECT COUNT(*)
|
SELECT cust_name, (SELECT COUNT(*)
|
||||||
|
@ -318,17 +318,17 @@ FROM Customers
|
||||||
ORDER BY cust_name;
|
ORDER BY cust_name;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 连接
|
||||||
|
|
||||||
??????????????????? JOIN ???????????????????? ON??
|
连接用于连接多个表,使用 JOIN 关键字,并且条件语句使用 ON。
|
||||||
|
|
||||||
????????滻?????????????????Ч?????????
|
连接可以替换子查询,并且比子查询的效率一般会更快。
|
||||||
|
|
||||||
?????? AS ??????????????κ???????????????????????????? SQL ???????????????
|
可以用 AS 给列名、计算字段和表名取别名,给表名取别名是为了简化 SQL 语句以及连接相同表。
|
||||||
|
|
||||||
## ??????
|
## 内连接
|
||||||
|
|
||||||
??????????????????? INNER JOIN ??????
|
内连接又称等值连接,使用 INNER JOIN 关键字。
|
||||||
|
|
||||||
```
|
```
|
||||||
select a, b, c
|
select a, b, c
|
||||||
|
@ -336,7 +336,7 @@ from A inner join B
|
||||||
on A.key = B.key
|
on A.key = B.key
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????? INNER JOIN????????????????? WHERE ?н???????????????????????????????????
|
可以不明确使用 INNER JOIN,而使用普通查询并在 WHERE 中将两个表中要连接的列用等值方法连接起来。
|
||||||
|
|
||||||
```
|
```
|
||||||
select a, b, c
|
select a, b, c
|
||||||
|
@ -344,15 +344,15 @@ from A, B
|
||||||
where A.key = B.key
|
where A.key = B.key
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????·???????????
|
在没有条件语句的情况下返回笛卡尔积。
|
||||||
|
|
||||||
## ??????
|
## 自连接
|
||||||
|
|
||||||
??????????????????????????????????????????
|
自连接可以看成内连接的一种,只是连接的表是自身而已。
|
||||||
|
|
||||||
??????????????????????????????????????? Jim ????????????????????????
|
一张员工表,包含员工姓名和员工所属部门,要找出与 Jim 处在同一部门的所有员工姓名。
|
||||||
|
|
||||||
**?????汾**
|
**子查询版本**
|
||||||
|
|
||||||
```
|
```
|
||||||
select name
|
select name
|
||||||
|
@ -363,7 +363,7 @@ where department = (
|
||||||
where name = "Jim");
|
where name = "Jim");
|
||||||
```
|
```
|
||||||
|
|
||||||
**??????汾**
|
**自连接版本**
|
||||||
|
|
||||||
```
|
```
|
||||||
select name
|
select name
|
||||||
|
@ -372,24 +372,24 @@ where e1.department = e2.department
|
||||||
and e1.name = "Jim";
|
and e1.name = "Jim";
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????Ч????
|
连接一般比子查询的效率高。
|
||||||
|
|
||||||
## ???????
|
## 自然连接
|
||||||
|
|
||||||
????????????????????????????????????????п????ж????
|
自然连接是把同名列通过等值测试连接起来的,同名列可以有多个。
|
||||||
|
|
||||||
?????????????????????????????????У?????????????????????????У???????????????????
|
内连接和自然连接的区别:内连接提供连接的列,而自然连接自动连接所有同名列;内连接属于自然连接。
|
||||||
|
|
||||||
```
|
```
|
||||||
select *
|
select *
|
||||||
from employee natural join department;
|
from employee natural join department;
|
||||||
```
|
```
|
||||||
|
|
||||||
## ??????
|
## 外连接
|
||||||
|
|
||||||
?????????????й???????Щ?С???????????????????????????????????????????????????????С?
|
外连接保留了没有关联的那些行。分为左外连接,右外连接以及全外连接,左外连接就是保留左表的所有行。
|
||||||
|
|
||||||
???????й???????????????????ж???????????
|
检索所有顾客的订单信息,包括还没有订单信息的顾客。
|
||||||
|
|
||||||
```
|
```
|
||||||
select Customers.cust_id, Orders.order_num
|
select Customers.cust_id, Orders.order_num
|
||||||
|
@ -397,7 +397,7 @@ select Customers.cust_id, Orders.order_num
|
||||||
on Customers.cust_id = Orders.curt_id
|
on Customers.cust_id = Orders.curt_id
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????????????????
|
如果需要统计顾客的订单数,使用聚集函数。
|
||||||
|
|
||||||
```
|
```
|
||||||
select Customers.cust_id,
|
select Customers.cust_id,
|
||||||
|
@ -407,13 +407,13 @@ on Customers.cust_id = Orders.curt_id
|
||||||
group by Customers.cust_id
|
group by Customers.cust_id
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?????
|
# 组合查询
|
||||||
|
|
||||||
??? **UNION** ??????????????????????????????????С?????????????????
|
使用 **UNION** 来连接两个查询,每个查询必须包含相同的列、表达式或者聚集函数。
|
||||||
|
|
||||||
???????????У???????????????У???? UNION ALL ??
|
默认会去除相同行,如果需要保留相同行,使用 UNION ALL 。
|
||||||
|
|
||||||
????????? ORDER BY ??????????λ?????????
|
只能包含一个 ORDER BY 子句,并且必须位于语句的最后。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT col
|
SELECT col
|
||||||
|
@ -425,16 +425,16 @@ FROM mytable
|
||||||
WHERE col =2;
|
WHERE col =2;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 插入
|
||||||
|
|
||||||
**???????**
|
**普通插入**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
INSERT INTO mytable(col1, col2)
|
INSERT INTO mytable(col1, col2)
|
||||||
VALUES(val1, val2);
|
VALUES(val1, val2);
|
||||||
```
|
```
|
||||||
|
|
||||||
**?????????????????**
|
**插入检索出来的数据**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
INSERT INTO mytable1(col1, col2)
|
INSERT INTO mytable1(col1, col2)
|
||||||
|
@ -442,14 +442,14 @@ SELECT col1, col2
|
||||||
FROM mytable2;
|
FROM mytable2;
|
||||||
```
|
```
|
||||||
|
|
||||||
**????????????????????±?**
|
**将一个表的内容复制到一个新表**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE newtable AS
|
CREATE TABLE newtable AS
|
||||||
SELECT * FROM mytable;
|
SELECT * FROM mytable;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 更新
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
UPDATE mytable
|
UPDATE mytable
|
||||||
|
@ -457,18 +457,18 @@ SET col = val
|
||||||
WHERE id = 1;
|
WHERE id = 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ???
|
# 删除
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
DELETE FROM mytable
|
DELETE FROM mytable
|
||||||
WHERE id = 1;
|
WHERE id = 1;
|
||||||
```
|
```
|
||||||
|
|
||||||
**TRUNCATE TABLE** ?????????????????????С?
|
**TRUNCATE TABLE** 可以清空表,也就是删除所有行。
|
||||||
|
|
||||||
????????????????????? WHERE ????????????????????????????????? SELECT ?????в????????????????
|
使用更新和删除操作时一定要用 WHERE 子句,不然会把整张表的数据都破坏。可以先用 SELECT 语句进行测试,防止错误删除。
|
||||||
|
|
||||||
# ??????
|
# 创建表
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE mytable (
|
CREATE TABLE mytable (
|
||||||
|
@ -479,38 +479,38 @@ CREATE TABLE mytable (
|
||||||
PRIMARY KEY (`id`));
|
PRIMARY KEY (`id`));
|
||||||
```
|
```
|
||||||
|
|
||||||
# ????
|
# 修改表
|
||||||
|
|
||||||
**?????**
|
**添加列**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
ALTER TABLE mytable
|
ALTER TABLE mytable
|
||||||
ADD col CHAR(20);
|
ADD col CHAR(20);
|
||||||
```
|
```
|
||||||
|
|
||||||
**?????**
|
**删除列**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
ALTER TABLE mytable
|
ALTER TABLE mytable
|
||||||
DROP COLUMN col;
|
DROP COLUMN col;
|
||||||
```
|
```
|
||||||
|
|
||||||
**?????**
|
**删除表**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
DROP TABLE mytable;
|
DROP TABLE mytable;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ???
|
# 视图
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????
|
视图是虚拟的表,本身不包含数据,也就不能对其进行索引操作。对视图的操作和对普通表的操作一样。
|
||||||
|
|
||||||
???????????????
|
视图具有如下好处:
|
||||||
|
|
||||||
1. ?????? SQL ?????????縴???????
|
1. 简化复杂的 SQL 操作,比如复杂的联结;
|
||||||
2. ???????????????????
|
2. 只使用实际表的一部分数据;
|
||||||
3. ???????????????????????????????????
|
3. 通过只给用户访问视图的权限,保证数据的安全性;
|
||||||
4. ????????????????
|
4. 更改数据格式和表示。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE VIEW myview AS
|
CREATE VIEW myview AS
|
||||||
|
@ -519,25 +519,25 @@ FROM mytable
|
||||||
WHERE col5 = val;
|
WHERE col5 = val;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?洢????
|
# 存储过程
|
||||||
|
|
||||||
?洢????????????????? SQL ????????????
|
存储过程可以看成是对一系列 SQL 操作的批处理;
|
||||||
|
|
||||||
**???洢???????**
|
**使用存储过程的好处**
|
||||||
|
|
||||||
1. ???????????洢?????У???????????????????
|
1. 把实现封装在了存储过程中,不仅简单,也保证了安全性;
|
||||||
2. ??????????
|
2. 可以复用代码;
|
||||||
3. ?????????????????к????????
|
3. 由于是预先编译,因此具有很高的性能。
|
||||||
|
|
||||||
**?????洢????**
|
**创建存储过程**
|
||||||
|
|
||||||
???????д????洢??????????????????????????????? ; ????????????洢???????????????????????????????????????????????????
|
命令行中创建存储过程需要自定义分隔符,因为命令行是以 ; 为结束符,而存储过程中也包含了分号,因此会错误把这部分分号当成是结束符,造成语法错误。
|
||||||
|
|
||||||
???? in??out ?? inout ?????????
|
包含 in、out 和 inout 三种参数。
|
||||||
|
|
||||||
???????????????? select into ???
|
给变量赋值都需要用 select into 语句。
|
||||||
|
|
||||||
?????????????????????????????????
|
每次只能给一个变量赋值,不支持集合的操作。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
delimiter //
|
delimiter //
|
||||||
|
@ -558,18 +558,18 @@ call myprocedure(@ret);
|
||||||
select @ret;
|
select @ret;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?α?
|
# 游标
|
||||||
|
|
||||||
??洢??????????α??????????????????????????
|
在存储过程中使用游标可以对一个结果集进行移动遍历。
|
||||||
|
|
||||||
?α??????????????????????????????????е??????н????????????
|
游标主要用于交互式应用,其中用户需要对数据集中的任意行进行浏览和修改。
|
||||||
|
|
||||||
**????α????????裺**
|
**使用游标的四个步骤:**
|
||||||
|
|
||||||
1. ?????α????????????????????????
|
1. 声明游标,这个过程没有实际检索出数据;
|
||||||
2. ???α?
|
2. 打开游标;
|
||||||
3. ????????
|
3. 取出数据;
|
||||||
4. ????α?
|
4. 关闭游标;
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
delimiter //
|
delimiter //
|
||||||
|
@ -579,7 +579,7 @@ create procedure myprocedure(out ret int)
|
||||||
|
|
||||||
declare mycursor cursor for
|
declare mycursor cursor for
|
||||||
select col1 from mytable;
|
select col1 from mytable;
|
||||||
# ?????????continue handler???? sqlstate '02000' ??????????????????? set done = 1
|
# 定义了一个continue handler,当 sqlstate '02000' 这个条件出现时,会执行 set done = 1
|
||||||
declare continue handler for sqlstate '02000' set done = 1;
|
declare continue handler for sqlstate '02000' set done = 1;
|
||||||
|
|
||||||
open mycursor;
|
open mycursor;
|
||||||
|
@ -594,43 +594,43 @@ create procedure myprocedure(out ret int)
|
||||||
delimiter ;
|
delimiter ;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ??????
|
# 触发器
|
||||||
|
|
||||||
?????????????????????????????????У?DELETE??INSERT??UPDATE
|
触发器会在某个表执行以下语句时而自动执行:DELETE、INSERT、UPDATE
|
||||||
|
|
||||||
???????????????????????????????????У????????? BEFORE ??????????????? AFTER ??????BEFORE ??????????????????
|
触发器必须指定在语句执行之前还是之后自动执行,之前执行使用 BEFORE 关键字,之后执行使用 AFTER 关键字。BEFORE 用于数据验证和净化。
|
||||||
|
|
||||||
INSERT ???????????????? NEW ???????
|
INSERT 触发器包含一个名为 NEW 的虚拟表。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TRIGGER mytrigger AFTER INSERT ON mytable
|
CREATE TRIGGER mytrigger AFTER INSERT ON mytable
|
||||||
FOR EACH ROW SELECT NEW.col;
|
FOR EACH ROW SELECT NEW.col;
|
||||||
```
|
```
|
||||||
|
|
||||||
DELETE ???????????????? OLD ???????????????????
|
DELETE 触发器包含一个名为 OLD 的虚拟表,并且是只读的。
|
||||||
|
|
||||||
UPDATE ???????????????? NEW ???????? OLD ??????????? NEW ????????????? OLD ????????
|
UPDATE 触发器包含一个名为 NEW 和一个名为 OLD 的虚拟表,其中 NEW 是可以被修改地,而 OLD 是只读的。
|
||||||
|
|
||||||
???????????????????????????????????????????С?
|
可以使用触发器来进行审计跟踪,把修改记录到另外一张表中。
|
||||||
|
|
||||||
MySQL ?????????????????? CALL ??? ?????????????洢?????
|
MySQL 不允许在触发器中使用 CALL 语句 ,也就是不能调用存储过程。
|
||||||
|
|
||||||
# ??????
|
# 事务处理
|
||||||
|
|
||||||
**????????**
|
**基本术语**
|
||||||
|
|
||||||
1. ????transaction?????? SQL ???
|
1. 事务(transaction)指一组 SQL 语句;
|
||||||
2. ?????rollback?????????? SQL ????????
|
2. 回退(rollback)指撤销指定 SQL 语句的过程;
|
||||||
3. ????commit?????δ?洢?? SQL ?????д????????
|
3. 提交(commit)指将未存储的 SQL 语句结果写入数据库表;
|
||||||
4. ??????savepoint????????????????????λ????placeholder?????????????????????????????????????????
|
4. 保留点(savepoint)指事务处理中设置的临时占位符(placeholder),你可以对它发布回退(与回退整个事务处理不同)。
|
||||||
|
|
||||||
??????? SELECT ??????? SELECT ????????壻???????? CRETE ?? DROP ???
|
不能回退 SELECT 语句,回退 SELECT 语句也没意义;也不能回退 CRETE 和 DROP 语句。
|
||||||
|
|
||||||
MySQL ?????????????????????????????????????????Ρ??????? START TRANSACTION ??????????????????? COMMIT ?? ROLLBACK ?????к??????????????????????????
|
MySQL 的事务提交默认是隐式提交,也就是每执行一条语句就会提交一次。当出现 START TRANSACTION 语句时,会关闭隐式提交;当 COMMIT 或 ROLLBACK 语句执行后,事务会自动关闭,重新恢复隐式提交。
|
||||||
|
|
||||||
??????? autocommit ? 0 ????????????????? autocommit ??????? 1 ???????autocommit ???????????????????????????????
|
通过设置 autocommit 为 0 可以取消自动提交,直到 autocommit 被设置为 1 才会提交;autocommit 标记是针对每个连接而不是针对服务器的。
|
||||||
|
|
||||||
???????????????ROLLBACK ?????? START TRANSACTION ????????????????????????? ROLLBACK ??????????????????????????
|
如果没有设置保留点,ROLLBACK 会回退到 START TRANSACTION 语句处;如果设置了保留点,并且在 ROLLBACK 中指定该保留点,则会回退到该保留点。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
START TRANSACTION
|
START TRANSACTION
|
||||||
|
@ -642,15 +642,15 @@ ROLLBACK TO delete1
|
||||||
COMMIT
|
COMMIT
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?????
|
# 字符集
|
||||||
|
|
||||||
**????????**
|
**基本术语**
|
||||||
|
|
||||||
1. ???????????????????
|
1. 字符集为字母和符号的集合;
|
||||||
2. ??????????????????????????
|
2. 编码为某个字符集成员的内部表示;
|
||||||
3. У??????????α?????????????????顣
|
3. 校对字符指定如何比较,主要用于排序和分组。
|
||||||
|
|
||||||
?????????????????У?????????????????
|
除了给表指定字符集和校对外,也可以给列指定:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE mytable
|
CREATE TABLE mytable
|
||||||
|
@ -658,7 +658,7 @@ CREATE TABLE mytable
|
||||||
DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;
|
DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????У???
|
可以在排序、分组时指定校对:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -666,67 +666,67 @@ FROM mytable
|
||||||
ORDER BY col COLLATE latin1_general_ci;
|
ORDER BY col COLLATE latin1_general_ci;
|
||||||
```
|
```
|
||||||
|
|
||||||
# ??????
|
# 权限管理
|
||||||
|
|
||||||
MySQL ?????????????? mysql ?????????С?
|
MySQL 的账户信息保存在 mysql 这个数据库中。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
USE mysql;
|
USE mysql;
|
||||||
SELECT user FROM user;
|
SELECT user FROM user;
|
||||||
```
|
```
|
||||||
|
|
||||||
**???????**
|
**创建账户**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE USER myuser IDENTIFIED BY 'mypassword';
|
CREATE USER myuser IDENTIFIED BY 'mypassword';
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????κ?????
|
新创建的账户没有任何权限。
|
||||||
|
|
||||||
**????????**
|
**修改账户名**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
RENAME myuser TO newuser;
|
RENAME myuser TO newuser;
|
||||||
```
|
```
|
||||||
|
|
||||||
**??????**
|
**删除账户**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
DROP USER myuser;
|
DROP USER myuser;
|
||||||
```
|
```
|
||||||
|
|
||||||
**?????**
|
**查看权限**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SHOW GRANTS FOR myuser;
|
SHOW GRANTS FOR myuser;
|
||||||
```
|
```
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c73aa08e-a987-43c9-92be-adea4a884c25.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c73aa08e-a987-43c9-92be-adea4a884c25.png)
|
||||||
|
|
||||||
????? username@host ????????壬username@% ?????????????????
|
账户用 username@host 的形式定义,username@% 使用的是默认主机名。
|
||||||
|
|
||||||
**???????**
|
**授予权限**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
GRANT SELECT, INSERT ON mydatabase.* TO myuser;
|
GRANT SELECT, INSERT ON mydatabase.* TO myuser;
|
||||||
```
|
```
|
||||||
|
|
||||||
**??????**
|
**删除权限**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
REVOKE SELECT, INSERT ON mydatabase.* FROM myuser;
|
REVOKE SELECT, INSERT ON mydatabase.* FROM myuser;
|
||||||
```
|
```
|
||||||
|
|
||||||
GRANT ?? REVOKE ??????????????????????
|
GRANT 和 REVOKE 可在几个层次上控制访问权限:
|
||||||
|
|
||||||
- ??????????????? GRANT ALL?? REVOKE ALL??
|
- 整个服务器,使用 GRANT ALL和 REVOKE ALL;
|
||||||
- ???????????? ON database.\*??
|
- 整个数据库,使用 ON database.\*;
|
||||||
- ????????? ON database.table??
|
- 特定的表,使用 ON database.table;
|
||||||
- ??????У?
|
- 特定的列;
|
||||||
- ?????洢?????
|
- 特定的存储过程。
|
||||||
|
|
||||||
**????????**
|
**更改密码**
|
||||||
|
|
||||||
??????? Password() ????
|
必须使用 Password() 函数
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SET PASSWROD FOR myuser = Password('newpassword');
|
SET PASSWROD FOR myuser = Password('newpassword');
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,129 +1,129 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [??????](#??????)
|
* [译者序](#译者序)
|
||||||
* [???](#???)
|
* [前言](#前言)
|
||||||
* [??????](#??????)
|
* [专业主义](#专业主义)
|
||||||
* [???](#???)
|
* [说不](#说不)
|
||||||
* [???](#???)
|
* [说是](#说是)
|
||||||
* [???](#???)
|
* [编程](#编程)
|
||||||
* [????????????](#????????????)
|
* [测试驱动开发](#测试驱动开发)
|
||||||
* [???](#???)
|
* [练习](#练习)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ??????
|
# 译者序
|
||||||
|
|
||||||
???? Bob ???壬???С??????????????????????????????????????????????????????????
|
作者 Bob 大叔,著有《敏捷软件开发:原则、模式与实践》《代码整洁之道》《程序员的职业素养》
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????
|
对于解决问题,重要的不是问题本身,而是解决问题的方式、步骤以及反思的深度,这就是职业素养。
|
||||||
|
|
||||||
# ???
|
# 前言
|
||||||
|
|
||||||
?????????????????????????????????????????????????Σ????棬??????????????????????????????????????????????????????????????????????????????η???????????????????????????????????????????д?绰???????????η????Σ?????
|
由于管理者面临很大的财务和政治压力,他们无视技术人员发出的危险警告,抱着侥幸心理发射了“挑战者”航天飞机,最终导致航天飞机在高空爆炸。虽说技术人员已经做很多事情去阻止这次发射,但是并不是说做了所有他们能做的,例如他们就没有打电话去新闻台揭露此次发射的危险性。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/bccb799f-56e2-4356-95f0-a9ea05b0de2a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/bccb799f-56e2-4356-95f0-a9ea05b0de2a.jpg)
|
||||||
|
|
||||||
|
|
||||||
# ??????
|
# 专业主义
|
||||||
|
|
||||||
?????岻????ζ????????????????ζ?????Ρ?
|
专业主义不仅意味着荣誉和骄傲,也意味着责任。
|
||||||
|
|
||||||
???????????????????绰??·????????????????????????????????????ж??????????в????????????? bug ??????????????????????????ε???????????????????
|
作者在自己开发的一个电话线路故障检测系统时,因为赶着在到期日交付新功能,没有对整个系统进行测试,导致了一个 bug 的出现。作者认为这是一种不负责任的表现,也就是不专业的表现。
|
||||||
|
|
||||||
???????????? bug?????????ζ??????? bug ????
|
代码中难免有 bug,但是不意味着你不用为 bug 负责。
|
||||||
|
|
||||||
????? QA ????? bug ??????????? QA ???? bug??????????????????? bug???????????
|
有人把 QA 当成查 bug 的机器,等着 QA 发现 bug,而自己却不主动去发现 bug,这是不对的。
|
||||||
|
|
||||||
???????????????????д?Щ??????????е??????????????????????????
|
为了保证代码的正确性,需要写一些随时可以运行的单元测试,并且不断地去运行它们。
|
||||||
|
|
||||||
?????????????? - ????????????????????????????????????????????
|
软件项目的根本原则 - 易于修改。为了让自己的软件易于修改,需要经常去修改它!
|
||||||
|
|
||||||
???????????ó?????????????????????????????????????????????
|
单元测试可以让程序员更有自信去修改代码,因为它会让人确信修改地是否正确。
|
||||||
|
|
||||||
???????????????????
|
专业素养包括以下内容:
|
||||||
|
|
||||||
1. ?????
|
1. 坚持学习
|
||||||
2. ???????Щ????????
|
2. 每天练习一些简单的编程题目
|
||||||
3. ????????????????????????????
|
3. 与他们合作,从彼此身上学到更多东西
|
||||||
4. ?????????????????????????????????????????????????????
|
4. 交流。通过交流表达自己的思想,发现自己的不足以及与别人思想上的差异。
|
||||||
5. ???????????????????????????
|
5. 了解业务领域,找几本相关领域的书看。
|
||||||
6. ????? / ??????????
|
6. 与雇主 / 客户保持一致
|
||||||
7. ?????????????????????????
|
7. 谦逊,因为他们知道自己也可能犯错。
|
||||||
|
|
||||||
# ???
|
# 说不
|
||||||
|
|
||||||
???Щ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
对一些不合理的要求,不能只是说“试试看”,这会被当成是接受了这个要求。如果自己深知这种不合理的要求会导致严重的后果,就不能任由它发展下去,对这一要求说“不”。
|
||||||
|
|
||||||
???????????????????????????????????????????
|
说“不”时要用最详细的细节来说明,而不是烦躁地反驳。
|
||||||
|
|
||||||
?????????????????????Э???Щ????????????????
|
当要求明显不合理时,可以协商一些双方都能接受的方案。
|
||||||
|
|
||||||
"?п???д?????????" ????????????????ο?????????????????"?????????"????ù?????????????????????????????????? ipone ??????????????????????д?????????????????????????????κ??????????????????????????????????????????????????????????????????ò???????д?????????????????????????Щ?????????????????????????????????????????????????????????????????????д???????д?????Bob ?????????????????????????ο???????????????Щ??????????????????ж???Щ???????????????
|
"有可能写出好代码吗" 这篇博文,讲述了一次开发一家零售商为了在"黑色星期五"能够让顾客看到商品信息商店信息以及发布优惠码等功能的 ipone 应用,最开始零售商的经理承诺说只要写个硬编码的应用就行了,但是客户所要的任何一项功能,总比它最开始时所说的要复杂许多。面对时间的紧急,客户方的不配合,以及需求的变更,让博文作者写了一堆很烂的代码,而他自己确实对那些设计模式等高级开发技术是非常热衷的。所以他认为在实际的开发中因为客户的需求等因素,很难写作自己想写的代码。Bob 认为,上面那篇博文的作者才是此次开发过程碰到的那些问题的负责人,因为他没有对那些不合理的要求说不。
|
||||||
|
|
||||||
# ???
|
# 说是
|
||||||
|
|
||||||
??????????????????裺??????????????????????ж???
|
做出承诺的是三个步骤:口头上答应,放在心里,付诸行动。
|
||||||
|
|
||||||
???????????
|
缺乏承诺的词语:
|
||||||
|
|
||||||
1. ????????????????????
|
1. 需要:我需要把这事做完;
|
||||||
2. ???????????????????????
|
2. 希望:希望今天我能完成任务;
|
||||||
3. ???????????????????????
|
3. 让我们:让我们把这件事做完。
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????????????...??...??
|
缺乏承诺的人不会把重点放在自己身上,也不会明确说明一件事情的截止日期。真正的承诺是这样的“我会在...之前...”
|
||||||
|
|
||||||
??????????????????????????????
|
对自己无法完全掌握的事,不要轻易承诺。
|
||||||
|
|
||||||
????????????????????????????????????????
|
发现自己无法做到承诺,立马去调整别人对你的预期。
|
||||||
|
|
||||||
??????????????????????????е?????????????????????????????????????????????????????????????????????????????????????
|
“试试看”说明自己对承诺的内容有点顾忌,因此不要用试试看来作为一种承诺。如果不能确信自己能达到承诺的内容而随便承诺,那么最后往往会产生严重的后果。
|
||||||
|
|
||||||
# ???
|
# 编程
|
||||||
|
|
||||||
??????????????ü???????????????????????????
|
要精通一项技术,要对该技术具备“信心”和“感知能力”。
|
||||||
|
|
||||||
??????????????д?????????÷???????????簾?????????????????????????????????????????????????????????б???
|
状态不好的时候最好别写代码。状态不好分为:疲劳,比如熬夜;焦虑,因为外界的事情让自己不能安心下来,这个时候应该下调整好再进行编程。
|
||||||
|
|
||||||
??????????о????????????????????????????????????????????????????????????????????????
|
进入流状态的感觉很好,觉得可以做很多事,但是流状态其实是一种浅层冥想,思维能力会下降,因此要避免进入流状态。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f0321ed1-fa93-460e-951b-4239fef819f3.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f0321ed1-fa93-460e-951b-4239fef819f3.jpg)
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????
|
流状态的特点是隔绝沟通,而结对编程能够打破这种隔绝,因此结对编程能够防止进入流状态。
|
||||||
|
|
||||||
?????????????????????????????????????????????????л???仯????????????????????????????????????????
|
当自己没法继续编程时,结对编程是个好选择,结对编程时,大脑和身体会有化学变化,也就是说思维方式会改变,有助于突破当前的思维阻塞状态。
|
||||||
|
|
||||||
???????????????????????????????????Ч???????????????????
|
听音乐时音乐会占用一部分脑力资源,因此会导致效率下降,但是这不是绝对。
|
||||||
|
|
||||||
???????Щ??????????????????С?????????????????????????
|
多输入一些创造性的内容,比如科幻小说等,自己的创造力也会得到提升。
|
||||||
|
|
||||||
??????????????????????????????????????
|
调试时间也很宝贵,测试驱动开发能够降低调试的时间。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????????????????????????????????????
|
编码和跑马拉松一样,无法全程以最快的速度冲刺,只能通过保持体力和维持节奏来取得胜利。因此要保持好自己的节奏,在疲劳的时候适当休息。
|
||||||
|
|
||||||
?????????????????????????????????????????????????
|
定期做进度衡量,用乐观预估、标准预估和悲观预估这三个时间点。
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????????
|
如果自己预估的进度赶不上截止时间,不要答应在截止时间去完成,因为你知道根据自己的预估这是不可能的。
|
||||||
|
|
||||||
?????????????????????????????????????塣
|
任务完成的标准通常用一个自动化的验收测试来定义。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
帮助他人也会给自己带来好处,在帮助别人的时候不要让自己看起来很仓促,就像是在随便应付。一般帮助别人不需要特别多的时间。也要学会请求别人的帮助,因为自己不可能是万能的,通过别人的帮助能更好的解决问题。
|
||||||
|
|
||||||
# ????????????
|
# 测试驱动开发
|
||||||
|
|
||||||
TDD ??????????????????????????????????γ??????????????????????????????????????????????????????????????飬???????????????緢?? bug???? bug ??緢??????????????
|
TDD 的运行周期很短,可能一两分钟就可以运行一次程序,短周期可以快速得到反馈,反馈在开发中特别重要,一方面是提高程序员编码的激情,另一方面是能够及早发现 bug,而 bug 越早发现修改地代价也越低。
|
||||||
|
|
||||||
TDD ??????
|
TDD 三法则:
|
||||||
|
|
||||||
1. ??д?????
|
1. 先写测试;
|
||||||
2. ???????????????????????д???????
|
2. 在一个单元测试失败的时候,不要再写测试代码;
|
||||||
3. ?????????????????????????????????????д??
|
3. 产品代码能恰好通过当前失败的单元测试即可,不要多写。
|
||||||
|
|
||||||
TDD ???
|
TDD 优点
|
||||||
|
|
||||||
1. ??????????????????????
|
1. 确定性:确定当前系统是否正确;
|
||||||
2. ???????????????????????????????????????????????????????????
|
2. 信心:程序员更有信息去修改混乱的代码,因为通过单元测试可以知道是否修改地正确;
|
||||||
3. ???????????????????????????????????????????????????????з????
|
3. 文档:单元测试是底层设计细节的文档,通过阅读单元测试能够知道程序的运行方式;
|
||||||
|
|
||||||
# ???
|
# 练习
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
卡塔在武术里面是一套设计好的招式,该招式模拟真实搏斗场景,习武者不断训练来让身体熟悉该招式,从而做到纯熟。编程卡塔是一套编程过程敲击鼠标和键盘的动作,练习者不是为了解决真正的问题,因为已经知道了解决方案,而是练习解决这个问题所需要的动作和决策。
|
||||||
|
|
||||||
???????????????????????????????????????д???????????????д??????????????????磬????????????????д??????????????????????????棬?????????
|
瓦萨即使两人对练的卡塔。在编程领域,可以是一个人写单元测试,另一个人写程序通过单元测试。比如,一个人实现排序算法,写测试的人可以很容易地限制速度和内存,给同伴施压。
|
||||||
|
|
649
notes/算法.md
649
notes/算法.md
File diff suppressed because it is too large
Load Diff
|
@ -1,92 +1,92 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [?? 1 ?? ???????????](#??-1-??-???????????)
|
* [第 1 章 可读性的重要性](#第-1-章-可读性的重要性)
|
||||||
* [?? 2 ?? ?????????????](#??-2-??-?????????????)
|
* [第 2 章 用名字表达代码含义](#第-2-章-用名字表达代码含义)
|
||||||
* [?? 3 ?? ??????????????](#??-3-??-??????????????)
|
* [第 3 章 名字不能带来歧义](#第-3-章-名字不能带来歧义)
|
||||||
* [?? 4 ?? ??????????](#??-4-??-??????????)
|
* [第 4 章 良好的代码风格](#第-4-章-良好的代码风格)
|
||||||
* [?? 5 ?? ??§Õ???](#??-5-??-??§Õ???)
|
* [第 5 章 编写注释](#第-5-章-编写注释)
|
||||||
* [?? 6 ?? ??¦Á?§Õ???](#??-6-??-??¦Á?§Õ???)
|
* [第 6 章 如何编写注释](#第-6-章-如何编写注释)
|
||||||
* [?? 7 ?? ??????????????](#??-7-??-??????????????)
|
* [第 7 章 提高控制流的可读性](#第-7-章-提高控制流的可读性)
|
||||||
* [?? 8 ?? ????????](#??-8-??-????????)
|
* [第 8 章 拆分长表达式](#第-8-章-拆分长表达式)
|
||||||
* [?? 9 ?? ??????????](#??-9-??-??????????)
|
* [第 9 章 变量与可读性](#第-9-章-变量与可读性)
|
||||||
* [?? 10 ?? ???????](#??-10-??-???????)
|
* [第 10 章 抽取函数](#第-10-章-抽取函数)
|
||||||
* [?? 11 ?? ???????????](#??-11-??-???????????)
|
* [第 11 章 一次只做一件事](#第-11-章-一次只做一件事)
|
||||||
* [?? 12 ?? ????????????????](#??-12-??-????????????????)
|
* [第 12 章 用自然语言表述代码](#第-12-章-用自然语言表述代码)
|
||||||
* [?? 13 ?? ?????????](#??-13-??-?????????)
|
* [第 13 章 减少代码量](#第-13-章-减少代码量)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ?? 1 ?? ???????????
|
# 第 1 章 可读性的重要性
|
||||||
|
|
||||||
????§Ü?????????????????????????????????????????????????????????????????????????????????§¹???
|
编程有很大一部分时间是在阅读代码,不仅要阅读自己的代码,而且要阅读别人的代码。因此,可读性良好的代码能够大大提高编程效率。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????
|
可读性良好的代码往往会让代码架构更好,因为程序员更愿意去修改这部分代码,而且也更容易修改。
|
||||||
|
|
||||||
???????????????§¹???????????????????????????¦Ë??
|
只有在核心领域为了效率才可以放弃可读性,否则可读性是第一位。
|
||||||
|
|
||||||
# ?? 2 ?? ?????????????
|
# 第 2 章 用名字表达代码含义
|
||||||
|
|
||||||
?§»????§Ò??????????
|
一些比较有表达力的单词:
|
||||||
|
|
||||||
| ???? | ????????? |
|
| 单词 | 可替代单词 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| send | deliver??dispatch??announce??distribute??route |
|
| send | deliver、dispatch、announce、distribute、route |
|
||||||
| find | search??extract??locate??recover |
|
| find | search、extract、locate、recover |
|
||||||
| start| launch??create??begin??open|
|
| start| launch、create、begin、open|
|
||||||
|make|create??set up??build??generate??compose??add??new|
|
|make|create、set up、build、generate、compose、add、new|
|
||||||
|
|
||||||
??? i??j??k ?????????????????????????????????§Ò??????????????????? user_i??member_i?????????????????????????§Ò???????????????????????
|
使用 i、j、k 作为循环迭代器不总是好的,为迭代器添加更有表达力的名字会更好,比如 user_i、member_i。因为循环层次越多,代码越难理解,有表达力的迭代器名字可读性会更高
|
||||||
|
|
||||||
?????????????????????????????§Ò??????????????????????????????????????????????????????????????????????????§»???????
|
为名字添加形容词等信息能让名字更具有表达力,但是名字也会变长。名字长短的准则是:作用域越大,名字越长。因此只有在短作用域才能使用一些简单名字。
|
||||||
|
|
||||||
# ?? 3 ?? ??????????????
|
# 第 3 章 名字不能带来歧义
|
||||||
|
|
||||||
??????????????¡À?????????????§Ü¦Í???????????????????????‰^
|
起完名字要思考一下别人会对这个名字有何解读,会不会误解了原本想表达的含义。
|
||||||
|
|
||||||
?? min??max ?????????¦¶??
|
用 min、max 表示数量范围;
|
||||||
|
|
||||||
?? first??last ???????????????¦¶??begin??end ???????????????¦¶???? end ??????¦Â????
|
用 first、last 表示访问空间的包含范围,begin、end 表示访问空间的排除范围,即 end 不包含尾部。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/26772ecc-a3e3-4ab7-a46f-8b4656990c27.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/26772ecc-a3e3-4ab7-a46f-8b4656990c27.jpg)
|
||||||
|
|
||||||
???????????????? is??can??should??has ??????
|
布尔相关的命名加上 is、can、should、has 等前缀。
|
||||||
|
|
||||||
# ?? 4 ?? ??????????
|
# 第 4 章 良好的代码风格
|
||||||
|
|
||||||
???????§Ü?????
|
适当的空行和缩进
|
||||||
|
|
||||||
?????????????
|
排列整齐的注释:
|
||||||
|
|
||||||
```
|
```
|
||||||
int a = 1; // ???
|
int a = 1; // 注释
|
||||||
int b = 11; // ???
|
int b = 11; // 注释
|
||||||
int c = 111; // ???
|
int c = 111; // 注释
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????? html ??????????????????¨²???? html ?§Ö????????
|
语句顺序不能随意,比如与 html 表单相关联的变量的赋值应该和表单在 html 中的顺序一致;
|
||||||
|
|
||||||
?????????????????????
|
把相关的代码按块组织放在一起。
|
||||||
|
|
||||||
# ?? 5 ?? ??§Õ???
|
# 第 5 章 编写注释
|
||||||
|
|
||||||
????????????????????????????????????????????????????????§»???????????????????§Õ???????????????????????????????????????§»??? getter ?? setter ?????????§»????§Õ?????????????????þŸ
|
阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是并不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
|
||||||
|
|
||||||
???????????????????????????????????????????§Õ????
|
不能因为有注释就随便起个名字,而是争取起个好名字而不写注释。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????
|
可以用注释来记录采用当前解决办法的思考过程,从而让读者更容易理解代码。
|
||||||
|
|
||||||
????????????§»?????????
|
注释用来提醒一些特殊情况。
|
||||||
|
|
||||||
?? TODO ????????
|
用 TODO 等做标记:
|
||||||
|
|
||||||
| ??? | ?¡Â? |
|
| 标记 | 用法 |
|
||||||
|---|---|
|
|---|---|
|
||||||
|TODO| ???? |
|
|TODO| 待做 |
|
||||||
|FIXME| ????? |
|
|FIXME| 待修复 |
|
||||||
|HACH| ?????????? |
|
|HACH| 粗糙的解决方案 |
|
||||||
|XXX| ¦²?????????????????? |
|
|XXX| 危险!这里有重要的问题 |
|
||||||
|
|
||||||
# ?? 6 ?? ??¦Á?§Õ???
|
# 第 6 章 如何编写注释
|
||||||
|
|
||||||
????????????
|
尽量简洁明了:
|
||||||
|
|
||||||
```
|
```
|
||||||
// The first String is student's name
|
// The first String is student's name
|
||||||
|
@ -99,7 +99,7 @@ Map<String, Integer> scoreMap = new HashMap<>();
|
||||||
Map<String, Integer> scoreMap = new HashMap<>();
|
Map<String, Integer> scoreMap = new HashMap<>();
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????
|
添加测试用例来说明:
|
||||||
|
|
||||||
```
|
```
|
||||||
//...
|
//...
|
||||||
|
@ -109,7 +109,7 @@ int add(int x, int y) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???????????????§Ø?????????????????
|
在很复杂的函数调用中对每个参数标上名字:
|
||||||
|
|
||||||
```
|
```
|
||||||
int a = 1;
|
int a = 1;
|
||||||
|
@ -117,37 +117,37 @@ int b = 2;
|
||||||
int num = add(\* x = *\ a, \* y = *\ b);
|
int num = add(\* x = *\ a, \* y = *\ b);
|
||||||
```
|
```
|
||||||
|
|
||||||
???????????????????????????????????????????????
|
使用专业名词来缩短概念上的解释,比如用设计模式名来说明代码。
|
||||||
|
|
||||||
# ?? 7 ?? ??????????????
|
# 第 7 章 提高控制流的可读性
|
||||||
|
|
||||||
?????????§µ?????????????????????????????????????????
|
条件表达式中,左侧是变量,右侧是常数。比如下面第一个语句正确:
|
||||||
|
|
||||||
```
|
```
|
||||||
if(len < 10)
|
if(len < 10)
|
||||||
if(10 > len)
|
if(10 > len)
|
||||||
```
|
```
|
||||||
|
|
||||||
if / else ??????????????????????? ????????? ????????????????
|
if / else 条件语句,先处理以下逻辑:① 正逻辑;② 关键逻辑;③:简单逻辑
|
||||||
```
|
```
|
||||||
if(a == b) {
|
if(a == b) {
|
||||||
// ?????
|
// 正逻辑
|
||||||
} else{
|
} else{
|
||||||
// ?????
|
// 反逻辑
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????? ? : ???????????????????????????¨°??? if / else??
|
只有在逻辑简单的情况下使用 ? : 三目运算符来使代码更紧凑,否则应该拆分成 if / else;
|
||||||
|
|
||||||
do / while ????????????—¨???????????????????§»?????????????? while ?????µµ
|
do / while 的条件放在后面,不够简单明了,并且会有一些迷惑的地方,最好使用 while 来代替。
|
||||||
|
|
||||||
????????? goto ?????? goto ?????????????????????? goto ???????????????????????? goto??
|
如果只有一个 goto 目标,那么 goto 尚且还能接受,但是过于复杂的 goto 会让代码可读性特别差,应该避免使用 goto。
|
||||||
|
|
||||||
??????????§µ????§» return ?????????????????????
|
在嵌套的循环中,用一些 return 语句往往能减少嵌套的层数。
|
||||||
|
|
||||||
# ?? 8 ?? ????????
|
# 第 8 章 拆分长表达式
|
||||||
|
|
||||||
???????????????????????§»??????????????????
|
长表达式的可读性很差,可以引入一些解释变量从而拆分表达式:
|
||||||
|
|
||||||
```
|
```
|
||||||
if line.split(':')[0].strip() == "root":
|
if line.split(':')[0].strip() == "root":
|
||||||
|
@ -159,7 +159,7 @@ if username == "root":
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
????????????§»?????????
|
使用摩根定理简化一些逻辑表达式:
|
||||||
|
|
||||||
```
|
```
|
||||||
if(!a && !b) {
|
if(!a && !b) {
|
||||||
|
@ -172,9 +172,9 @@ if(a || b) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 9 ?? ??????????
|
# 第 9 章 变量与可读性
|
||||||
|
|
||||||
????????????????????????? break ???? return ????????????????????¨¢?
|
去除控制流变量。在循环中通过 break 或者 return 可以减少控制流变量的使用。
|
||||||
|
|
||||||
```
|
```
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
|
@ -195,9 +195,9 @@ while(/* condition */) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
??§³?????????????????§³????????¦Ë??????????????????
|
减小变量作用域。作用域越小,越容易定位到变量所有使用的地方。
|
||||||
|
|
||||||
JavaScript ??????????§³??????????????? submit_form ???????????submitted ????????????????????¦±??????????? submitted ??????????????????? submitted ????????????§µ??????????????????¦¶??
|
JavaScript 可以用闭包减小作用域。以下代码中 submit_form 是函数变量,submitted 变量控制函数不会被提交两次。第一个实现中 submitted 是全局变量,第二个实现把 submitted 放到匿名函数中,从而限制了起作用域范围。
|
||||||
|
|
||||||
```
|
```
|
||||||
submitted = false;
|
submitted = false;
|
||||||
|
@ -218,16 +218,16 @@ var submit_form = (function() {
|
||||||
}
|
}
|
||||||
submitted = true;
|
submitted = true;
|
||||||
}
|
}
|
||||||
}()); // () ?????????????????????
|
}()); // () 使得外层匿名函数立即执行
|
||||||
```
|
```
|
||||||
|
|
||||||
JavaScript ??????? var ????????????????????????????????????????????????????? var ????????????
|
JavaScript 中没有用 var 声明的变量都是全局变量,而全局变量很容易造成迷惑,因此应当总是用 var 来声明变量。
|
||||||
|
|
||||||
?????????¦Ë?????????????¦Ë???????
|
变量定义的位置应当离它使用的位置最近。
|
||||||
|
|
||||||
**???????**
|
**实例解析**
|
||||||
|
|
||||||
?????????????????????????¦²?
|
在一个网页中有以下文本输入字段:
|
||||||
|
|
||||||
```
|
```
|
||||||
<input type = "text" id = "input1" value = "a">
|
<input type = "text" id = "input1" value = "a">
|
||||||
|
@ -236,7 +236,7 @@ JavaScript ??????? var ????????????????????????????????????????????????????? var
|
||||||
<input type = "text" id = "input4" value = "d">
|
<input type = "text" id = "input4" value = "d">
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????????????????????? input ????§µ????????????
|
现在要接受一个字符串并把它放到第一个空的 input 字段中,初始实现如下:
|
||||||
|
|
||||||
```
|
```
|
||||||
var setFirstEmptyInput = function(new_alue) {
|
var setFirstEmptyInput = function(new_alue) {
|
||||||
|
@ -256,11 +256,11 @@ var setFirstEmptyInput = function(new_alue) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????
|
以上实现有以下问题:
|
||||||
|
|
||||||
- found ?????????
|
- found 可以去除;
|
||||||
- elem ?????????
|
- elem 作用域过大;
|
||||||
- ?????? for ??????? while ?????
|
- 可以用 for 循环代替 while 循环;
|
||||||
|
|
||||||
```
|
```
|
||||||
var setFirstEmptyInput = function(new_value) {
|
var setFirstEmptyInput = function(new_value) {
|
||||||
|
@ -277,13 +277,13 @@ var setFirstEmptyInput = function(new_value) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 10 ?? ???????
|
# 第 10 章 抽取函数
|
||||||
|
|
||||||
??????????????????§³?????????§»?????????????????
|
工程学就是把大问题拆分成小问题再把这些问题的解决方案放回一起。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????§³?
|
首先应该明确一个函数的高层次目标,然后对于不是直接为了这个目标工作的代码,抽取出来放到独立的函数中。
|
||||||
|
|
||||||
??????????
|
介绍性的代码:
|
||||||
|
|
||||||
```
|
```
|
||||||
int findClostElement(int[] arr) {
|
int findClostElement(int[] arr) {
|
||||||
|
@ -304,7 +304,7 @@ int findClostElement(int[] arr) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????§³?????????????????????????????????????§³???????????????????????§µ???????????§Ó?????????????????????????
|
以上代码中循环部分主要计算距离,这部分不属于代码高层次目标,高层次目标是寻找最小距离的值,因此可以把这部分代替提取到独立的函数中。这样做也带来一个额外的好处有:可以单独进行测试、可以快速找到程序错误并修改。
|
||||||
|
|
||||||
```
|
```
|
||||||
public int findClostElement(int[] arr) {
|
public int findClostElement(int[] arr) {
|
||||||
|
@ -321,22 +321,22 @@ public int findClostElement(int[] arr) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
并不是函数抽取的越多越好,如果抽取过多,在阅读代码的时候可能需要不断跳来跳去。只有在当前函数不需要去了解某一块代码细节而能够表达其内容时,把这块代码抽取成子函数才是好的。
|
||||||
|
|
||||||
?????????????§³?????????
|
函数抽取也用于减小代码的冗余。
|
||||||
|
|
||||||
# ?? 11 ?? ???????????
|
# 第 11 章 一次只做一件事
|
||||||
|
|
||||||
??????????????????????????????????
|
只做一件事的代码很容易让人知道其要做的事;
|
||||||
|
|
||||||
??????????§Ô???????????????????????????????????????????????????
|
基本流程:列出代码所做的所有任务;把每个任务拆分到不同的函数,或者不同的段落。
|
||||||
|
|
||||||
# ?? 12 ?? ????????????????
|
# 第 12 章 用自然语言表述代码
|
||||||
|
|
||||||
?????????????§Õ??????????????¦Á?????????§Õ????????????????????????
|
先用自然语言书写代码逻辑,也就是伪代码,然后再写代码,这样代码逻辑会更清晰。
|
||||||
|
|
||||||
# ?? 13 ?? ?????????
|
# 第 13 章 减少代码量
|
||||||
|
|
||||||
????????????????????§Ü??<3F>£??????????????????????????????
|
不要过度设计,编码过程会有很多变化,过度设计的内容到最后往往是无用的。
|
||||||
|
|
||||||
????????????
|
多用标准库实现。
|
||||||
|
|
632
notes/计算机操作系统.md
632
notes/计算机操作系统.md
|
@ -1,248 +1,248 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [????? ????](#?????-????)
|
* [第一章 概述](#第一章-概述)
|
||||||
* [??????????????](#??????????????)
|
* [操作系统基本特征](#操作系统基本特征)
|
||||||
* [1. ????](#1-????)
|
* [1. 并发](#1-并发)
|
||||||
* [2. ????](#2-????)
|
* [2. 共享](#2-共享)
|
||||||
* [3. ????](#3-????)
|
* [3. 虚拟](#3-虚拟)
|
||||||
* [4. ??](#4-??)
|
* [4. 异步](#4-异步)
|
||||||
* [??????](#??????)
|
* [系统调用](#系统调用)
|
||||||
* [?ж????](#?ж????)
|
* [中断分类](#中断分类)
|
||||||
* [1. ???ж?](#1-???ж?)
|
* [1. 外中断](#1-外中断)
|
||||||
* [2. ??](#2-??)
|
* [2. 异常](#2-异常)
|
||||||
* [3. ????](#3-????)
|
* [3. 陷入](#3-陷入)
|
||||||
* [??????????](#??????????)
|
* [大内核和微内核](#大内核和微内核)
|
||||||
* [1. ?????](#1-?????)
|
* [1. 大内核](#1-大内核)
|
||||||
* [2. ????](#2-????)
|
* [2. 微内核](#2-微内核)
|
||||||
* [????? ???????](#?????-???????)
|
* [第二章 进程管理](#第二章-进程管理)
|
||||||
* [?????????](#?????????)
|
* [进程与线程](#进程与线程)
|
||||||
* [1. ????](#1-????)
|
* [1. 进程](#1-进程)
|
||||||
* [2. ???](#2-???)
|
* [2. 线程](#2-线程)
|
||||||
* [3. ????](#3-????)
|
* [3. 区别](#3-区别)
|
||||||
* [?????????л?](#?????????л?)
|
* [进程状态的切换](#进程状态的切换)
|
||||||
* [??????](#??????)
|
* [调度算法](#调度算法)
|
||||||
* [1. ?????????е????](#1-?????????е????)
|
* [1. 批处理系统中的调度](#1-批处理系统中的调度)
|
||||||
* [1.1 ?????????FCFS??](#11-?????????fcfs??)
|
* [1.1 先来先服务(FCFS)](#11-先来先服务fcfs)
|
||||||
* [1.2 ??????????SJF??](#12-??????????sjf??)
|
* [1.2 短作业优先(SJF)](#12-短作业优先sjf)
|
||||||
* [1.3 ??????????????SRTN??](#13-??????????????srtn??)
|
* [1.3 最短剩余时间优先(SRTN)](#13-最短剩余时间优先srtn)
|
||||||
* [2. ????????е????](#2-????????е????)
|
* [2. 交互式系统中的调度](#2-交互式系统中的调度)
|
||||||
* [2.1 ?????????](#21-?????????)
|
* [2.1 优先权优先](#21-优先权优先)
|
||||||
* [2.2 ???????](#22-???????)
|
* [2.2 时间片轮转](#22-时间片轮转)
|
||||||
* [2.3 ??????????](#23-??????????)
|
* [2.3 多级反馈队列](#23-多级反馈队列)
|
||||||
* [2.4 ?????????](#24-?????????)
|
* [2.4 短进程优先](#24-短进程优先)
|
||||||
* [3. ?????е????](#3-?????е????)
|
* [3. 实时系统中的调度](#3-实时系统中的调度)
|
||||||
* [???????](#???????)
|
* [进程同步](#进程同步)
|
||||||
* [1. ?????](#1-?????)
|
* [1. 临界区](#1-临界区)
|
||||||
* [2. ???????](#2-???????)
|
* [2. 同步与互斥](#2-同步与互斥)
|
||||||
* [3. ?????](#3-?????)
|
* [3. 信号量](#3-信号量)
|
||||||
* [4. ???](#4-???)
|
* [4. 管程](#4-管程)
|
||||||
* [???????](#???????)
|
* [进程通信](#进程通信)
|
||||||
* [1. ???](#1-???)
|
* [1. 管道](#1-管道)
|
||||||
* [2. ?????](#2-?????)
|
* [2. 信号量](#2-信号量)
|
||||||
* [3. ???????](#3-???????)
|
* [3. 消息队列](#3-消息队列)
|
||||||
* [4. ???](#4-???)
|
* [4. 信号](#4-信号)
|
||||||
* [5. ???????](#5-???????)
|
* [5. 共享内存](#5-共享内存)
|
||||||
* [6. ?????](#6-?????)
|
* [6. 套接字](#6-套接字)
|
||||||
* [???????????](#???????????)
|
* [经典同步问题](#经典同步问题)
|
||||||
* [1. ????-д??????](#1-????-д??????)
|
* [1. 读者-写者问题](#1-读者-写者问题)
|
||||||
* [2. ????????????](#2-????????????)
|
* [2. 哲学家进餐问题](#2-哲学家进餐问题)
|
||||||
* [?????? ????](#??????-????)
|
* [第三章 死锁](#第三章-死锁)
|
||||||
* [??????????](#??????????)
|
* [死锁的条件](#死锁的条件)
|
||||||
* [???????????](#???????????)
|
* [死锁的处理方法](#死锁的处理方法)
|
||||||
* [1. ???????](#1-???????)
|
* [1. 鸵鸟策略](#1-鸵鸟策略)
|
||||||
* [2. ???????](#2-???????)
|
* [2. 死锁预防](#2-死锁预防)
|
||||||
* [2.1 ???????????](#21-???????????)
|
* [2.1 破坏互斥条件](#21-破坏互斥条件)
|
||||||
* [2.2 ???????????????](#22-???????????????)
|
* [2.2 破坏请求与保持条件](#22-破坏请求与保持条件)
|
||||||
* [2.3 ??????????????](#23-??????????????)
|
* [2.3 破坏不可抢占条件](#23-破坏不可抢占条件)
|
||||||
* [2.4 ?????·???](#24-?????·???)
|
* [2.4 破坏环路等待](#24-破坏环路等待)
|
||||||
* [3. ????????](#3-????????)
|
* [3. 死锁避免](#3-死锁避免)
|
||||||
* [3.1 ?????](#31-?????)
|
* [3.1 安全状态](#31-安全状态)
|
||||||
* [3.2 ????????????м???](#32-????????????м???)
|
* [3.2 单个资源的银行家算法](#32-单个资源的银行家算法)
|
||||||
* [3.3 ???????????м???](#33-???????????м???)
|
* [3.3 多个资源的银行家算法](#33-多个资源的银行家算法)
|
||||||
* [4. ????????????????](#4-????????????????)
|
* [4. 死锁检测与死锁恢复](#4-死锁检测与死锁恢复)
|
||||||
* [4.1 ?????????](#41-?????????)
|
* [4.1 死锁检测算法](#41-死锁检测算法)
|
||||||
* [4.2 ???????](#42-???????)
|
* [4.2 死锁恢复](#42-死锁恢复)
|
||||||
* [?????? ?洢??????](#??????-?洢??????)
|
* [第四章 存储器管理](#第四章-存储器管理)
|
||||||
* [???????](#???????)
|
* [虚拟内存](#虚拟内存)
|
||||||
* [???????](#???????)
|
* [分页与分段](#分页与分段)
|
||||||
* [1. ???](#1-???)
|
* [1. 分页](#1-分页)
|
||||||
* [2. ???](#2-???)
|
* [2. 分段](#2-分段)
|
||||||
* [3. ????](#3-????)
|
* [3. 段页式](#3-段页式)
|
||||||
* [4. ???????????](#4-???????????)
|
* [4. 分页与分段区别](#4-分页与分段区别)
|
||||||
* [????????](#????????)
|
* [页面置换算法](#页面置换算法)
|
||||||
* [1. ????Optimal??](#1-????optimal??)
|
* [1. 最佳(Optimal)](#1-最佳optimal)
|
||||||
* [2. ????????FIFO??](#2-????????fifo??)
|
* [2. 先进先出(FIFO)](#2-先进先出fifo)
|
||||||
* [3. ??????δ????LRU??Least Recently Used??](#3-??????δ????lru??least-recently-used??)
|
* [3. 最近最久未使用(LRU,Least Recently Used)](#3-最近最久未使用lru,least-recently-used)
|
||||||
* [4. ????Clock??](#4-????clock??)
|
* [4. 时钟(Clock)](#4-时钟clock)
|
||||||
* [?????? ?豸????](#??????-?豸????)
|
* [第五章 设备管理](#第五章-设备管理)
|
||||||
* [?????????](#?????????)
|
* [磁盘调度算法](#磁盘调度算法)
|
||||||
* [1. ?????????FCFS??First Come First Serverd??](#1-?????????fcfs??first-come-first-serverd??)
|
* [1. 先来先服务(FCFS,First Come First Serverd)](#1-先来先服务fcfs,first-come-first-serverd)
|
||||||
* [2. ??????????????SSTF??Shortest Seek Time First??](#2-??????????????sstf??shortest-seek-time-first??)
|
* [2. 最短寻道时间优先(SSTF,Shortest Seek Time First)](#2-最短寻道时间优先sstf,shortest-seek-time-first)
|
||||||
* [3. ???????SCAN??](#3-???????scan??)
|
* [3. 扫描算法(SCAN)](#3-扫描算法scan)
|
||||||
* [4. ??????????CSCAN??](#4-??????????cscan??)
|
* [4. 循环扫描算法(CSCAN)](#4-循环扫描算法cscan)
|
||||||
* [?ο?????](#?ο?????)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ????? ????
|
# 第一章 概述
|
||||||
|
|
||||||
## ??????????????
|
## 操作系统基本特征
|
||||||
|
|
||||||
### 1. ????
|
### 1. 并发
|
||||||
|
|
||||||
???????????????????????????????ж??????????????????????????ж????䶮
|
并发性是指宏观上在一段时间内能同时运行多个程序,而并行性则指同一时刻能运行多个指令。
|
||||||
|
|
||||||
????????????????????????????????
|
并行需要硬件支持,如多流水线或者多处理器。
|
||||||
|
|
||||||
???????????????????????ó?????????????С?
|
操作系统通过引入进程和线程,使得程序能够并发运行。
|
||||||
|
|
||||||
### 2. ????
|
### 2. 共享
|
||||||
|
|
||||||
??????????е?????????????????????????á?
|
共享是指系统中的资源可以供多个并发的进程共同使用。
|
||||||
|
|
||||||
?????????????????????????
|
有两种共享方式:互斥共享和同时共享。
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????????????????????????????????
|
互斥共享的资源称为临界资源,例如打印机等,在同一时间只允许一个进程访问,否则会出现错误,需要用同步机制来实现对临界资源的访问。
|
||||||
|
|
||||||
### 3. ????
|
### 3. 虚拟
|
||||||
|
|
||||||
??????????????????????????????塣??????????????????????ü?????????ü???????????????????????????????????????????????ü????????????????????д???????????????С?????????????л?????????????ж???????????д???
|
虚拟技术把一个物理实体转换为多个逻辑实体。主要有两种虚拟技术:时分复用技术和空分复用技术,例如多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换,这样就好像有多个处理器进行处理。
|
||||||
|
|
||||||
### 4. ??
|
### 4. 异步
|
||||||
|
|
||||||
???????????????????????????????????????????????????????
|
异步是指进程不是一次性执行完毕,而是走走停停,以不可知的速度向前推进。
|
||||||
|
|
||||||
## ??????
|
## 系统调用
|
||||||
|
|
||||||
???????????????????????????????Щ?????????????????????????????????????????ɡ?
|
如果一个进程在用户态需要用到操作系统的一些功能,就需要使用系统调用从而陷入内核,由操作系统代为完成。
|
||||||
|
|
||||||
???????????????????????豸???????????????????????????洢????????
|
可以由系统调用请求的功能有设备管理、文件管理、进程管理、进程通信、存储器管理等。
|
||||||
|
|
||||||
## ?ж????
|
## 中断分类
|
||||||
|
|
||||||
### 1. ???ж?
|
### 1. 外中断
|
||||||
|
|
||||||
?? CPU ???????????????????? I/O ?????ж??????豸????/????????????????????????????????????/????????????????ж????????ж???
|
由 CPU 执行指令以外的事件引起,如 I/O 结束中断,表示设备输入/输出处理已经完成,处理器能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等。
|
||||||
|
|
||||||
### 2. ??
|
### 2. 异常
|
||||||
|
|
||||||
?? CPU ????????????????????????????????硢??????????
|
由 CPU 执行指令的内部事件引起,如非法操作码、地址越界、算术溢出等。
|
||||||
|
|
||||||
### 3. ????
|
### 3. 陷入
|
||||||
|
|
||||||
???????????????????á?
|
在用户程序中使用系统调用。
|
||||||
|
|
||||||
## ??????????
|
## 大内核和微内核
|
||||||
|
|
||||||
### 1. ?????
|
### 1. 大内核
|
||||||
|
|
||||||
????????????????????????????????????????????????鹲???????????к????????
|
大内核是将操作系统功能作为一个紧密结合的整体放到内核,由于各模块共享信息,因此有很高的性能。
|
||||||
|
|
||||||
### 2. ????
|
### 2. 微内核
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????л?????????????????????
|
由于操作系统不断复杂,因此将一部分操作系统功能移出内核,从而降低内核的复杂性。移出的部分根据分层的原则划分成若干服务,相互独立。但是需要频繁地在用户态和核心态之间进行切换,会有一定的性能损失。
|
||||||
|
|
||||||
# ????? ???????
|
# 第二章 进程管理
|
||||||
|
|
||||||
## ?????????
|
## 进程与线程
|
||||||
|
|
||||||
### 1. ????
|
### 1. 进程
|
||||||
|
|
||||||
????????????????????????????λ??
|
进程是操作系统进行资源分配的基本单位。
|
||||||
|
|
||||||
???????? (Process Control Block, PCB) ???????????????????????????ν????????????????????????? PCB ???????
|
进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。
|
||||||
|
|
||||||
### 2. ???
|
### 2. 线程
|
||||||
|
|
||||||
???????п????ж?????????????????????λ???????????е?????????????????У????????????????
|
一个线程中可以有多个线程,是独立调度的基本单位。同一个进程中的多个线程之间可以并发执行,它们共享进程资源。
|
||||||
|
|
||||||
### 3. ????
|
### 3. 区别
|
||||||
|
|
||||||
?? ???????????????????????????λ?????????????????????????????????????????
|
① 拥有资源:进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问率属进程的资源。
|
||||||
|
|
||||||
?? ???????????????????????λ???????????У??????л?????????????л???????????????????л?????????????е?????????????????л???
|
② 调度:线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。
|
||||||
|
|
||||||
?? ?????????????????????????????????????????????????????I/O ?豸???????????????????????????????????????????????????????н????л?????漰?????н??? CPU ????????漰???????? CPU ?????????á???????л????豣???????????????????????????С??????????????????????????????????????????Щ????????????????????????????????????????????
|
③ 系统开销:由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,因此操作系统所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置。而线程切换时只需保存和设置少量寄存器内容,开销很小。此外,由于同一进程内的多个线程共享进程的地址空间,因此,这些线程之间的同步与通信非常容易实现,甚至无需操作系统的干预。
|
||||||
|
|
||||||
?? ?????棺???????? (IPC) ?????????????????ε?????????????????????????????????????/д????????Σ?????????????????????
|
④ 通信方面:进程间通信 (IPC) 需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以通过直接读/写进程数据段(如全局变量)来进行通信。
|
||||||
|
|
||||||
??????QQ ?? ??????????????????????????????к?????????? http ????????????????????????????????????????????????е????????????????? http ???????????????????????????????????
|
举例:QQ 和 浏览器是两个进程,浏览器进程里面有很多线程,例如 http 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 http 请求时,浏览器还可以响应用户的其它事件。
|
||||||
|
|
||||||
## ?????????л?
|
## 进程状态的切换
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1706ce58-a081-4fed-9b36-c3c0d7e22b3a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1706ce58-a081-4fed-9b36-c3c0d7e22b3a.jpg)
|
||||||
|
|
||||||
????????????????????????????????????????????????????? CPU????? CPU ????????????????????????
|
阻塞状态是缺少需要的资源从而由运行状态转换而来,但是该资源不包括 CPU,缺少 CPU 会让进程从运行态转换为就绪态。
|
||||||
|
|
||||||
??о????????????????????????????????????????????????????????????????? CPU ????????????????????????????????????? CPU ??????????????????????????????ε????
|
只有就绪态和运行态可以相互转换,其它的都是单向转换。就绪状态的进程通过调度算法从而获得 CPU 时间,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完之后就会转为就绪状态,等待下一次调度。
|
||||||
|
|
||||||
## ??????
|
## 调度算法
|
||||||
|
|
||||||
?????????????????????????
|
需要针对不同环境来讨论调度算法。
|
||||||
|
|
||||||
### 1. ?????????е????
|
### 1. 批处理系统中的调度
|
||||||
|
|
||||||
#### 1.1 ?????????FCFS??
|
#### 1.1 先来先服务(FCFS)
|
||||||
|
|
||||||
first-come first-serverd??
|
first-come first-serverd。
|
||||||
|
|
||||||
?????????????????е??????
|
调度最先进入就绪队列的作业。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????У???????????????к?????????????????????????
|
有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。
|
||||||
|
|
||||||
#### 1.2 ??????????SJF??
|
#### 1.2 短作业优先(SJF)
|
||||||
|
|
||||||
shortest job first??
|
shortest job first。
|
||||||
|
|
||||||
???????????????????????
|
调度估计运行时间最短的作业。
|
||||||
|
|
||||||
??????п????????????????????????????????????????ж??????????????????????ò????????
|
长作业有可能会饿死,处于一直等待短作业执行完毕的状态。如果一直有短作业到来,那么长作业永远得不到调度。
|
||||||
|
|
||||||
#### 1.3 ??????????????SRTN??
|
#### 1.3 最短剩余时间优先(SRTN)
|
||||||
|
|
||||||
shortest remaining time next??
|
shortest remaining time next。
|
||||||
|
|
||||||
### 2. ????????е????
|
### 2. 交互式系统中的调度
|
||||||
|
|
||||||
#### 2.1 ?????????
|
#### 2.1 优先权优先
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????????
|
除了可以手动赋予优先权之外,还可以把响应比作为优先权,这种调度方式叫做高响应比优先调度算法。
|
||||||
|
|
||||||
????? = (?????? + ?????????) / ????????? = ?????? / ?????????
|
响应比 = (等待时间 + 要求服务时间) / 要求服务时间 = 响应时间 / 要求服务时间
|
||||||
|
|
||||||
??????????????????? SJF ?г????????????????????????????????????????????????????
|
这种调度算法主要是为了解决 SJF 中长作业可能会饿死的问题,因为随着等待时间的增长,响应比也会越来越高。
|
||||||
|
|
||||||
#### 2.2 ???????
|
#### 2.2 时间片轮转
|
||||||
|
|
||||||
?????о???????? FCFS ??????????????У???ε???????? CPU ????????????????????????????????????????????????????????????ж????????????????????У??????????????????е??β?????????? CPU ??????????????
|
将所有就绪进程按 FCFS 的原则排成一个队列,每次调度时,把 CPU 分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 分配给队首的进程。
|
||||||
|
|
||||||
???????????Ч????????к???????????ν????л??????????????????????????????????????????????????л?????????????л????????????
|
时间片轮转算法的效率和时间片有很大关系。因为每次进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太短,进程切换太频繁,在进程切换上就会花过多时间。
|
||||||
|
|
||||||
#### 2.3 ??????????
|
#### 2.3 多级反馈队列
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png)
|
||||||
|
|
||||||
?? ?????????????У???????????и??費??????????????????е??????????????????д????????????е??????????????????????????????н?????????????С?????????????????????????У????????????涨????????????С??
|
① 设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权越高的队列中,为每个进程所规定的执行时间片就越小。
|
||||||
|
|
||||||
?? ?????????????????????????????????е??β???? FCFS ???????????????????????????????????????????????????????????????????????????????????δ????????????????????????????е??β??
|
② 当一个新进程进入内存后,首先将它放入第一队列的末尾,按 FCFS 原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入下一个队列的队尾。
|
||||||
|
|
||||||
?? ????? i -1 ?????о????????????? i ?????е???????С?
|
③ 仅当前 i -1 个队列均空时,才会调度第 i 队列中的进程运行。
|
||||||
|
|
||||||
????????????????ж????????????
|
优点:实时性好,也适合运行短作业和长作业。
|
||||||
|
|
||||||
#### 2.4 ?????????
|
#### 2.4 短进程优先
|
||||||
|
|
||||||
### 3. ?????е????
|
### 3. 实时系统中的调度
|
||||||
|
|
||||||
????????????????????????????????????
|
实时系统要一个服务请求在一个确定时间内得到响应。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????
|
分为硬实时和软实时,前者必须满足绝对的截止时间,后者可以容忍一定的超时。
|
||||||
|
|
||||||
## ???????
|
## 进程同步
|
||||||
|
|
||||||
### 1. ?????
|
### 1. 临界区
|
||||||
|
|
||||||
???????????з??????δ????????????
|
对临界资源进行访问的那段代码称为临界区。
|
||||||
|
|
||||||
?????????????????????????????????????????????м?顣
|
为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
// entry section
|
// entry section
|
||||||
|
@ -250,44 +250,44 @@ shortest remaining time next??
|
||||||
// exit section
|
// exit section
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. ???????
|
### 2. 同步与互斥
|
||||||
|
|
||||||
????????????????????У??????????????????????????????????????????
|
同步指多个进程按一定顺序执行;互斥指多个进程在同一时刻只有一个进程能进入临界区。
|
||||||
|
|
||||||
????????????????????????????????????????????????????
|
同步是在对临界区互斥访问的基础上,通过其它机制来实现有序访问的。
|
||||||
|
|
||||||
### 3. ?????
|
### 3. 信号量
|
||||||
|
|
||||||
**???????Samaphore??**???????????????????????? down ?? up ???????????????? P ?? V ??????
|
**信号量(Samaphore)**是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。
|
||||||
|
|
||||||
- **down** : ???????????? 0 ????? - 1 ?????????????????? 0???????????????????????? 0??
|
- **down** : 如果信号量大于 0 ,执行 - 1 操作;如果信号量等于 0,将进程睡眠,等待信号量大于 0;
|
||||||
- **up**???????????? + 1 ????????????????????????????? down ??????
|
- **up**:对信号量执行 + 1 操作,并且唤醒睡眠的进程,让进程完成 down 操作。
|
||||||
|
|
||||||
down ?? up ????????????????????????????????????????Щ??????????????ж??
|
down 和 up 操作需要被设计成原语,不可分割,通常的做法是在执行这些操作的时候屏蔽中断。
|
||||||
|
|
||||||
???????????????? 0 ???? 1???????????**????????Mutex??**??0 ?????????????????1 ??????????????
|
如果信号量的取值只能为 0 或者 1,那么就成为了**互斥量(Mutex)**,0 表示临界区已经加锁,1 表示临界区解锁。
|
||||||
|
|
||||||
```c
|
```c
|
||||||
typedef int samaphore;
|
typedef int samaphore;
|
||||||
samaphore mutex = 1;
|
samaphore mutex = 1;
|
||||||
void P1() {
|
void P1() {
|
||||||
down(mutex);
|
down(mutex);
|
||||||
// ?????
|
// 临界区
|
||||||
up(mutex);
|
up(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void P2() {
|
void P2() {
|
||||||
down(mutex);
|
down(mutex);
|
||||||
// ?????
|
// 临界区
|
||||||
up(mutex);
|
up(mutex);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**?????????????????-??????????**
|
**使用信号量实现生产者-消费者问题**
|
||||||
|
|
||||||
???????????? mutex ?????????????з????empty ??????????????????full ???????????????????
|
使用一个互斥量 mutex 来对临界资源进行访问;empty 记录空缓冲区的数量,full 记录满缓冲区的数量。
|
||||||
|
|
||||||
???????????? down ??????????????????????????????????????????????????????????????????? down ???????????????????????????????????????? down(empty) ?????????? empty = 0?????????????????????????????????????????????????????????????????????? up(empty) ??????????????????????????????????
|
注意,必须先执行 down 操作再用互斥量对临界区加锁,否则会出现死锁。如果都先对临界区加锁,然后再执行 down 操作,考虑这种情况:生产者对临界区加锁后,执行 down(empty) 操作,发现 empty = 0,此时生成者睡眠。消费者此时不能进入临界区,因为生产者对临界区加锁了,也就无法对执行 up(empty) 操作,那么生产者和消费者就会一直等待下去。
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#define N 100
|
#define N 100
|
||||||
|
@ -319,11 +319,11 @@ void consumer() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. ???
|
### 4. 管程
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????????????????????????????????????????
|
使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。
|
||||||
|
|
||||||
c ?????????????????????????????? Pascal ??????????????????????е??????? insert() ?? remove() ??????????????????????????????????????????-??????????
|
c 语言不支持管程,下面的示例代码使用了类 Pascal 语言来描述管程。示例代码中的管程提供了 insert() 和 remove() 方法,客户端代码通过调用这两个方法来解决生产者-消费者问题。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
monitor ProducerConsumer
|
monitor ProducerConsumer
|
||||||
|
@ -342,11 +342,11 @@ monitor ProducerConsumer
|
||||||
end monitor;
|
end monitor;
|
||||||
```
|
```
|
||||||
|
|
||||||
??????????????????????????????????????ù??????????????????е??????????ù??????????????????????????????????????ù???
|
管程有一个重要特性:在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,必须将进程阻塞,否者其它进程永远不能使用管程。
|
||||||
|
|
||||||
????????? **????????** ????????????**wait()** ?? **signal()** ??????????????????????????? wait() ?????????????????????????ó????????????????С?signal() ??????????????????????
|
管程引入了 **条件变量** 以及相关的操作:**wait()** 和 **signal()** 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来让另一个进程持有。signal() 操作用于唤醒被阻塞的进程。
|
||||||
|
|
||||||
**??ù???????????-??????????**
|
**使用管程实现生成者-消费者问题**
|
||||||
|
|
||||||
```html
|
```html
|
||||||
monitor ProducerConsumer
|
monitor ProducerConsumer
|
||||||
|
@ -390,55 +390,55 @@ begin
|
||||||
end;
|
end;
|
||||||
```
|
```
|
||||||
|
|
||||||
## ???????
|
## 进程通信
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????????????????????
|
进程通信可以看成是不同进程间的线程通信,对于同一个进程内线程的通信方式,主要使用信号量、条件变量等同步机制。
|
||||||
|
|
||||||
### 1. ???
|
### 1. 管道
|
||||||
|
|
||||||
??????????????????????????????С?????????????????????????????????????????????????????д??????????β??д???????????????????????????????????????????????????????????????????????Щ?????
|
管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的首端读出数据。数据读出后将从管道中移走,其它读进程都不能再读到这些数据。
|
||||||
|
|
||||||
???????????????????????????????????????????д??????????????????????????????????????????????д????????????????????????????????д?????????????
|
管道提供了简单的流控制机制,进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样地,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。
|
||||||
|
|
||||||
Linux ?й??????????????????
|
Linux 中管道是通过空文件来实现。
|
||||||
|
|
||||||
??????????
|
管道有三种:
|
||||||
|
|
||||||
?? ?????????????????????????????????????????????????????????????????????
|
① 普通管道:有两个限制:一是只支持半双工通信方式,即只能单向传输;二是只能在父子进程之间使用;
|
||||||
|
|
||||||
?? ????????????????????????????
|
② 流管道:去除第一个限制,支持双向传输;
|
||||||
|
|
||||||
?? ?????????????????????????????????????????????
|
③ 命名管道:去除第二个限制,可以在不相关进程之间进行通信。
|
||||||
|
|
||||||
### 2. ?????
|
### 2. 信号量
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Ρ?
|
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其它进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
|
||||||
|
|
||||||
### 3. ???????
|
### 3. 消息队列
|
||||||
|
|
||||||
??????п?????????????????????????????????????????????С????????
|
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
|
||||||
|
|
||||||
### 4. ???
|
### 4. 信号
|
||||||
|
|
||||||
?????????????????????????????????????????????????
|
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
|
||||||
|
|
||||||
### 5. ???????
|
### 5. 共享内存
|
||||||
|
|
||||||
????????????????????????????????????棬??ι??????????????????????????????????????????????????? IPC ??????????????????????????????Ч??????????????????????????????????????????????????????????????????
|
共享内存就是映射一段能被其它进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其它进程间通信方式运行效率低而专门设计的。它往往与其它通信机制(如信号量)配合使用,来实现进程间的同步和通信。
|
||||||
|
|
||||||
### 6. ?????
|
### 6. 套接字
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????
|
套接字也是一种进程间通信机制,与其它通信机制不同的是,它可用于不同机器间的进程通信。
|
||||||
|
|
||||||
## ???????????
|
## 经典同步问题
|
||||||
|
|
||||||
??????????????????????????????
|
生产者和消费者问题前面已经讨论过。
|
||||||
|
|
||||||
### 1. ????-д??????
|
### 1. 读者-写者问题
|
||||||
|
|
||||||
????????????????????ж???????????????????д???д??д????????????
|
允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写操作同时发生。
|
||||||
|
|
||||||
?????????? count ????????????ж????????????????????????? count_mutex ????? count ??????????????? data_mutex ??????д???????????
|
一个整型变量 count 记录在对数据进行读操作的进程数量,一个互斥量 count_mutex 用于对 count 加锁,一个互斥量 data_mutex 用于对读写的数据加锁。
|
||||||
|
|
||||||
```c
|
```c
|
||||||
typedef int semaphore;
|
typedef int semaphore;
|
||||||
|
@ -450,7 +450,7 @@ void reader() {
|
||||||
while(TRUE) {
|
while(TRUE) {
|
||||||
down(count_mutex);
|
down(count_mutex);
|
||||||
count++;
|
count++;
|
||||||
if(count == 1) down(data_mutex); // ????????????????????м????????д???????
|
if(count == 1) down(data_mutex); // 第一个读者需要对数据进行加锁,防止写进程访问
|
||||||
up(count_mutex);
|
up(count_mutex);
|
||||||
read();
|
read();
|
||||||
down(count_mutex);
|
down(count_mutex);
|
||||||
|
@ -469,13 +469,13 @@ void writer() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. ????????????
|
### 2. 哲学家进餐问题
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg)
|
||||||
|
|
||||||
????????Χ???????????????????????????????????????????????????????????????????????????????????????????????????????
|
五个哲学家围着一张圆周,每个哲学家面前放着饭。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先一根一根拿起左右两边的筷子。
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????????????
|
下面是一种错误的解法,考虑到如果每个哲学家同时拿起左手边的筷子,那么就无法拿起右手边的筷子,造成死锁。
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#define N 5
|
#define N 5
|
||||||
|
@ -496,7 +496,7 @@ void philosopher(int i) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????????????????????????δ????????
|
为了防止死锁的发生,可以加一点限制,只允许同时拿起左右两边的筷子,方法是引入一个互斥量,对拿起两个筷子的那段代码加锁。
|
||||||
|
|
||||||
```c
|
```c
|
||||||
semaphore mutex = 1;
|
semaphore mutex = 1;
|
||||||
|
@ -517,223 +517,223 @@ void philosopher(int i) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?????? ????
|
# 第三章 死锁
|
||||||
|
|
||||||
## ??????????
|
## 死锁的条件
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png)
|
||||||
|
|
||||||
1. ????
|
1. 互斥
|
||||||
2. ????????????????????????????????????????????????????
|
2. 请求与保持:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
|
||||||
3. ???????
|
3. 不可抢占
|
||||||
4. ??·???
|
4. 环路等待
|
||||||
|
|
||||||
## ???????????
|
## 死锁的处理方法
|
||||||
|
|
||||||
### 1. ???????
|
### 1. 鸵鸟策略
|
||||||
|
|
||||||
????????????????????????????
|
把头埋在沙子里,假装根本没发生问题。
|
||||||
|
|
||||||
?????????????
|
这种策略不可取。
|
||||||
|
|
||||||
### 2. ???????
|
### 2. 死锁预防
|
||||||
|
|
||||||
????????????????????????
|
在程序运行之前预防发生死锁。
|
||||||
|
|
||||||
#### 2.1 ???????????
|
#### 2.1 破坏互斥条件
|
||||||
|
|
||||||
?????????????????????????????????????Ψ????????????????????????????????????
|
例如假脱机打印机技术允许若干个进程同时输出,唯一真正请求物理打印机的进程是打印机守护进程。
|
||||||
|
|
||||||
#### 2.2 ???????????????
|
#### 2.2 破坏请求与保持条件
|
||||||
|
|
||||||
??????????涨???н??????????????????????????????
|
一种实现方式是规定所有进程在开始执行前请求所需要的全部资源。
|
||||||
|
|
||||||
#### 2.3 ??????????????
|
#### 2.3 破坏不可抢占条件
|
||||||
|
|
||||||
#### 2.4 ?????·???
|
#### 2.4 破坏环路等待
|
||||||
|
|
||||||
????????????????????????????????????
|
给资源统一编号,进程只能按编号顺序来请求资源。
|
||||||
|
|
||||||
### 3. ????????
|
### 3. 死锁避免
|
||||||
|
|
||||||
??????????????????????
|
在程序运行时避免发生死锁。
|
||||||
|
|
||||||
#### 3.1 ?????
|
#### 3.1 安全状态
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed523051-608f-4c3f-b343-383e2d194470.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed523051-608f-4c3f-b343-383e2d194470.png)
|
||||||
|
|
||||||
? a ?????? has ???????е?????????????? max ??????????????????free ??????п????????????????? a ????????????? B ????????????????????н???????? B????? free ??? 4??????????????????? C ?? A????????н???????????У????????? a ??????????????
|
图 a 的第二列 has 表示已拥有的资源数,第三列 max 表示总共需要的资源数,free 表示还有可以使用的资源数。从图 a 开始出发,先让 B 拥有所需的所有资源,运行结束后释放 B,此时 free 变为 4;接着以同样的方式运行 C 和 A,使得所有进程都能成功运行,因此可以称图 a 所示的状态时安全的。
|
||||||
|
|
||||||
???壺?????????????????????????н??????????????????????????????????????????????????????????????????????????
|
定义:如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能够使得每一个进程运行完毕,则称该状态是安全的。
|
||||||
|
|
||||||
#### 3.2 ????????????м???
|
#### 3.2 单个资源的银行家算法
|
||||||
|
|
||||||
???С????????м???????????????????????????????????????ж?????????????????????????????????????????????????
|
一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png)
|
||||||
|
|
||||||
??? c ????????????????????????????????????? c ?е?????
|
上图 c 为不安全状态,因此算法会拒绝之前的请求,从而避免进入图 c 中的状态。
|
||||||
|
|
||||||
#### 3.3 ???????????м???
|
#### 3.3 多个资源的银行家算法
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png)
|
||||||
|
|
||||||
????????????????????????????????????????????????????????????????????????? E??P ??? A ???????????????????????????????????????????????????????????????????? A=(1020)????? 4 ??????????? 1/0/2/0??
|
上图中有五个进程,四个资源。左边的图表示已经分配的资源,右边的图表示还需要分配的资源。最右边的 E、P 以及 A 分别表示:总资源、已分配资源以及可用资源,注意这三个为向量,而不是具体数值,例如 A=(1020),表示 4 个资源分别还剩下 1/0/2/0。
|
||||||
|
|
||||||
?????????????????????
|
检查一个状态是否安全的算法如下:
|
||||||
|
|
||||||
?? ????????????????????С????????? A??????????????????У?????????????????????????????
|
① 查找右边的矩阵是否存在一行小于等于向量 A。如果不存在这样的行,那么系统将会发生死锁,状态是不安全的。
|
||||||
|
|
||||||
?? ?????????????У????????????????????????????????? A ?С?
|
② 假若找到这样一行,将该进程标记为终止,并将其已分配资源加到 A 中。
|
||||||
|
|
||||||
?? ???????????????????н????????????????????????
|
③ 重复以上两步,直到所有进程都标记为终止,则状态时安全的。
|
||||||
|
|
||||||
### 4. ????????????????
|
### 4. 死锁检测与死锁恢复
|
||||||
|
|
||||||
??????????????????????????????????????????л????
|
不试图组织死锁,而是当检测到死锁发生时,采取措施进行恢复。
|
||||||
|
|
||||||
#### 4.1 ?????????
|
#### 4.1 死锁检测算法
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????У????????е????????????????????????????????????С?
|
死锁检测的基本思想是,如果一个进程所请求的资源能够被满足,那么就让它执行,释放它拥有的所有资源,然后让其它能满足条件的进程执行。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png)
|
||||||
|
|
||||||
????У??????????????????????????????????????
|
上图中,有三个进程四个资源,每个数据代表的含义如下:
|
||||||
|
|
||||||
E ?????????????
|
E 向量:资源总量
|
||||||
A ??????????????
|
A 向量:资源剩余量
|
||||||
C ???????????????е?????????????ж????????????????????????
|
C 矩阵:每个进程所拥有的资源数量,每一行都代表一个进程拥有资源的数量
|
||||||
R ???????????????????????
|
R 矩阵:每个进程请求的资源数量
|
||||||
|
|
||||||
???? P<sub>1</sub> ?? P<sub>2</sub> ?????????????ò?????????н??? P<sub>3</sub> ??????? P<sub>3</sub> ??У??????? P<sub>3</sub> ??е????????? A = (2 2 2 0)??P<sub>1</sub> ??????У???к???? P<sub>1</sub> ??е?????? A = (4 2 2 2) ??P<sub>2</sub> ???????С????н?????????????У??????????
|
进程 P<sub>1</sub> 和 P<sub>2</sub> 所请求的资源都得不到满足,只有进程 P<sub>3</sub> 可以,让 P<sub>3</sub> 执行,之后释放 P<sub>3</sub> 拥有的资源,此时 A = (2 2 2 0)。P<sub>1</sub> 可以执行,执行后释放 P<sub>1</sub> 拥有的资源, A = (4 2 2 2) ,P<sub>2</sub> 也可以执行。所有进程都可以顺利执行,没有死锁。
|
||||||
|
|
||||||
??????????
|
算法总结如下:
|
||||||
|
|
||||||
???????????????????????й????п????????????????????κ???б????????????????????
|
每个进程最开始时都不被标记,执行过程有可能被标记。当算法结束时,任何没有被标记的进程都是死锁进程。
|
||||||
|
|
||||||
?? ????????б?????? P<sub>i</sub>??????????????С????? A??
|
① 寻找一个没有标记的进程 P<sub>i</sub>,它所请求的资源小于等于 A。
|
||||||
?? ????????????????????????? C ?????? i ????????? A ?У?????????????? ???
|
② 如果找到了这样一个进程,那么将 C 矩阵的第 i 行向量加到 A 中,标记该进程,并转回 ①。
|
||||||
?? ???????????????????????????
|
③ 如果有没有这样一个进程,算法终止。
|
||||||
|
|
||||||
#### 4.2 ???????
|
#### 4.2 死锁恢复
|
||||||
|
|
||||||
?? ??????????
|
① 利用抢占恢复
|
||||||
?? ???????
|
② 杀死进程
|
||||||
|
|
||||||
# ?????? ?洢??????
|
# 第四章 存储器管理
|
||||||
|
|
||||||
## ???????
|
## 虚拟内存
|
||||||
|
|
||||||
????????????????????????????????????飬??????? ?????Щ????????????棬??????????????????????棬???????????????????????????С?
|
每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一 页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。
|
||||||
|
|
||||||
??????????????????????????е????????????????????б??????????????????????????????????е????????????????????????????????????沢?????????????䶮
|
当程序引用到一部分在物理内存中的地址空间时,由硬件立即执行必要的映射。当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的指令。
|
||||||
|
|
||||||
## ???????
|
## 分页与分段
|
||||||
|
|
||||||
### 1. ???
|
### 1. 分页
|
||||||
|
|
||||||
??????????????????????????С?????????????????????????????????????飬??????С?????????????????????????????????У?????????????????????????????????????????
|
用户程序的地址空间被划分为若干固定大小的区域,称为“页”。相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配,由一个页表来维护它们之间的映射关系。
|
||||||
|
|
||||||
### 2. ???
|
### 2. 分段
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png)
|
||||||
|
|
||||||
??????????????????????н??????????? 4 ????????????????????÷?????????????????????????????????????????
|
上图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态递增的特点会导致覆盖问题的出现。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png)
|
||||||
|
|
||||||
??ε???????????????Σ?????ι?????????????????????ε????????????????????
|
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,可以动态改变。
|
||||||
|
|
||||||
????ζ????????????????
|
每个段都需要程序员来划分。
|
||||||
|
|
||||||
### 3. ????
|
### 3. 段页式
|
||||||
|
|
||||||
?÷?η?????????????????洢???????????????????λ????????????Σ????????????????????????η??????С?????????
|
用分段方法来分配和管理虚拟存储器。程序的地址空间按逻辑单位分成基本独立的段,而每一段有自己的段名,再把每段分成固定大小的若干页。
|
||||||
|
|
||||||
?÷??????????????????档???????????????????????С????洢?飬???????????κ????????????????????????????е????????????????????????
|
用分页方法来分配和管理实存。即把整个主存分成与上述页大小相等的存储块,可装入作业的任何一页。程序对内存的调入或调出是按页进行的。但它又可按段实现共享和保护。
|
||||||
|
|
||||||
### 4. ???????????
|
### 4. 分页与分段区别
|
||||||
|
|
||||||
?? ???????????????????????????????????????????????Ρ?
|
① 对程序员的透明性:分页透明,但是分段需要程序员显示划分每个段。
|
||||||
|
|
||||||
?? ??????????????????????????????????
|
② 地址空间的维度:分页是一维地址空间,分段是二维的。
|
||||||
|
|
||||||
?? ??С????????????С??????ε??С?????????
|
③ 大小是否可以改变:页的大小不可变,段的大小可以动态改变。
|
||||||
|
|
||||||
?? ??????????????????????????棬?????????????????????????????????????????????????????????????????????????????
|
④ 出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。
|
||||||
|
|
||||||
## ????????
|
## 页面置换算法
|
||||||
|
|
||||||
????????й????У???????????????治????????????????????棬?????????????п????????????????е????????浽?????????У???????????????????????????С?????????????????????????????????????????????????
|
在程序运行过程中,若其所要访问的页面不在内存而需要把它们调入内存,但是内存已无空闲空间时,系统必须从内存中调出一个页面到磁盘对换区中,并且将程序所需要的页面调入内存中。页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。
|
||||||
|
|
||||||
### 1. ????Optimal??
|
### 1. 最佳(Optimal)
|
||||||
|
|
||||||
???????????????潫???????????????????????????????????????
|
所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。
|
||||||
|
|
||||||
????????????????????????????????????????????
|
是一种理论上的算法,因为无法知道一个页面多长时间会被再访问到。
|
||||||
|
|
||||||
??????????????????????????????飬??????????????????У?
|
举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:
|
||||||
|
|
||||||
7??0??1??2??0??3??0??4??2??3??0??3??2??1??2??0??1??7??0??1
|
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
|
||||||
|
|
||||||
?????????????? 7,0,1 ????????????档?????????????? 2 ??????????ж??????? 7 ???????????? 7 ??α?????????????
|
进程运行时,先将 7,0,1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。
|
||||||
|
|
||||||
### 2. ????????FIFO??
|
### 2. 先进先出(FIFO)
|
||||||
|
|
||||||
???????????????????????档
|
所选择换出的页面是最先进入的页面。
|
||||||
|
|
||||||
????????Щ????????????????????????????????????
|
该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。
|
||||||
|
|
||||||
### 3. ??????δ????LRU??Least Recently Used??
|
### 3. 最近最久未使用(LRU,Least Recently Used)
|
||||||
|
|
||||||
???????????????????????????????????????????????????LRU ????????δ??????滻????
|
虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。
|
||||||
|
|
||||||
???????????????????д洢???????????????????????????????????????????????????????????????????????????????????????????????????????δ??????????????????????
|
可以用栈来实现该算法,栈中存储页面的页面号。当进程访问一个页面时,将该页面的页面号从栈移除,并将它压入栈顶,这样,最近被访问的页面的页面号总是在栈顶,而最近最久未使用的页面的页面号总是在栈底。
|
||||||
|
|
||||||
4??7??0??7??1??0??1??2??1??2??6
|
4,7,0,7,1,0,1,2,1,2,6
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png)
|
||||||
|
|
||||||
### 4. ????Clock??
|
### 4. 时钟(Clock)
|
||||||
|
|
||||||
Clock ?????????????????????λ?????????汻????????????????? 1??
|
Clock 页面置换算法需要用到一个访问位,当一个页面被访问时,将访问为置为 1。
|
||||||
|
|
||||||
???????????е??????????????????????У??????ж?????????鵱????????????????λ?????????λ? 0?????????滻???????????????λ????? 0????????????ε???????????????顣
|
首先,将内存中的所有页面链接成一个循环队列,当缺页中断发生时,检查当前指针所指向页面的访问位,如果访问位为 0,就将该页面换出;否则将该页的访问位设置为 0,给该页面第二次的机会,移动指针继续检查。
|
||||||
|
|
||||||
# ?????? ?豸????
|
# 第五章 设备管理
|
||||||
|
|
||||||
## ?????????
|
## 磁盘调度算法
|
||||||
|
|
||||||
??????????????????????????????д?????????????????????????????????????????????????????????
|
当多个进程同时请求访问磁盘时,需要进行磁盘调度来控制对磁盘的访问。磁盘调度的主要目标是使磁盘的平均寻道时间最少。
|
||||||
|
|
||||||
### 1. ?????????FCFS??First Come First Serverd??
|
### 1. 先来先服务(FCFS,First Come First Serverd)
|
||||||
|
|
||||||
?????????????????????????????е?????????????????????????????δ????????κ???????????????????????
|
根据进程请求访问磁盘的先后次序来进行调度。优点是公平和简单,缺点也很明显,因为未对寻道做任何优化,使平均寻道时间可能较长。
|
||||||
|
|
||||||
### 2. ??????????????SSTF??Shortest Seek Time First??
|
### 2. 最短寻道时间优先(SSTF,Shortest Seek Time First)
|
||||||
|
|
||||||
????????????????????????????????????е???????????????????????????????????? FCFS ?ú??
|
要求访问的磁道与当前磁头所在磁道距离最近的优先进行调度。这种算法并不能保证平均寻道时间最短,但是比 FCFS 好很多。
|
||||||
|
|
||||||
### 3. ???????SCAN??
|
### 3. 扫描算法(SCAN)
|
||||||
|
|
||||||
SSTF ???????м???????????????????????????????????????????????????????????????????????????????????????????????
|
SSTF 会出现进行饥饿现象。考虑以下情况,新进程请求访问的磁道与磁头所在磁道的距离总是比一个在等待的进程来的近,那么等待的进程会一直等待下去。
|
||||||
|
|
||||||
SCAN ???? SSTF ????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
SCAN 算法在 SSTF 算法之上考虑了磁头的移动方向,要求所请求访问的磁道在磁头当前移动方向上才能够得到调度。因为考虑了移动方向,那么一个进程请求访问的磁道一定会得到调度。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????????У????????? SCAN ??????????????
|
当一个磁头自里向外移动时,移到最外侧会改变移动方向为自外向里,这种移动的规律类似于电梯的运行,因此又常称 SCAN 算法为电梯调度算法。
|
||||||
|
|
||||||
### 4. ??????????CSCAN??
|
### 4. 循环扫描算法(CSCAN)
|
||||||
|
|
||||||
CSCAN ?? SCAN ??????????????????????????????????
|
CSCAN 对 SCAN 进行了改动,要求磁头始终沿着一个方向移动。
|
||||||
|
|
||||||
# ?ο?????
|
# 参考资料
|
||||||
|
|
||||||
- Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hall Press, 2014.
|
- Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hall Press, 2014.
|
||||||
|
|
||||||
- ?????, ?????, ??С??. ???????????[M]. ???????????????????, 2001.
|
- 汤子瀛, 哲凤屏, 汤小丹. 计算机操作系统[M]. 西安电子科技大学出版社, 2001.
|
||||||
|
|
||||||
- Bryant, R. E., & O??Hallaron, D. R. (2004). ?????????????.
|
- Bryant, R. E., & O’Hallaron, D. R. (2004). 深入理解计算机系统.
|
||||||
|
|
||||||
- [С???????????????](http://wdxtub.com/interview/index.html)
|
- [小土刀的面试刷题笔记](http://wdxtub.com/interview/index.html)
|
||||||
|
|
||||||
- [??????????????](http://blog.csdn.net/yufaw/article/details/7409596)
|
- [进程间的几种通信方式](http://blog.csdn.net/yufaw/article/details/7409596)
|
||||||
|
|
804
notes/计算机网络.md
804
notes/计算机网络.md
File diff suppressed because it is too large
Load Diff
420
notes/设计模式.md
420
notes/设计模式.md
|
@ -1,74 +1,74 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [?? 1 ?? ?????????](#??-1-??-?????????)
|
* [第 1 章 设计模式入门](#第-1-章-设计模式入门)
|
||||||
* [?? 2 ?? ???????](#??-2-??-???????)
|
* [第 2 章 观察者模式](#第-2-章-观察者模式)
|
||||||
* [?? 3 ?? ?????](#??-3-??-?????)
|
* [第 3 章 装饰模式](#第-3-章-装饰模式)
|
||||||
* [?? 4 ?? ??????](#??-4-??-??????)
|
* [第 4 章 工厂模式](#第-4-章-工厂模式)
|
||||||
* [4.1 ?????](#41-?????)
|
* [4.1 简单工厂](#41-简单工厂)
|
||||||
* [4.2 ??????????](#42-??????????)
|
* [4.2 工厂方法模式](#42-工厂方法模式)
|
||||||
* [4.3 ???????](#43-???????)
|
* [4.3 抽象工厂模式](#43-抽象工厂模式)
|
||||||
* [?? 5 ?? ??????](#??-5-??-??????)
|
* [第 5 章 单件模式](#第-5-章-单件模式)
|
||||||
* [?? 6 ?? ??????](#??-6-??-??????)
|
* [第 6 章 命令模式](#第-6-章-命令模式)
|
||||||
* [?? 7 ?? ???????????????](#??-7-??-???????????????)
|
* [第 7 章 适配器模式与外观模式](#第-7-章-适配器模式与外观模式)
|
||||||
* [7.1 ????????](#71-????????)
|
* [7.1 适配器模式](#71-适配器模式)
|
||||||
* [7.2 ?????](#72-?????)
|
* [7.2 外观模式](#72-外观模式)
|
||||||
* [?? 8 ?? ??毰????](#??-8-??-??毰????)
|
* [第 8 章 模板方法模式](#第-8-章-模板方法模式)
|
||||||
* [?? 9 ?? ?????????????](#??-9-??-?????????????)
|
* [第 9 章 迭代器和组合模式](#第-9-章-迭代器和组合模式)
|
||||||
* [9.1 ????????](#91-????????)
|
* [9.1 迭代器模式](#91-迭代器模式)
|
||||||
* [9.2 Java ??????????](#92-java-??????????)
|
* [9.2 Java 内置的迭代器](#92-java-内置的迭代器)
|
||||||
* [9.3 ?????](#93-?????)
|
* [9.3 组合模式](#93-组合模式)
|
||||||
* [?? 10 ?? ????](#??-10-??-????)
|
* [第 10 章 状态模式](#第-10-章-状态模式)
|
||||||
* [?? 11 ?? ?????? // TODO](#??-11-??-??????--todo)
|
* [第 11 章 代理模式 // TODO](#第-11-章-代理模式--todo)
|
||||||
* [?? 12 ?? ??????](#??-12-??-??????)
|
* [第 12 章 复合模式](#第-12-章-复合模式)
|
||||||
* [12.1 MVC](#121-mvc)
|
* [12.1 MVC](#121-mvc)
|
||||||
* [12.1.1 ??? MVC](#1211-???-mvc)
|
* [12.1.1 传统 MVC](#1211-传统-mvc)
|
||||||
* [12.1.2 Web ?快? MVC](#1212-web-?快?-mvc)
|
* [12.1.2 Web 中的 MVC](#1212-web-中的-mvc)
|
||||||
* [?? 13 ?? ?????????](#??-13-??-?????????)
|
* [第 13 章 与设计模式相处](#第-13-章-与设计模式相处)
|
||||||
* [?? 14 ?? ?????? // TODO](#??-14-??-??????--todo)
|
* [第 14 章 剩下的模式 // TODO](#第-14-章-剩下的模式--todo)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ?? 1 ?? ?????????
|
# 第 1 章 设计模式入门
|
||||||
|
|
||||||
**1. ?????????**
|
**1. 设计模式概念**
|
||||||
|
|
||||||
?????????????????????????????????快?????????????????坆?芍?
|
设计模式不是代码,而是解决问题的方案,学习现有的设计模式可以做到经验复用。
|
||||||
|
|
||||||
????????????????????????????????????????????????????
|
拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。
|
||||||
|
|
||||||
**2. ????????**
|
**2. 问题描述**
|
||||||
|
|
||||||
???????????????志???????????戒????
|
设计不同种类的鸭子拥有不同的叫声和飞行方式。
|
||||||
|
|
||||||
**3. ????????**
|
**3. 简单实现方案**
|
||||||
|
|
||||||
??邦?快?????????????????????????????????????????????????????戒????????????????????
|
使用继承的解决方案如下,这种方案代码无法复用,如果两个鸭子类拥有同样的飞行方式,就有两份重复的代码。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/144d28a0-1dc5-4aba-8961-ced5bc88428a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/144d28a0-1dc5-4aba-8961-ced5bc88428a.jpg)
|
||||||
|
|
||||||
**4. ??????**
|
**4. 设计原则**
|
||||||
|
|
||||||
**????<3F>**??????<3F>???????抗???快?????????
|
**封装变化**在这里变化的是鸭子叫和飞行的行为方式。
|
||||||
|
|
||||||
**??????????????????????** ?????????????????????????????????????????快????????????????????????????????????????????????????????????????
|
**针对接口编程,而不是针对实现编程** 变量声明的类型为父类,而不是具体的某个子类。父类中的方法实现不在父类,而是在各个子类。程序在运行时可以动态改变变量所指向的子类类型。
|
||||||
|
|
||||||
????????????抗???快???????????????????????抗???快???????????????????抗???戒????
|
运用这一原则,将叫和飞行的行为抽象出来,实现多种不同的叫和飞行的子类,让子类去实现具体的叫和飞行方式。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1c8ccf5c-7ecd-4b8a-b160-3f72a510ce26.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1c8ccf5c-7ecd-4b8a-b160-3f72a510ce26.png)
|
||||||
|
|
||||||
**???????????邦??** ???????? has-a ????????????????????????????????????????侳???????????????????阱?????抉??????????宏??????????????????????????
|
**多用组合,少用继承** 组合也就是 has-a 关系,通过组合,可以在运行时动态改变实现,只要通过改变父类对象具体指向哪个子类即可。而继承就不能做到这些,继承体系在创建类时就已经确定。
|
||||||
|
|
||||||
???????????? Duck ??????? FlyBehavior ?? QuackBehavior ??performQuack() ?? performFly() ??????我???????????????????????????? Duck ??????????????????? FlyBehavior ?? QuackBehavior ???????????????????????我??
|
运用这一原则,在 Duck 类中组合 FlyBehavior 和 QuackBehavior 类,performQuack() 和 performFly() 方法委托给这两个类去处理。通过这种方式,一个 Duck 子类可以根据需要去实例化 FlyBehavior 和 QuackBehavior 的子类对象,并且也可以动态地进行改变。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29574e6f-295c-444e-83c7-b162e8a73a83.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29574e6f-295c-444e-83c7-b162e8a73a83.jpg)
|
||||||
|
|
||||||
**5. ????????**
|
**5. 整体设计图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e13833c8-e215-462e-855c-1d362bb8d4a0.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e13833c8-e215-462e-855c-1d362bb8d4a0.jpg)
|
||||||
|
|
||||||
**6. ??????**
|
**6. 模式定义**
|
||||||
|
|
||||||
**??????** ???????????<3F>???????????????????????????䣺????????????<3F>?????????????????
|
**策略模式** :定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
|
||||||
|
|
||||||
**7. ??????**
|
**7. 实现代码**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public abstract class Duck {
|
public abstract class Duck {
|
||||||
|
@ -164,42 +164,42 @@ public class MiniDuckSimulator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
??扶??
|
执行结果
|
||||||
```html
|
```html
|
||||||
QuackBehavior.Quack
|
QuackBehavior.Quack
|
||||||
FlyBehavior.FlyWithWings
|
FlyBehavior.FlyWithWings
|
||||||
FlyBehavior.FlyNoWay
|
FlyBehavior.FlyNoWay
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 2 ?? ???????
|
# 第 2 章 观察者模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????????Subject??????????????????????????Observer???????????
|
定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。主题(Subject)是被观察的对象,而其所有依赖者(Observer)成为观察者。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/26cb5e7e-6fa3-44ad-854e-fe24d1a5278c.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/26cb5e7e-6fa3-44ad-854e-fe24d1a5278c.jpg)
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
?????抉??????????????????????????????????????????????????????忌????????宏???????
|
主题中具有注册和移除观察者,并通知所有注册者的功能,主题是通过维护一张观察者列表来实现这些操作的。
|
||||||
|
|
||||||
?????????????????????????????????????????????????孝??????????????????????????????
|
观察者拥有一个主题对象的引用,因为注册、移除还有数据都在主题当中,必须通过操作主题才能完成相应功能。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5c558190-fccd-4b5e-98ed-1896653fc97f.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5c558190-fccd-4b5e-98ed-1896653fc97f.jpg)
|
||||||
|
|
||||||
**3. ????????**
|
**3. 问题描述**
|
||||||
|
|
||||||
???????????????????????????????????????????????忪???????????????????????
|
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/760a5d63-d96d-4dd9-bf9a-c3d126b2f401.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/760a5d63-d96d-4dd9-bf9a-c3d126b2f401.jpg)
|
||||||
|
|
||||||
**5. ??????**
|
**5. 设计原则**
|
||||||
|
|
||||||
**?????????????????????????** ????????????????????????????????????????????????????????????????????????眕????????????????????快??????????<3F>??
|
**为交互对象之间的松耦合设计而努力** 当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。由于松耦合的两个对象之间互相依赖程度很低,因此系统具有弹性,能够应对变化。
|
||||||
|
|
||||||
**6. ??????**
|
**6. 实现代码**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Subject {
|
public interface Subject {
|
||||||
|
@ -297,7 +297,7 @@ public class WeatherStation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
??扶??
|
执行结果
|
||||||
```html
|
```html
|
||||||
CurrentConditionsDisplay.update:0.0 0.0 0.0
|
CurrentConditionsDisplay.update:0.0 0.0 0.0
|
||||||
StatisticsDisplay.update:0.0 0.0 0.0
|
StatisticsDisplay.update:0.0 0.0 0.0
|
||||||
|
@ -305,39 +305,39 @@ CurrentConditionsDisplay.update:1.0 1.0 1.0
|
||||||
StatisticsDisplay.update:1.0 1.0 1.0
|
StatisticsDisplay.update:1.0 1.0 1.0
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 3 ?? ?????
|
# 第 3 章 装饰模式
|
||||||
|
|
||||||
**1. ????????**
|
**1. 问题描述**
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????
|
设计不同种类的饮料,并且每种饮料可以动态添加新的材料,比如可以添加牛奶。计算一种饮料的价格。
|
||||||
|
|
||||||
**2. ??????**
|
**2. 模式定义**
|
||||||
|
|
||||||
?????????牟??????????????????????????????????我??快?????????????
|
动态地将责任附加到对象上。在扩展功能上,装饰者提供了比继承更有弹性的替代方案。
|
||||||
|
|
||||||
????? DarkRoast ???? Mocha ??????Mocha ??????? Whip ??????????????????????????????? cost() ????????????????? cost() ??????????????????? cost() ???????????????? DarkRoast ????? Mocha??????????? Mocha ???? DarkRoast?????????? Whip ?????? Whip ???? Mocha???????? cost() ?????????????????????????
|
下图中 DarkRoast 对象被 Mocha 包裹,Mocha 对象又被 Whip 包裹,并且他们都继承自相同父类,都有 cost() 方法,但是外层对象的 cost() 方法实现调用了内层对象的 cost() 方法。因此,如果要在 DarkRoast 上添加 Mocha,那么只需要用 Mocha 包裹 DarkRoast,如果还需要 Whip ,就用 Whip 包裹 Mocha,最后调用 cost() 方法能把三种对象的价格都包含进去。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/41a4cb30-f393-4b3b-abe4-9941ccf8fa1f.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/41a4cb30-f393-4b3b-abe4-9941ccf8fa1f.jpg)
|
||||||
|
|
||||||
**3. ?????**
|
**3. 模式类图**
|
||||||
|
|
||||||
??????????????????????????????抉?????????????????????????????????????????????????????????????????????????????????????????糸??曳?????????????????????汍??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????汕?汍??????????抉??????????????????????我??????????????
|
装饰者和具体组件都继承自组件类型,其中具体组件的方法实现不需要依赖于其它对象,而装饰者拥有一个组件类型对象,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰的对象之外,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件有直接实现而不需要委托给其它对象去处理。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/3dc454fb-efd4-4eb8-afde-785b2182caeb.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/3dc454fb-efd4-4eb8-afde-785b2182caeb.jpg)
|
||||||
|
|
||||||
**4. ???????????????**
|
**4. 问题解决方案的类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9c997ac5-c8a7-44fe-bf45-2c10eb773e53.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9c997ac5-c8a7-44fe-bf45-2c10eb773e53.jpg)
|
||||||
|
|
||||||
**5. ??????**
|
**5. 设计原则**
|
||||||
|
|
||||||
**??????????????????????**???????????????????????????????????我??????????????????????????????????????????????????????????????????????????????????????????????????????????????扭??????????
|
**类应该对扩展开放,对修改关闭。**也就是添加新功能时不需要修改代码。在本章问题中该原则体现在,在饮料中添加新的材料,而不需要去修改饮料的代码。观察则模式也符合这个原则。不可能所有类都能实现这个原则,应当把该原则应用于设计中最有可能改变的地方。
|
||||||
|
|
||||||
**6. Java I/O ?快????????**
|
**6. Java I/O 中的装饰者模式**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2a40042a-03c8-4556-ad1f-72d89f8c555c.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2a40042a-03c8-4556-ad1f-72d89f8c555c.jpg)
|
||||||
|
|
||||||
**7. ???????**
|
**7. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Beverage {
|
public interface Beverage {
|
||||||
|
@ -402,32 +402,32 @@ public class StartbuzzCoffee {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???
|
输出
|
||||||
|
|
||||||
```html
|
```html
|
||||||
3.0
|
3.0
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 4 ?? ??????
|
# 第 4 章 工厂模式
|
||||||
|
|
||||||
## 4.1 ?????
|
## 4.1 简单工厂
|
||||||
|
|
||||||
**1. ????????**
|
**1. 问题描述**
|
||||||
|
|
||||||
?志???? Pizza??????????????辰???????????????? Pizza ????
|
有不同的 Pizza,根据不同的情况用不同的子类实例化一个 Pizza 对象。
|
||||||
|
|
||||||
**2. ????**
|
**2. 定义**
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????孝??迄????????????????????????????????????????????????????????????????????????????????宏????????????????????????????????忪???????????邦????????????快????????????????????????????????????????????????????快?????????????
|
简单工厂不是设计模式,更像是一种编程习惯。在实例化一个超类的对象时,可以用它的所有子类来进行实例化,要根据具体需求来决定使用哪个子类。在这种情况下,把实例化的操作放到工厂来中,让工厂类来决定应该用哪个子类来实例化。这样做把客户对象和具体子类的实现解耦,客户对象不再需要知道有哪些子类以及实例化哪个子类。因为客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节,一旦子类发生改变,例如增加子类,那么所有的客户类都要发生改变。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c470eb9b-fb05-45c5-8bb7-1057dc3c16de.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c470eb9b-fb05-45c5-8bb7-1057dc3c16de.jpg)
|
||||||
|
|
||||||
**3. ??????????**
|
**3. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dc3e704c-7c57-42b8-93ea-ddd068665964.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dc3e704c-7c57-42b8-93ea-ddd068665964.jpg)
|
||||||
|
|
||||||
|
|
||||||
**4. ???????**
|
**4. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Pizza {
|
public interface Pizza {
|
||||||
|
@ -473,33 +473,33 @@ public class PizzaStore {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???扶??
|
运行结果
|
||||||
|
|
||||||
```java
|
```java
|
||||||
CheesePizza
|
CheesePizza
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4.2 ??????????
|
## 4.2 工厂方法模式
|
||||||
|
|
||||||
**1. ????????**
|
**1. 问题描述**
|
||||||
|
|
||||||
????????? Pizza ???????????????????????????汎?????????????????縺?????????????? cheese ????? Pizza ?????????????????? Pizza ???????
|
每个地区的 Pizza 店虽然种类相同,但是都有自己的风味,需要单独区分。例如,一个客户点了纽约的 cheese 种类的 Pizza 和在芝加哥点的相同种类的 Pizza 是不同的。
|
||||||
|
|
||||||
**2. ??????**
|
**2. 模式定义**
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????
|
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
|
||||||
|
|
||||||
**3. ?????**
|
**3. 模式类图**
|
||||||
|
|
||||||
???????孝???????????????????????????????孝???????????????????????????????????????????????????????????????????????????????????????????忱????????????????????????????????????????????????????????????????????
|
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。工厂方法常用在在每个子类都有自己的一组产品类。可以为每个子类创建单独的简单工厂,但是把简单工厂中创建对象的代码放到子类中来可以减少类的数目,因为子类不算是产品类,因此完全可以这么做。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/903093ec-acc8-4f9b-bf2c-b990b9a5390c.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/903093ec-acc8-4f9b-bf2c-b990b9a5390c.jpg)
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/664f8901-5dc7-4644-a072-dad88cc5133a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/664f8901-5dc7-4644-a072-dad88cc5133a.jpg)
|
||||||
|
|
||||||
**5. ???????**
|
**5. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Pizza {
|
public interface Pizza {
|
||||||
|
@ -588,36 +588,36 @@ public class PizzaTestDrive {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???扶??
|
运行结果
|
||||||
|
|
||||||
```html
|
```html
|
||||||
NYStyleCheesePizza is making..
|
NYStyleCheesePizza is making..
|
||||||
ChicagoStyleCheesePizza is making..
|
ChicagoStyleCheesePizza is making..
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4.3 ???????
|
## 4.3 抽象工厂模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 设计原则**
|
||||||
|
|
||||||
**???????????**??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????縺????? PizzaStore ???????????????????????????? Pizza ?????????????????? Pizza ?????????????????迄??? Pizza ????????????
|
**依赖倒置原则**:要依赖抽象,不要依赖具体类。听起来像是针对接口编程,不针对实现编程,但是这个原则说明了:不能让高层组件依赖底层组件,而且,不管高层或底层组件,两者都应该依赖于抽象。例如,下图中 PizzaStore 属于高层组件,但是它依赖于底层组件 Pizza 的具体类。如果依赖的是 Pizza 的抽象类,那么就可以不用关心 Pizza 的具体实现细节。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ddf72ca9-c0be-49d7-ab81-57a99a974c8e.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ddf72ca9-c0be-49d7-ab81-57a99a974c8e.jpg)
|
||||||
|
|
||||||
**2. ??????**
|
**2. 模式定义**
|
||||||
|
|
||||||
???????????????????????????????<3F>???????????????????
|
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
|
||||||
|
|
||||||
**3. ?????**
|
**3. 模式类图**
|
||||||
|
|
||||||
????????????????????<3F>???????????????????????????宏??????????????????????????????????????????????????????????????????抗?????????????????????????????????????????????????AbstractFactory ?快? CreateProductA ?? CreateProductB ????????????????????????????????????????????????????????????????????备?????????????????????????? Client ?????Client ???? AbstractFactory ????????????????????????????????????????????????抗?????????Client ??????????????尿??????????????????????????????????????? Cilent ????? AbstractFactory ????????????????妊?
|
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。并且,抽象工厂模式也用到了工厂模式来创建单一对象,在类图左部,AbstractFactory 中的 CreateProductA 和 CreateProductB 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义。至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要这两个对象的协作才能完成任务。从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory ,而工厂模式使用了继承。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d301774f-e0d2-41f3-95f4-bfe39859b52e.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d301774f-e0d2-41f3-95f4-bfe39859b52e.jpg)
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8785dabd-1285-4bd0-b3aa-b05cc060a24a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8785dabd-1285-4bd0-b3aa-b05cc060a24a.jpg)
|
||||||
|
|
||||||
**5. ???????**
|
**5. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Dough {
|
public interface Dough {
|
||||||
|
@ -719,28 +719,28 @@ public class NYPizzaStoreTestDrive {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???扶??
|
运行结果
|
||||||
|
|
||||||
```html
|
```html
|
||||||
ThickCrustDough
|
ThickCrustDough
|
||||||
MarinaraSauce
|
MarinaraSauce
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 5 ?? ??????
|
# 第 5 章 单件模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
???????????????????????????????????
|
确保一个类只有一个实例,并提供了一个全局访问点。
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
???????? Java ??????????抄????????????抉???????????????抉?????????迆?????????忌????????????????迆?????????????????朵?????抉????????
|
单件模式的 Java 实现用一个私有构造器、一个私有静态变量以及一个公有静态函数,该函数返回私有变量,使得所有通过该函数获取的对象都指向这个唯一的私有静态变量。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/59aff6c1-8bc5-48e4-9e9c-082baeb2f274.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/59aff6c1-8bc5-48e4-9e9c-082baeb2f274.jpg)
|
||||||
|
|
||||||
**3. ???????**
|
**3. 经典实现**
|
||||||
|
|
||||||
????????孝???抉???????????????????????????????????????????????????????????抉??????????????????????????????????????????????????????????????? if(uniqueInstance == null) ??????<3F>????????????? uniqueInstance ??抉????????
|
以下实现中,私有静态变量被延迟化实例化,这样做的好处是,如果没有用到该类,那么就不会创建该私有静态变量,从而节约资源。这个实现在多线程环境下是不安全的,因为多个线程能够同时进入 if(uniqueInstance == null) 内的语句块,那么就会多次实例化 uniqueInstance 私有静态变量。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Singleton {
|
public class Singleton {
|
||||||
|
@ -759,9 +759,9 @@ public class Singleton {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**4. ???????????????????**
|
**4. 线程不安全问题的解决方案一**
|
||||||
|
|
||||||
?????? getUniqueInstance() ????????????????¯????????????????????????????? uniqueInstance ???????忪?????????????????????????????????????????????????????????????????
|
只需要对 getUniqueInstance() 方法加锁,就能让该方法一次只能一个线程访问,从而避免了对 uniqueInstance 变量进行多次实例化的问题。但是这样有一个问题是一次只能一个线程进入,性能上会有一定的浪费。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public static synchronized Singleton getUniqueInstance() {
|
public static synchronized Singleton getUniqueInstance() {
|
||||||
|
@ -772,17 +772,17 @@ public class Singleton {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**5. ????????????????????**
|
**5. 线程不安全问题的解决方案二**
|
||||||
|
|
||||||
????????????????????????????
|
不用延迟实例化,采用直接实例化。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private static Singleton uniqueInstance = new Singleton();
|
private static Singleton uniqueInstance = new Singleton();
|
||||||
```
|
```
|
||||||
|
|
||||||
**6. ????????????????????**
|
**6. 线程不安全问题的解决方案三**
|
||||||
|
|
||||||
????????????????????????? getUniqueInstance() ???????技?????????????????? uniqueInstance = new Singleton(); ?????????????阱??????????????????忪? uniqueInstance ???????????????????????????????????
|
考虑第一个解决方案,它是直接对 getUniqueInstance() 方法进行加锁,而实际上只需要对 uniqueInstance = new Singleton(); 这条语句加锁即可。使用两个条件语句来判断 uniqueInstance 是否已经实例化,如果没有实例化才需要加锁。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Singleton {
|
public class Singleton {
|
||||||
|
@ -805,31 +805,31 @@ public class Singleton {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 6 ?? ??????
|
# 第 6 章 命令模式
|
||||||
|
|
||||||
**1. ????????**
|
**1. 问题描述**
|
||||||
|
|
||||||
????????????????抗??????????????????????????????????????????????戒??????縺????????????<3F>
|
设计一个遥控器,它有很多按钮,每个按钮可以发起一个命令,让一个家电完成相应操作。有非常多的家电,并且也会增加家电。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7b8f0d8e-a4fa-4c9d-b9a0-3e6a11cb3e33.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7b8f0d8e-a4fa-4c9d-b9a0-3e6a11cb3e33.jpg)
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c3ca36b2-8459-4cf1-98b0-cc95a0e94f20.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c3ca36b2-8459-4cf1-98b0-cc95a0e94f20.jpg)
|
||||||
|
|
||||||
**2. ??????**
|
**2. 模式定义**
|
||||||
|
|
||||||
??????????????????辰????????????????????????
|
将命令封装成对象,以便使用不同的命令来参数化其它对象。
|
||||||
|
|
||||||
**3. ?????**
|
**3. 模式类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1e09d75f-6268-4425-acf8-8ecd1b4a0ef3.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1e09d75f-6268-4425-acf8-8ecd1b4a0ef3.jpg)
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
Invoker ?????????????????????????????????????? execute() ??????Receiver ???????????????????????ConcreteCommand ?????????? Receiver ??????????????我? Receiver ??????????????? LightOnCommand ????? excute ??????我? Light ??????????Light ??????????? on() ??????????????Invoker ???? Client ??????????????????????? Invoker ?????????????????? Client ????????????宏??????
|
Invoker 是遥控器,它可以设置命令,并且调用命令对象的 execute() 方法。Receiver 是电灯,是命令真正的执行者。ConcreteCommand 类组合了一个 Receiver 对象,命令的执行委托给 Receiver 对象来处理,也就是 LightOnCommand 命令的 excute 方法委托给 Light 对象来处理,Light 对象通过调用 on() 方法来完成操作。Invoker 不是 Client 对象,是因为命令的创建不是在 Invoker 中完成的,因此需要额外的 Client 对象来处理这些操作。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ef94f62-98ce-464d-a646-842d9c72c8b8.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ef94f62-98ce-464d-a646-842d9c72c8b8.jpg)
|
||||||
|
|
||||||
**5. ???????**
|
**5. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Command {
|
public interface Command {
|
||||||
|
@ -864,7 +864,7 @@ public class LightOnCommand implements Command{
|
||||||
```
|
```
|
||||||
```java
|
```java
|
||||||
/**
|
/**
|
||||||
* ???????
|
* 遥控器类
|
||||||
*/
|
*/
|
||||||
public class SimpleRemoteControl {
|
public class SimpleRemoteControl {
|
||||||
Command slot;
|
Command slot;
|
||||||
|
@ -895,39 +895,39 @@ public class RemoteLoader {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???
|
输出
|
||||||
|
|
||||||
```html
|
```html
|
||||||
Light is on!
|
Light is on!
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 7 ?? ???????????????
|
# 第 7 章 适配器模式与外观模式
|
||||||
|
|
||||||
## 7.1 ????????
|
## 7.1 适配器模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????
|
将一个类的接口,转换为客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8e8ba824-7a9e-4934-a212-e6a41dcc1602.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8e8ba824-7a9e-4934-a212-e6a41dcc1602.jpg)
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????Adapter??????????????????Adaptee???????????????????我??????????????????????孝?Adapter ??????? Target ?? Adaptee ?????????????? Adaptee ??????????????? Adapter ????????????? Target ?????????? Client ?????????????? Target ???????????
|
有两种适配器模式的实现,一种是对象方式,一种是类方式。对象方式是通过组合的方法,让适配器类(Adapter)拥有一个待适配的对象(Adaptee),从而把相应的处理委托给待适配的对象。类方式用到多重继承,Adapter 可以看成 Target 和 Adaptee 类型,先把它当成 Adaptee 类型然后实例化一个 Adapter 对象,再把它当成 Target 类型的,这样 Client 就可以把这个对象当成 Target 的对象来处理。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/253bd869-ea48-4092-9aed-6906ccb2f3b0.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/253bd869-ea48-4092-9aed-6906ccb2f3b0.jpg)
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a797959a-0ed5-475b-8d97-df157c672019.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a797959a-0ed5-475b-8d97-df157c672019.jpg)
|
||||||
|
|
||||||
**3. ????????**
|
**3. 问题描述**
|
||||||
|
|
||||||
??????Duck????????Turkey????Duck ?? quack() ???????? Turkey ??? gobble() ?????????????? Turkey ??? Duck ?? quack() ??????
|
让鸭子(Duck)适配火鸡(Turkey),Duck 有 quack() 方法,而 Turkey 只有 gobble() 方法。也就是要让 Turkey 也有 Duck 的 quack() 方法。
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1a511c76-bb6b-40ab-b8aa-39eeb619d673.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1a511c76-bb6b-40ab-b8aa-39eeb619d673.jpg)
|
||||||
|
|
||||||
**5. ???????**
|
**5. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface Duck {
|
public interface Duck {
|
||||||
|
@ -984,69 +984,69 @@ public class DuckTestDrive {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???扶??
|
运行结果
|
||||||
```html
|
```html
|
||||||
gobble!
|
gobble!
|
||||||
fly!
|
fly!
|
||||||
```
|
```
|
||||||
|
|
||||||
## 7.2 ?????
|
## 7.2 外观模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
???????????????????????????快??????????????????????????????????????芍?
|
提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/78f2314e-2643-41df-8f3d-b7e28294094b.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/78f2314e-2643-41df-8f3d-b7e28294094b.jpg)
|
||||||
|
|
||||||
**3. ????????**
|
**3. 问题描述**
|
||||||
|
|
||||||
???????????????????????抄???????????????????志???????????宏????????邦???????????????????????????????????????????????????????
|
家庭影院中有众多电器,当要进行观看电影时需要对很多电器进行操作。要求简化这些操作,使得家庭影院类只提供一个简化的接口,例如提供一个看电影的接口而不用具体操作众多电器。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/106f5585-b2e7-4718-be5d-3b322d1ef42a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/106f5585-b2e7-4718-be5d-3b322d1ef42a.jpg)
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25387681-89f8-4365-a2fa-83b86449ee84.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25387681-89f8-4365-a2fa-83b86449ee84.jpg)
|
||||||
|
|
||||||
**5. ??????**
|
**5. 设计原则**
|
||||||
|
|
||||||
**?????????**????????????????????????????????????????????????????????????
|
**最少知识原则**:只和你的密友谈话。也就是应当使得客户对象所需要交互的对象应当尽可能少。
|
||||||
|
|
||||||
# ?? 8 ?? ??毰????
|
# 第 8 章 模板方法模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
??????????忪??????????????????宏?????????????妊?
|
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。
|
||||||
|
|
||||||
??毰????????????????????????????????????????快??宏???畟
|
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
??毰?? templateMethod() ?????????????????? primitiveOperation1() ?? primitiveOperation2() ??????快????? primitiveOperation1() ?? primitiveOperation2() ???????????????
|
模板方法 templateMethod() 定义了算法的骨架,确定了 primitiveOperation1() 和 primitiveOperation2() 方法执行的顺序,而 primitiveOperation1() 和 primitiveOperation2() 让子类去具体实现。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed62f400-192c-4185-899b-187958201f0c.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed62f400-192c-4185-899b-187958201f0c.jpg)
|
||||||
|
|
||||||
**3. ????????**
|
**3. 问题描述**
|
||||||
|
|
||||||
?蚡????劘?????????????????宏??????快??????
|
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d8f873fc-00bc-41ee-a87c-c1b4c0172844.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d8f873fc-00bc-41ee-a87c-c1b4c0172844.png)
|
||||||
|
|
||||||
**4. ??????????**
|
**4. 解决方案类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/aa20c123-b6b5-432a-83d3-45dc39172192.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/aa20c123-b6b5-432a-83d3-45dc39172192.jpg)
|
||||||
|
|
||||||
**5. ??????**
|
**5. 设计原则**
|
||||||
|
|
||||||
**?????????**??????????朝????????????????????朝??????????????????????????????????????????????????????????????????????????????毰?????????????我???????????????????????
|
**好莱坞原则**:别调用(打电话给)我们,我们会调用(打电话给)你。这一原则可以防止依赖腐败,即防止高层组件依赖底层组件,底层组件又依赖高层组件。该原则在模板方法的体现为,只有父类会调用子类,子类不会调用父类。
|
||||||
|
|
||||||
**6. ????**
|
**6. 钩子**
|
||||||
|
|
||||||
?????hock?????宏????????????扭??扭????????????????????????????????????????毰?? templteMethod() ?孝??????????????????????????????????????
|
钩子(hock):某些步骤在不同实现中可有可无,可以先定义一个什么都不做的方法,把它加到模板方法 templteMethod() 中,如果子类需要它就覆盖默认实现并加上自己的实现。
|
||||||
|
|
||||||
**7. ???????**
|
**7. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public abstract class CaffeineBeverage {
|
public abstract class CaffeineBeverage {
|
||||||
|
@ -1109,7 +1109,7 @@ public class CaffeineBeverageTestDrive {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
???扶??
|
运行结果
|
||||||
|
|
||||||
```html
|
```html
|
||||||
boilWater
|
boilWater
|
||||||
|
@ -1123,21 +1123,21 @@ pourInCup
|
||||||
Tea.addCondiments
|
Tea.addCondiments
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 9 ?? ?????????????
|
# 第 9 章 迭代器和组合模式
|
||||||
|
|
||||||
## 9.1 ????????
|
## 9.1 迭代器模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
?????????????????????快????????????????????????????????
|
提供一种顺序访问一个聚合对象中的各个元素的方法,而又不暴露其内部的表示。
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????????????????
|
客户类拥有一个聚合对象和迭代器对象,迭代器对象是聚合对象生成的。只需要迭代器定义好移动的操作,就可以让聚合对象能够顺序遍历。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/439deca7-fed0-4c89-87e5-7088d10f1fdb.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/439deca7-fed0-4c89-87e5-7088d10f1fdb.jpg)
|
||||||
|
|
||||||
**3. ???????**
|
**3. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Aggregate {
|
public class Aggregate {
|
||||||
|
@ -1195,7 +1195,7 @@ public class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
???扶??
|
运行结果
|
||||||
```html
|
```html
|
||||||
0
|
0
|
||||||
1
|
1
|
||||||
|
@ -1209,13 +1209,13 @@ public class Client {
|
||||||
9
|
9
|
||||||
```
|
```
|
||||||
|
|
||||||
## 9.2 Java ??????????
|
## 9.2 Java 内置的迭代器
|
||||||
|
|
||||||
**1. ?????**
|
**1. 实现接口**
|
||||||
|
|
||||||
Java ????????? Iterator ????????? Java ??????????????????? Iterable ????????????? iterator() ??????????? Iterator ??????? Java ??????????????????????????? foreach ????????????????快????????
|
Java 中已经有了 Iterator 接口,在使用 Java 实现时,需要让聚合对象实现 Iterable 接口,该接口有一个 iterator() 方法会返回一个 Iterator 对象。使用 Java 内置的迭代器实现,客户对象可以使用 foreach 循环来遍历聚合对象中的每个元素。
|
||||||
|
|
||||||
**2. ???????**
|
**2. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -1271,25 +1271,25 @@ public class Client {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 9.3 ?????
|
## 9.3 组合模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 设计原则**
|
||||||
|
|
||||||
????????????????????????
|
一个类应该只有一个引起改变的原因。
|
||||||
|
|
||||||
**2. ??????**
|
**2. 模式定义**
|
||||||
|
|
||||||
???????????????糸???????????? / ???????糸???
|
允许将对象组合成树形结构来表现“整体 / 部分”层次结构。
|
||||||
|
|
||||||
??????????????????????????????????????
|
组合能让客户以一致的方式处理个别对象以及对象组合。
|
||||||
|
|
||||||
**3. ?????**
|
**3. 模式类图**
|
||||||
|
|
||||||
????????Composite???????????????Component???????????????竹?????糸????技???????????????????????????????????????????????
|
由于组合(Composite)类拥有一个组件(Component)对象,因此组合对象位于树形结构的中间,它还可以继续操作这个组件对象,并忽略组件对象的具体类型。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f99c019e-7e91-4c2e-b94d-b031c402dcb5.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f99c019e-7e91-4c2e-b94d-b031c402dcb5.jpg)
|
||||||
|
|
||||||
**4. ???????**
|
**4. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public abstract class Component {
|
public abstract class Component {
|
||||||
|
@ -1316,7 +1316,7 @@ public class Leaf extends Component {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addChild(Component component) {
|
public void addChild(Component component) {
|
||||||
throw new UnsupportedOperationException(); // ???????????????????? , ??????????????????????????
|
throw new UnsupportedOperationException(); // 牺牲透明性换取单一职责原则 , 这样就不用考虑是叶子节点还是组合节点
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1378,7 +1378,7 @@ public class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
???扶??
|
运行结果
|
||||||
|
|
||||||
```html
|
```html
|
||||||
Composite:root
|
Composite:root
|
||||||
|
@ -1390,56 +1390,56 @@ Composite:root
|
||||||
--left:3
|
--left:3
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 10 ?? ????
|
# 第 10 章 状态模式
|
||||||
|
|
||||||
**1. ??????**
|
**1. 模式定义**
|
||||||
|
|
||||||
?????????????????????????????????????????????????????
|
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????縺????????????????????????????????????????????????扭???????????????????????快???????????????????????????????????????????????????????????????????????
|
状态模式的类图和策略模式一样,并且都是能够动态改变对象的行为。但是状态模式是通过状态对象的状态转移来改变客户对象组合的状态对象,而策略模式是通过客户对象本身的决策来改变组合的策略对象。例如,状态模式下,客户对象委托状态对象进行一个处理操作,那么状态对象有可能发生状态转移,使得客户对象拥有的状态对象发生改变。状态对象组合了客户对象,状态转移是状态对象通过改变客户对象所组合的状态对象实现的。
|
||||||
|
|
||||||
**2. ?????**
|
**2. 模式类图**
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c28fd93a-0d55-4a19-810f-72652feee00d.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c28fd93a-0d55-4a19-810f-72652feee00d.jpg)
|
||||||
|
|
||||||
**3. ????????**
|
**3. 问题描述**
|
||||||
|
|
||||||
?????????忪????????????????????志???????????????????????????????????????????
|
糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f7d880c9-740a-4a16-ac6d-be502281b4b2.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f7d880c9-740a-4a16-ac6d-be502281b4b2.jpg)
|
||||||
|
|
||||||
**4. ?????????**
|
**4. 直接解决方案**
|
||||||
|
|
||||||
???????????????????????秄?忪??????????????????????志????????????????????????????????????????快???????????????????????????????????????????????
|
在糖果机的每个操作函数里面,判断当前的状态,根据不同的状态进行不同的处理,并且发生不同的状态转移。这种解决方案把所有的实现细节都放到客户类,这样在新增状态的时候就要去修改客户类的代码。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62ebbb63-8fd7-4488-a866-76a9dc911662.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62ebbb63-8fd7-4488-a866-76a9dc911662.png)
|
||||||
|
|
||||||
**5. ???????????????**
|
**5. 使用状态模式的解决方案**
|
||||||
|
|
||||||
??????????????????秄???????????????????我???????????????????????????????????糸????????
|
状态的转移被移到状态类里面,客户类的每个操作只需要委托给状态类即可,而不需要知道当前是什么状态以及状态时如何进行转移的。
|
||||||
|
|
||||||
|
|
||||||
**6. ???????**
|
**6. 代码实现**
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public interface State {
|
public interface State {
|
||||||
/**
|
/**
|
||||||
* ???25 ???
|
* 投入25 分钱
|
||||||
*/
|
*/
|
||||||
void insertQuarter();
|
void insertQuarter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ???25 ???
|
* 退回25 分钱
|
||||||
*/
|
*/
|
||||||
void ejectQuarter();
|
void ejectQuarter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ???????
|
* 转动曲柄
|
||||||
*/
|
*/
|
||||||
void turnCrank();
|
void turnCrank();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ???????
|
* 发放糖果
|
||||||
*/
|
*/
|
||||||
void dispense();
|
void dispense();
|
||||||
}
|
}
|
||||||
|
@ -1667,7 +1667,7 @@ public class GumballMachineTestDrive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
???扶??
|
运行结果
|
||||||
```html
|
```html
|
||||||
You insert a quarter
|
You insert a quarter
|
||||||
You turned...
|
You turned...
|
||||||
|
@ -1696,34 +1696,34 @@ You turned, but there are no gumballs
|
||||||
No gumball dispensed
|
No gumball dispensed
|
||||||
```
|
```
|
||||||
|
|
||||||
# ?? 11 ?? ?????? // TODO
|
# 第 11 章 代理模式 // TODO
|
||||||
|
|
||||||
# ?? 12 ?? ??????
|
# 第 12 章 复合模式
|
||||||
|
|
||||||
## 12.1 MVC
|
## 12.1 MVC
|
||||||
|
|
||||||
### 12.1.1 ??? MVC
|
### 12.1.1 传统 MVC
|
||||||
|
|
||||||
???????????????????????????????????????????????
|
视图使用组合模式,模型使用了观察者模式,控制器使用了策略模式。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4f67611d-492f-4958-9fa0-4948010e345f.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4f67611d-492f-4958-9fa0-4948010e345f.jpg)
|
||||||
|
|
||||||
### 12.1.2 Web ?快? MVC
|
### 12.1.2 Web 中的 MVC
|
||||||
|
|
||||||
????????迄????????
|
模式不再使用观察者模式。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1dd56e61-2970-4d27-97c2-6e81cee86978.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1dd56e61-2970-4d27-97c2-6e81cee86978.jpg)
|
||||||
|
|
||||||
# ?? 13 ?? ?????????
|
# 第 13 章 与设计模式相处
|
||||||
|
|
||||||
???倃??? **??** ??????? **????** ????? **???????**??
|
定义:在某 **情境** 下,针对某 **问题** 的某种 **解决方案**。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????????
|
过度使用设计模式可能导致代码被过度工程化,应该总是用最简单的解决方案完成工作,并在真正需要模式的地方才使用它。
|
||||||
|
|
||||||
???????????????????????????????????????????笥??????宏?????????
|
反模式:不好的解决方案来解决一个问题。主要作用是为了警告不要使用这些解决方案。
|
||||||
|
|
||||||
??????
|
模式分类:
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/524a237c-ffd7-426f-99c2-929a6bf4c847.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/524a237c-ffd7-426f-99c2-929a6bf4c847.jpg)
|
||||||
|
|
||||||
# ?? 14 ?? ?????? // TODO
|
# 第 14 章 剩下的模式 // TODO
|
||||||
|
|
736
notes/重构.md
736
notes/重构.md
File diff suppressed because it is too large
Load Diff
224
notes/面向对象思想.md
224
notes/面向对象思想.md
|
@ -1,75 +1,75 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [S.O.L.I.D](#solid)
|
* [S.O.L.I.D](#solid)
|
||||||
* [1. ??????????](#1-??????????)
|
* [1. 单一责任原则](#1-单一责任原则)
|
||||||
* [2. ?????????](#2-?????????)
|
* [2. 开放封闭原则](#2-开放封闭原则)
|
||||||
* [3. ?????<3F>I???](#3-?????<3F>I???)
|
* [3. 里氏替换原则](#3-里氏替换原则)
|
||||||
* [4. ?????????](#4-?????????)
|
* [4. 接口分离原则](#4-接口分离原则)
|
||||||
* [5. ???????????](#5-???????????)
|
* [5. 依赖倒置原则](#5-依赖倒置原则)
|
||||||
* [???????§³????](#???????§ã????)
|
* [封装、继承、多态](#封装继承多态)
|
||||||
* [1. ???](#1-???)
|
* [1. 封装](#1-封装)
|
||||||
* [2. ???](#2-???)
|
* [2. 继承](#2-继承)
|
||||||
* [3. ???](#3-???)
|
* [3. 多态](#3-多态)
|
||||||
* [UML](#uml)
|
* [UML](#uml)
|
||||||
* [1. ???](#1-???)
|
* [1. 类图](#1-类图)
|
||||||
* [2. ????](#2-????)
|
* [2. 时序图](#2-时序图)
|
||||||
* [?¦Ï?????](#?¦Ï?????)
|
* [参考资料](#参考资料)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# S.O.L.I.D
|
# S.O.L.I.D
|
||||||
|
|
||||||
S.O.L.I.D???????????????(OOD&OOP)?§Þ?????????????(Programming Priciple)?????????§Õ??
|
S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写。
|
||||||
|
|
||||||
|??§Õ |?? |???????|
|
|简写 |全拼 |中文翻译|
|
||||||
| -- | -- | -- |
|
| -- | -- | -- |
|
||||||
|SRP| The Single Responsibility Principle |??????????|
|
|SRP| The Single Responsibility Principle |单一责任原则|
|
||||||
|OCP| The Open Closed Principle | ?????????|
|
|OCP| The Open Closed Principle | 开放封闭原则|
|
||||||
|LSP| The Liskov Substitution Principle |?????<3F>I???|
|
|LSP| The Liskov Substitution Principle |里氏替换原则|
|
||||||
|ISP| The Interface Segregation Principle |?????????|
|
|ISP| The Interface Segregation Principle |接口分离原则|
|
||||||
|DIP| The Dependency Inversion Principle |???????????|
|
|DIP| The Dependency Inversion Principle |依赖倒置原则|
|
||||||
|
|
||||||
|
|
||||||
## 1. ??????????
|
## 1. 单一责任原则
|
||||||
|
|
||||||
???????????????????????????????????Ñö?????????????????????????¦²????????????§Ö?????????????¦Å????????????????
|
当需要修改某个类的时候原因有且只有一个。换句话说就是让一个类只做一种类型责任,当这个类需要承当其他类型的责任的时候,就需要分解这个类。
|
||||||
|
|
||||||
## 2. ?????????
|
## 2. 开放封闭原则
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????
|
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
|
||||||
|
|
||||||
## 3. ?????<3F>I???
|
## 3. 里氏替换原则
|
||||||
|
|
||||||
????????????????????<3F>I?¦Ê??????????????????????? is-a ?????
|
当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有 is-a 关系。
|
||||||
|
|
||||||
## 4. ?????????
|
## 4. 接口分离原则
|
||||||
|
|
||||||
?????????????????§»???????????????Ñö??????????????????????????????¨¢?
|
不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口总要好。
|
||||||
|
|
||||||
## 5. ???????????
|
## 5. 依赖倒置原则
|
||||||
|
|
||||||
1. ?????öö?????????????ï…?????????????????
|
1. 高层模块不应该依赖于低层模块,二者都应该依赖于抽象
|
||||||
2. ????????????????????????????????
|
2. 抽象不应该依赖于细节,细节应该依赖于抽象
|
||||||
|
|
||||||
# ???????§³????
|
# 封装、继承、多态
|
||||||
|
|
||||||
???????§³???????????????????????
|
封装、继承、多态是面向对象的三大特性。
|
||||||
|
|
||||||
## 1. ???
|
## 1. 封装
|
||||||
|
|
||||||
???¨®??????????????????????????????????????<3F>q?????????????????ÈÉ??????????????????????????????????????????????????????§»????????????????????????????????????????????????????????????????????????????????
|
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户是无需知道对象内部的细节,但可以通过该对象对外的提供的接口来访问该对象。
|
||||||
|
|
||||||
?????????????
|
封装有三大好处:
|
||||||
|
|
||||||
1. ??????????????????
|
1. 良好的封装能够减少耦合。
|
||||||
|
|
||||||
2. ????????????????????
|
2. 类内部的结构可以自由修改。
|
||||||
|
|
||||||
3. ??????????§Ú??????????
|
3. 可以对成员进行更精确的控制。
|
||||||
|
|
||||||
4. ????????????????
|
4. 隐藏信息,实现细节。
|
||||||
|
|
||||||
???? Person ???? name??gender??age ???????????????? get() ?????????? Person ????? name ????? gender ????????????? age ????????? age ???????? work() ??????¨¢?
|
以下 Person 类封装 name、gender、age 等属性,外界只能通过 get() 方法获取一个 Person 对象的 name 属性和 gender 属性,而无法获取 age 属性,但是 age 属性可以供 work() 方法使用。
|
||||||
|
|
||||||
??? gender ??????? int ??????????§Õ›¥????????????????????????????????????????????????????????????????????????????????§³?
|
注意到 gender 属性使用 int 数据类型进行存储,封装使得用户注意不到这种实现细节。并且在需要修改使用的数据类型时,也可以在不影响客户端代码的情况下进行。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Person {
|
public class Person {
|
||||||
|
@ -95,25 +95,25 @@ public class Person {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. ???
|
## 2. 继承
|
||||||
|
|
||||||
???????? **is-a** ????????? Cat ?? Animal ??????? is-a ???????????? Cat ????? Animal???????? Animal ?? private ????????????
|
继承实现了 **is-a** 关系,例如 Cat 和 Animal 就是一种 is-a 关系,因此可以将 Cat 继承自 Animal,从而获得 Animal 非 private 的属性和方法。
|
||||||
|
|
||||||
Cat ??????? Animal ????????????????? Animal ???? Cat ?????????????????????? **???????**??
|
Cat 可以当做 Animal 来使用,也就是可以使用 Animal 引用 Cat 对象,这种子类转换为父类称为 **向上转型**。
|
||||||
|
|
||||||
??????????????<3F>I??????????????????????<3F>I?¦Ê??????????????????????? is-a ?????
|
继承应该遵循里氏替换原则:当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有 is-a 关系。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Animal animal = new Cat();
|
Animal animal = new Cat();
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. ???
|
## 3. 多态
|
||||||
|
|
||||||
???????????????????????????????????????????????????????????????§Ø???????????????????????????????????????
|
多态分为编译时多态和运行时多态。编译时多态主要指方法的重装,运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定。
|
||||||
|
|
||||||
???????????????1. ??§µ?2. ???????????3. ????????
|
多态有三个条件:1. 继承;2. 覆盖父类方法;3. 向上转型。
|
||||||
|
|
||||||
?????????§µ???????Instrument????????????Wind ?? Percussion????????????? play() ???????????? main() ???????????? Instrument ?????? Wind ?? Percussion ?????? Instrument ??????? play() ????????????????????????????? play() ???????????? Instrument ????????
|
下面的代码中,乐器类(Instrument)有两个子类:Wind 和 Percussion,它们都覆盖了 play() 方法,并且在 main() 方法中使用父类 Instrument 来引用 Wind 和 Percussion 对象。在 Instrument 引用调用 play() 方法时,会执行实际引用对象所在类的 play() 方法,而不是 Instrument 类的方法。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Instrument {
|
public class Instrument {
|
||||||
|
@ -151,157 +151,157 @@ public class Music {
|
||||||
|
|
||||||
# UML
|
# UML
|
||||||
|
|
||||||
## 1. ???
|
## 1. 类图
|
||||||
|
|
||||||
**1.1 ??????**
|
**1.1 继承相关**
|
||||||
|
|
||||||
????????????: ??????generalize????????realize????????? is-a ?????
|
继承有两种形式: 泛化(generalize)和实现(realize),表现为 is-a 关系。
|
||||||
|
|
||||||
?? ???????(generalization)
|
① 泛化关系(generalization)
|
||||||
|
|
||||||
????????§Þ??
|
从具体类中继承
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29badd92-109f-4f29-abb9-9857f5973928.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29badd92-109f-4f29-abb9-9857f5973928.png)
|
||||||
|
|
||||||
?? ?????(realize)
|
② 实现关系(realize)
|
||||||
|
|
||||||
?????????????§Þ??
|
从抽象类或者接口中继承
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4b16e1d3-3a60-472c-9756-2f31b1c48abe.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4b16e1d3-3a60-472c-9756-2f31b1c48abe.png)
|
||||||
|
|
||||||
**1.2 ????????**
|
**1.2 整体和部分**
|
||||||
|
|
||||||
?? ?????(aggregation)
|
① 聚合关系(aggregation)
|
||||||
|
|
||||||
??????????????????????????????????????????<3F>I????????????????????¡À?? B ?? A ????
|
表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。以下表示 B 由 A 组成:
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/34259bb8-ca3a-4872-8771-9e946782d9c3.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/34259bb8-ca3a-4872-8771-9e946782d9c3.png)
|
||||||
|
|
||||||
|
|
||||||
?? ?????(composition)
|
② 组合关系(composition)
|
||||||
|
|
||||||
??????????????????????????????????<3F>I??????????????????????ÀM??????????????????????????????????????????????????????????????????
|
和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7dda050d-ac35-4f47-9f51-18f18ed6fa9a.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7dda050d-ac35-4f47-9f51-18f18ed6fa9a.png)
|
||||||
|
|
||||||
**1.3 ?????**
|
**1.3 相互联系**
|
||||||
|
|
||||||
?? ???????(association)
|
① 关联关系(association)
|
||||||
|
|
||||||
???????????????§Û????????????????????????§Û??????????????????????????????????? 1 ?? 1????? 1?????????????????????????????????§µ???????????????????§µ?????§Ü??????????????????????????§µ??????????????????????????§á??????????????
|
表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4ccd294c-d6b2-421b-839e-d88336ff5fb7.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4ccd294c-d6b2-421b-839e-d88336ff5fb7.png)
|
||||||
|
|
||||||
?? ???????(dependency)
|
② 依赖关系(dependency)
|
||||||
|
|
||||||
???????????????, ??????????????§Û??????????????????????????????????????????????????????????????????
|
和关联关系不同的是, 依赖关系是在运行过程中起作用的。一般依赖作为类的构造器或者方法的参数传入。双向依赖时一种不好的设计。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/47ca2614-509f-476e-98fc-50ec9f9d43c0.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/47ca2614-509f-476e-98fc-50ec9f9d43c0.png)
|
||||||
|
|
||||||
|
|
||||||
## 2. ????
|
## 2. 时序图
|
||||||
|
|
||||||
**2.1 ????**
|
**2.1 定义**
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
时序图描述了对象之间传递消息的时间顺序,它用来表示用例的行为顺序。它的主要作用是通过对象间的交互来描述用例(注意是对象),从而寻找类的操作。
|
||||||
|
|
||||||
**2.2 ?????????**
|
**2.2 赤壁之战时序图**
|
||||||
|
|
||||||
????????????¡À???????????
|
从虚线从上往下表示时间的推进。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/80c5aff8-fc46-4810-aeaa-215b5c60a003.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/80c5aff8-fc46-4810-aeaa-215b5c60a003.png)
|
||||||
|
|
||||||
????????????????????????????????????
|
可见,通过时序图可以知道每个类具有以下操作:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
publc class ???? {
|
publc class 刘备 {
|
||||||
public void ??();
|
public void 应战();
|
||||||
}
|
}
|
||||||
|
|
||||||
publc class ???? {
|
publc class 孔明 {
|
||||||
public void ??????();
|
public void 拟定策略();
|
||||||
public void ???????();
|
public void 联合孙权();
|
||||||
private void ?Úˆ???();
|
private void 借东风火攻();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ???? {
|
public class 关羽 {
|
||||||
public void ?????G??();
|
public void 防守荊州();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ??? {
|
public class 张飞 {
|
||||||
public void ??????????();
|
public void 防守荆州前线();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ??? {
|
public class 孙权 {
|
||||||
public void ???????();
|
public void 领兵相助();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**2.3 ???????????????**
|
**2.3 活动图、时序图之间的关系**
|
||||||
|
|
||||||
?????????????????????????
|
活动图示从用户的角度来描述用例;
|
||||||
|
|
||||||
?????????????????????????????????????
|
时序图是从计算机的角度(对象间的交互)描述用例。
|
||||||
|
|
||||||
**2.4 ?????????????**
|
**2.4 类图与时序图的关系**
|
||||||
|
|
||||||
????????????????????????????????????
|
类图描述系统的静态结构,时序图描述系统的动态行为。
|
||||||
|
|
||||||
**2.5 ?????????**
|
**2.5 时序图的组成**
|
||||||
|
|
||||||
?? ????
|
① 对象
|
||||||
|
|
||||||
????????????
|
有三种表现形式
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25b8adad-2ef6-4f30-9012-c306b4e49897.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25b8adad-2ef6-4f30-9012-c306b4e49897.png)
|
||||||
|
|
||||||
????????????????????
|
在画图时,应该遵循以下原则:
|
||||||
|
|
||||||
1. ?????????????????????
|
1. 把交互频繁的对象尽可能地靠拢。
|
||||||
|
|
||||||
2. ????????????????????????????????????????????????
|
2. 把初始化整个交互活动的对象(有时是一个参与者)放置在最左边。
|
||||||
|
|
||||||
?? ??????
|
② 生命线
|
||||||
|
|
||||||
???????????????????????????????
|
生命线从对象的创建开始到对象销毁时终止
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b7b0eac6-e7ea-4fb6-8bfb-95fec6f235e2.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b7b0eac6-e7ea-4fb6-8bfb-95fec6f235e2.png)
|
||||||
|
|
||||||
?? ???
|
③ 消息
|
||||||
|
|
||||||
?????????????????????????????
|
对象之间的交互式通过发送消息来实现的。
|
||||||
|
|
||||||
?????4???????
|
消息有4种类型:
|
||||||
|
|
||||||
1\. ????????????????????
|
1\. 简单消息,不区分同步异步。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a13b62da-0fa8-4224-a615-4cadacc08871.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a13b62da-0fa8-4224-a615-4cadacc08871.png)
|
||||||
|
|
||||||
2\. ????????????????????????????????????
|
2\. 同步消息,发送消息之后需要暂停活动来等待回应。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/33821037-dc40-4266-901c-e5b38e618426.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/33821037-dc40-4266-901c-e5b38e618426.png)
|
||||||
|
|
||||||
3\. ?????????????????????????
|
3\. 异步消息,发送消息之后不需要等待。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dec6c6cc-1b5f-44ed-b8fd-464fcf849dac.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dec6c6cc-1b5f-44ed-b8fd-464fcf849dac.png)
|
||||||
|
|
||||||
4\. ??????????????
|
4\. 返回消息,可选。
|
||||||
|
|
||||||
?? ????
|
④ 激活
|
||||||
|
|
||||||
???????????????????????????????????????
|
生命线上的方框表示激活状态,其它时间处于休眠状态。
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6ab5de9b-1c1e-4118-b2c3-fb6c7ed7de6f.png)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6ab5de9b-1c1e-4118-b2c3-fb6c7ed7de6f.png)
|
||||||
|
|
||||||
|
|
||||||
# ?¦Ï?????
|
# 参考资料
|
||||||
|
|
||||||
- Java ??????
|
- Java 编程思想
|
||||||
|
|
||||||
- [???????????SOLID???](http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html)
|
- [面向对象设计的SOLID原则](http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html)
|
||||||
|
|
||||||
- [????UML?????????](http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#generalization)
|
- [看懂UML类图和时序图](http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#generalization)
|
||||||
|
|
||||||
- [UML??§³???????????????sequence diagram](http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html)
|
- [UML系列——时序图(顺序图)sequence diagram](http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html)
|
||||||
|
|
||||||
- [?????????????????------???????§³????](http://blog.csdn.net/jianyuerensheng/article/details/51602015)
|
- [面向对象编程三大特性------封装、继承、多态](http://blog.csdn.net/jianyuerensheng/article/details/51602015)
|
||||||
|
|
160
notes/黑客与画家.md
160
notes/黑客与画家.md
|
@ -1,135 +1,135 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [??????](#??????)
|
* [译者序](#译者序)
|
||||||
* [?????????????](#?????????????)
|
* [为什么书呆子不受欢迎](#为什么书呆子不受欢迎)
|
||||||
* [???????](#???????)
|
* [黑客与画家](#黑客与画家)
|
||||||
* [????????](#????????)
|
* [不能说的话](#不能说的话)
|
||||||
* [?????·](#?????·)
|
* [另一条路](#另一条路)
|
||||||
* [??????о?](#??????о?)
|
* [设计与研究](#设计与研究)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# ??????
|
# 译者序
|
||||||
|
|
||||||
?????????????????????
|
作者:美国互联网创业之父
|
||||||
|
|
||||||
??? hack ??????????????????Щ???????????? hacker??????????????????????桢?????????????????????????????????????????????????????á???????????????????Щ???????????
|
最开始 hack 指的是难题的解决办法,那些最能干的人被成为 hacker。黑客包含以下三个特点:好玩、高智商、探索精神。黑客的核心价值观:分享、开放、民主、计算机的自由使用、进步。因此黑客指的是那些专家级程序员。
|
||||||
|
|
||||||
?????????????????????????Щ???????????????????????????????????????????????????????????????????????????????á?
|
由于黑客常常入侵系统,因此被与那些破坏计算机系统的人联系起来。然而破坏计算机系统的人称为骇客,真正的黑客不这么做,反而是让世界变得更好。
|
||||||
|
|
||||||
# ?????????????
|
# 为什么书呆子不受欢迎
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????
|
作者认为,“书呆子”和“高智商”正相关,而“书呆子”和“受欢迎”负相关。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????????????????侫???????????????????????????????????????????????????????????????????????????????????????????
|
提出问题:既然书呆子智商高,那么为什么不想出受欢迎的方法?因为要想受欢迎,需要投入很大的时间精力去塑造个人魅力。而书呆子没有那么多的时间和精力,相比于受欢迎,他们更在乎其它更有趣的事,比如设计奇妙的火箭等。
|
||||||
|
|
||||||
????????????
|
欺负书呆子的原因:
|
||||||
|
|
||||||
- ?????????????????????????????ζ???????????????
|
- 青少年的孩子更加残忍,书呆子不受欢迎意味着被歧视和受欺负。
|
||||||
> 11 ???????С??????????????????????????????????? ??????????????С??????????????????????????о????????С??????????????ο???????仯?????? 11 ???????????????????????????????? ??????????п??????????????磬??????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????硣???????????????????????????????????????????????????硣?????????????????а????????? ??????????????????????????????????????ε?????????????????ú???档????????????????????????????????
|
> 11 岁以前,小孩的生活由家长主导,其他孩子的影响有限。 孩子们不是不关心小学里其他同学的想法,但是后者不具有决定性影响。小学毕业以后,这种情形开始发生变化。到了 11 岁左右,孩子们逐渐把家庭生活当作寻常事了。 他们在同伴中开辟了一个新的世界,并认为那个世界才是重要的,比家里的世界更重要。实际上,如果他们在家里与父母发生冲突, 反而能在那个新的世界中挣得面子,而他们也确实更在乎那个世界。但是,问题在于,孩子们自己创造出来的世界是一个非常原始的世界。青少年在心理上还没有摆脱儿童状态, 许多人都会残忍地对待他人。他们折磨书呆子的原因就像拔掉一条蜘蛛腿一样,觉得很好玩。在一个人产生良知之前,折磨就是一种娱乐。
|
||||||
|
|
||||||
- ???????????
|
- 为了凸显自己。
|
||||||
> ???κ??????????У???Щ????????????????????????????е???????????????????????????????????????????????????????е???????????????п????塣?????????????????????????????????????????????????????????????????????????????????????Щ??????м??
|
> 在任何社会等级制度中,那些对自己没自信的人就会通过虐待他们眼中的下等人来突显自己的身份。我已经意识到,正是因为这个原因,在美国社会中底层白人是对待黑人最残酷的群体。最受欢迎的孩子并不欺负书呆子,他们不需要靠踩在书呆子身上来垫高自己。大部分的欺负来自处于下一等级的学生,那些焦虑的中间层。
|
||||||
|
|
||||||
- ??????????????????
|
- 为了和受欢迎的人结成同盟。
|
||||||
> ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????й??????????????????????????????????????????????????п???
|
> 没有什么比一个共同的敌人更能使得人们团结起来了。这就好比一个政客,他想让选民忘记糟糕的国内局势,方法就是为国家找出一个敌人,哪怕敌人并不真的存在,他也可以创造一个出来。一群人在一起,挑出一个书呆子,居高临下地欺负他,就会把彼此联系起来。一起攻击一个外人,所有人因此就都成了自己人。这就是为什么最恶劣的以强凌弱的事件都与团体有关的原因。随便找一个书呆子,他都会告诉你,一群人的虐待比一个人的虐待残酷得多。
|
||||||
|
|
||||||
?У???????????鵱???????
|
学校老师的只是把教书当成工作。
|
||||||
> ?????У????????????????????????????????????????????????????????λ?á?????÷????ж????????????????????????????????????????
|
> 公立学校的老师很像监狱的狱卒。看管监狱的人主要关心的是犯人都待在自己应该待的位置。然后,让犯人有东西吃,尽可能不要发生斗殴和伤害事件,这就可以了。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????Щ???
|
到社会之后,书呆子会被友好对待,因为他们做的事能够产生更多的影响,而社会正需要这些影响。
|
||||||
|
|
||||||
?????????????У???????????????????????????????????У??????????????У????????????????????????????????????У???????????????
|
成年人把孩子在学校受苦受难归结为青春期的激素影响,但是实际上这是学校这种体制的问题,学校只是把孩子圈养起来,不让他们到处乱跑,然而学校内部存在着很多残忍。
|
||||||
|
|
||||||
????????????????????????????????
|
过去的孩子更早投入社会,也更能够真正学会本领。
|
||||||
> ?????????У????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????С????????????????????????????????????????????????????????????????ü??????????????????????????????????????????????????????????????????????????????????????????У?????δ??????????????????к??????
|
> 过去的社会中,青少年扮演着一个更积极的角色。工业化时代到来前,青少年都是某种形式的学徒,不是在某个作坊,就是在某个农庄,甚至在某艘军舰上。他们不会被扔到一旁,创造自己的小社会。他们是成年人社会的低级成员。以前的青少年似乎也更尊敬成年人,因为成年人都是看得见的专家,会传授他们所要学习的技能。如今的大多数青少年,对他们的家长在遥远的办公室所从事的工作几乎一无所知。他们看不到学校作业与未来走上社会后从事的工作有何联系。
|
||||||
|
|
||||||
?У??????????????????????????????????????????????????????????????????????????
|
学校的使命是教书育人,而并没有外界的压力去监督他们这么做,所以老师和学生双方往往都是敷衍了事。
|
||||||
|
|
||||||
??????????????????????????????????
|
没有外在的对手,孩子们就互相把对方当作对手。
|
||||||
|
|
||||||
?????????????????????????硰????
|
成年人贬低了很多美好的东西,比如“人格”。
|
||||||
> ???????????????????????????б????????????????????????????????????????????????????????????????????????????????硰????????????????????????????Щ???????????????Щ???????????????????????????????Щ????????????ν?????????????????????佱????????????????????????????????????????????????????????????????????????????????????????????
|
> 许多书呆子可能都与我一样,直到高中毕业多年后,才去读中学里的指定读物。但是,我错过的绝不仅仅只是几本书而已。我对许多美好的字眼都嗤之以鼻,比如“人格”、“正直”,因为成年人贬低了这些词。在他们嘴里,这些词似乎都是同一个意思——“听话”。一些孩子因为具备所谓的“人格”和“正直”,而受到夸奖,可是他们不是呆得像一头大笨牛,就是轻浮得像一个不动脑筋的吹牛者。如果“人格”和“正直”就是这种样子,我宁愿不要它们。
|
||||||
|
|
||||||
# ???????
|
# 黑客与画家
|
||||||
|
|
||||||
?????????????????????????????д?????
|
黑客和画家一样,都是艺术家,都在进行创作。
|
||||||
|
|
||||||
??????????????????????????????????????????????????????
|
黑客比较喜欢脚本语言那种可以动态扩展,并且可以像铅笔画画一样修修改改。
|
||||||
> ???????????????????????????????malleable??????????????????????????????????????????????????????????????????????????????????????????У??????????????????????static typing??????????????䶮??????????????????????????????????????????????????????????????????????????????????????????Σ????????????????????????豭??С?????????????????????????????????????????????????????????????????????????????????????ò???????
|
> 编程语言首要的特性应该是允许动态扩展(malleable)。编程语言是用来帮助思考程序的,而不是用来表达你已经想好的程序。它应该是一支铅笔,而不是一支钢笔。如果大家都像学校教的那样编程,那么静态类型(static typing)是一个不错的概念。但是,我认识的黑客,没有一个人喜欢用静态类型语言编程。我们需要的是一种可以随意涂抹、擦擦改改的语言,我们不想正襟危坐,把一个盛满各种变量类型的茶杯,小心翼翼放在自己的膝盖上,为了与一丝不苟的编译器大婶交谈,努力地挑选词语,确保变量类型匹配,好让自己显得礼貌又周到。
|
||||||
|
|
||||||
???????????о???????????????д???????
|
编码并不是科学研究,因此数学家不一定写一手好代码。
|
||||||
> ?????????????????????????к?????????????????????????????????????????????????????????????????????ɡ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
|
> 创作者不同于科学家,明白这一点有很多好处。除了不用为静态类型烦恼以外,还可以免去另一个折磨科学家的难题,那就是“对数学的妒忌”。科学界的每一个人,暗地里都相信数学家比自己聪明。我觉得,数学家自己也相信这一点。最后的结果就是科学家往往会把自己的工作尽可能弄得看上去像数学。对于物理学这样的领域,这可能不会有太大不良影响。但是,你越往自然科学的方向发展,它就越成为一个严重的问题。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????
|
黑客为了能做自己喜欢做的事并且可以养活自己,往往白天工作晚上做自己的事。
|
||||||
|
|
||||||
?????????????????????????????
|
热爱编程的人不可避免的会开发自己的项目。
|
||||||
> ??????????????????????????????????????????д????????????????????????????????????????????????????????????????????????????????????
|
> 我们面试程序员的时候,主要关注的事情就是业余时间他们写了什么软件。因为如果你不爱一件事,你不可能把它做得真正优秀,要是你很热爱编程,你就不可避免地会开发你自己的项目。
|
||||||
|
|
||||||
???????е???????????????????λ???????
|
黑客不是机械工作的技术工人,而是一位创作者。
|
||||||
> ??????????????????????????????????????????????????д?????????????????????????????????????????????????????????????????????????????????????????????е??????????????????С?
|
> 如果黑客只是一个负责实现领导意志的技术工人,职责就是根据规格说明书写出代码,那么他其实与一个挖水沟的工人是一样的,从这头挖到那头,仅此而已。但是,如果黑客是一个创作者,他从事的就不是机械性的工作,他必须具备灵感。
|
||||||
|
|
||||||
# ????????
|
# 不能说的话
|
||||||
|
|
||||||
???е?????????????????????????????????????????Υ????Щ?????????Щ????????????????????????鷳??С?
|
流行的道德观念虽然在后世看来会是荒诞的,但是如果在现今去违背这些道德观念,说一些不合适的言论,会让自己处于麻烦之中。
|
||||||
|
|
||||||
?????????????????????????????????????????????????Щ????????????????????????????????????????
|
自己会深深赞同自己的观点,并且确信会得到别人的认同,很可能是,这些观点是别人给自己灌输的,别人说什么,自己就相信什么。
|
||||||
|
|
||||||
?????????????????????????????????????????Щ??????????
|
不能说的话往往是正确的话,因为具有争议性,会让某些人暴跳如雷。
|
||||||
|
|
||||||
??Щ??????????????????????????????????а?????????????????????????????????????????
|
那些不一定正确,极富争议性的言论被成为“异端邪说“,人们常常会给它们加上标签,目的是为了封杀它们。
|
||||||
> ???????????????顢????????????????????????????????????????绯???????塢?????????????
|
> 亵渎神明、冒犯圣灵、异端都是西方历史上常见的标签,当代的标签则是有伤风化、不得体、破坏国家利益等。
|
||||||
|
|
||||||
??????????????Щ?????е?????????????????????????????????????????棬???????????????????????С?
|
禁忌的推崇者是那些处于中等阶层的人,他们不像高等阶层那样有足够自信保护自己的利益,又不同于低等阶层,他们有实力去推行。
|
||||||
|
|
||||||
???й??????????????????????????????????????????????????????
|
流行观点的第一批追逐者是为了让自己与众不同,而第二批则是怕自己与众不同。
|
||||||
|
|
||||||
???????????????????й????????????
|
科学家往往需要打破流行观点,从而取得突破。
|
||||||
|
|
||||||
??????????Щ??????????????????????????????
|
如果因为说了某些话而让干扰了自己的生活,最好还是别说。
|
||||||
> ??????????????????????????????????????е?????????Щ????????????????????????????????????????????????????????????????????????????????????????????????????????????????仮????????????????????????????????????????????????????????????????Щ????????????????????????????????????????????????????????????????????????????????????????????????????????
|
> 这时你要明白,自由思考比畅所欲言更重要。如果你感到一定要跟那些人辩个明白,绝不咽下这口气,一定要把话说清楚,结果很可能是从此你再也无法自由理性地思考了。我认为这样做不可取,更好的方法是在思想和言论之间划一条明确的界线。在心里无所不想,但是不一定要说出来。我就鼓励自己在心里默默思考那些最无法无天的想法。你的思想是一个地下组织,绝不要把那里发生的事情一股脑说给外人听。“格斗俱乐部”的第一条规则,就是不要提到格斗俱乐部。
|
||||||
|
|
||||||
???????????????????????????????????á?
|
当狂热分子质问你的观点时,最好是说自己还没想好。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????
|
人们会误认为自己思想开放,但是他们心里早就有一根界限,认为什么是正确的什么是错误的。
|
||||||
|
|
||||||
???????????????
|
更深入的认识自己。
|
||||||
> ?????????????????????????????????????????????????????????????????????????????????????????????????????
|
> 儿童精疲力竭时,可能会大发脾气,因为他不知道为了什么;成年人则会了解是个人的身体状况问题,与外界无关,说一句“没关系,我只是累了”。
|
||||||
|
|
||||||
# ?????·
|
# 另一条路
|
||||||
|
|
||||||
??????????????
|
互联网软件的优点
|
||||||
|
|
||||||
1. ?????????????????????????????????????????????????????
|
1. 不需要用户来管理系统,因此不需要专门的计算机知识,使用浏览器即可使用;
|
||||||
2. ??????????????????????????????????????????豸???У?
|
2. 需要的硬件资源很少,只需要能运行浏览器并且联网的设备就行;
|
||||||
3. ????????????????????
|
3. 更方便,随时随地就可以使用;
|
||||||
4. ???????????????????????????????
|
4. 不用担心数据丢失,因为数据保存在云端;
|
||||||
5. ??????????????????????????????????????????????????
|
5. 易于对软件进行升级,而用户可以在完全不知情的情况下继续使用;
|
||||||
6. ??????? bug ?????????? bug ????
|
6. 更容易的 bug 发现,更快的 bug 修改;
|
||||||
7. ??????????????????????????????????
|
7. 有专门的技术人员管理服务器,因为更加安全;
|
||||||
|
|
||||||
|
|
||||||
bug ????????????????????????????????????????????? bug ??????????
|
bug 越快发现越好,而互联网软件因为发布周期短,用户反馈快,因此 bug 的发现也更快。
|
||||||
|
|
||||||
?????????????????? bug??
|
高级用户很乐意帮助寻找 bug。
|
||||||
> ????????????????? bug ??????????????????????????????????????????????????????????????Щ??????????????????????????? bug ????????????????????Щ bug ????????????????????????????Щ?????????????????????????????????????????????? bug ????????о????Щ?????????????????????????????????????????????? bug ?е???????????绰???????????????????????????????????????????????????????????÷????????
|
> 因为软件发布以后,大多数 bug 都是罕见情况下才会发生的个案,受到影响的用户往往都是高级使用者,他们喜欢试验那些不常用的、难度大的操作。高级使用者对 bug 的容忍度比较高,尤其如果这些 bug 是在开发新功能的过程中引入的,而这些新功能又正是他们所需要的,他们就更能理解了。事实上,因为 bug 不多,你只有经过一些复杂的过程以后才会遇到它们,所以高级使用者往往因为发现了 bug 感到很得意。他们打电话给客服时,多半是一副胜利者的口吻,而不是怒气冲冲的样子,好像他们击败我们得分了一样。
|
||||||
|
|
||||||
????????????????????????????ú?????????????? bug??
|
好的技术支持是:客服人员和技术人员离得很近,并且当场修复 bug。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????
|
一个好的想法在实现过程中能引起更多想法,因此尽早去实现它比将它束之高阁能够带来更多好处。
|
||||||
|
|
||||||
????????????????????????????????????????г????????
|
不会购买软件的用户使用了盗版软件能够让软件更具有市场影响力。
|
||||||
> ??????????????????????к?????????????????????????Щ???????????????????????????????棬??????κ???????????????????????????????????????????????г??????????????Щ???????????????????????????????????
|
> 一定数量的盗版对软件公司是有好处的。不管你的软件定价多少,有些用户永远都不会购买。如果这样的用户使用盗版,你并没有任何损失。事实上,你反而赚到了,因为你的软件现在多了一个用户,市场影响力就更大了一些,而这个用户可能毕业以后就会出钱购买你的软件。
|
||||||
|
|
||||||
# ??????о?
|
# 设计与研究
|
||||||
|
|
||||||
??????????????о??????????
|
设计追求的是好,而研究追求的是新。
|
||||||
|
|
||||||
?????????????????????????????????????????????????????????????????????????????????
|
用户要求和用户需求有区别,用户可能并不了解自己要什么,所以用户要求的内容往往不是用户真正需求的东西。
|
||||||
|
|
||||||
??????????????????????о????????????????????????????????????????????????鷳????????????????????????????????????????????????????????????????????????
|
艺术设计与人为本,而科学研究追求简洁正确。比如数学家不会为了让读者更容易懂而采用一种更麻烦的证明,而是会选择最直接简洁的证明。编程语言也是与人为本的,因此编程语言也是通过设计产生的。
|
||||||
|
|
||||||
???????????????????????????????????????????????е???????????????????????????????????????????????????????????????????????????????????
|
大理石做出的东西漂亮,但是制作过程却很难,无法不断的进行雕琢。编程语言也需要这种雕琢过程,如果一种编程语言像大理石一样,只是结果好看,那么它就不是一种好的编程语言。
|
||||||
|
|
||||||
??????????????ó???????????????????????ü????????????????????????????????????
|
设计软件应当尽快拿出原型来。就像画画一样,是先用几根线画出一个大致准确的轮廓,然后再逐步加工。
|
||||||
> ????????????????????????????????????????????????????ó???????????????????????????????????????????????????????????????г?????????????????????????????????????????????????????????????й????????????????????????????????????????????????????
|
> 还有另一种软件设计思想,也许可以被称为“圣母玛丽亚”模式。它不要求尽快拿出原型,然后再逐步优化,它的观点是你应该等到完整的成品出来以后再一下子隆重地推向市场,就像圣母玛丽亚降临一样,哪怕整个过程漫长得像橄榄球运动员长途奔袭也没有关系。在互联网泡沫时期,无数创业公司因为相信了这种模式而自毁前程。
|
||||||
|
|
||||||
????????????????ζ?????????????????????ζ??????????????ó?????и????????????????????????????????????????????????????
|
如果觉得做某件事很乏味,那么做出来的东西就会很乏味。快速的原型能够让程序员有更高的士气,从而让他们更有兴趣去实现。也可以理解为快速反馈很重要。
|
||||||
|
|
Loading…
Reference in New Issue
Block a user