Merge pull request #1487 from CyC2018/proofread-notes

Update notes
This commit is contained in:
CyC2018
2026-10-28 13:38:28 +08:00
committed by GitHub
28 changed files with 80 additions and 77 deletions
+2 -2
View File
@@ -36,7 +36,7 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU 资源,一台机器只能开启几十个的虚拟机。
而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
而容器只是宿主机上隔离运行的进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以运行成千上万个容器。
## 三、优势
@@ -152,7 +152,7 @@ spec:
在单节点 K8s(k3s v1.31)上实际操作的结果如下:
- kubectl apply 之后约 20 秒,3 个 Pod 全部就绪,Service 得到虚拟 IP 10.43.189.89,在集群内用 http://order-service 就能访问;
- 删除一个 Pod,Deployment 发现副本数少于 3,立即创建新的 Pod,约 1.2 秒后恢复为 3/3,新 Pod 的 IP 与原来不同,Service 自动更新了后端列表;
- 删除一个 Pod,Deployment 创建的 ReplicaSet 发现副本数少于 3,立即创建新的 Pod,约 1.2 秒后恢复为 3/3,新 Pod 的 IP 与原来不同,Service 自动更新了后端列表;
- kubectl scale 把副本数改为 5;kubectl set image 修改镜像版本后,Deployment 创建新的 ReplicaSet,逐个用新版本的 Pod 替换旧的,约 12 秒完成滚动升级,期间一直有就绪的 Pod 在提供服务,需要时可以用 kubectl rollout undo 回滚。
readinessProbe 是就绪探针:Pod 启动后要通过检查才会加入 Service 的后端列表,避免把请求转发给还没启动完成的实例。
+7 -7
View File
@@ -71,7 +71,7 @@ Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本
<div align="center"> <img src="pics/git-branch-commit.png" width="760px"/> </div><br>
合并分支也只需要改变指针即可:切换回 master 后合并 dev,master 直接移动到 dev 所指的提交。
合并分支也只需要改变指针即可:切换回 master 后合并 dev,master 直接移动到 dev 所指的提交。这种情况称为快进合并(Fast-forward),两个分支都有新的提交时,合并会生成一个新的提交。
<div align="center"> <img src="pics/git-branch-merge.png" width="760px"/> </div><br>
@@ -105,9 +105,9 @@ $ git merge --no-ff -m "merge with no-ff" dev
## 储藏(Stashing)
在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。
在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。如果这些修改涉及的文件在两个分支上不同,切换会覆盖掉修改,Git 会拒绝切换。
可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈中,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区中已跟踪文件的修改都会被存到栈中,工作区回到干净的状态;未跟踪的新文件默认不会储藏,需要加上 -u 选项。此时就可以安全的切换到其它分支上了。
```bash
$ git stash
@@ -119,15 +119,15 @@ HEAD is now at 049d078 added the index file (To restore them type "git stash app
## SSH 传输设置
Git 仓库和 GitHub 中心仓库之间的传输是通过 SSH 加密。
Git 仓库和 GitHub 中心仓库之间可以通过 HTTPS 或者 SSH 加密传输,使用 SSH 时需要配置 SSH Key。
如果用户主目录下没有 .ssh 目录,或者该目录下没有 id_rsa 和 id_rsa.pub 这两个文件,可以通过以下命令来创建 SSH Key:
如果用户主目录下没有 .ssh 目录,或者该目录下没有 id_ed25519 和 id_ed25519.pub 这两个文件,可以通过以下命令来创建 SSH Key:
```bash
$ ssh-keygen -t rsa -C "youremail@example.com"
$ ssh-keygen -t ed25519 -C "youremail@example.com"
```
然后把公钥 id_rsa.pub 的内容复制到 GitHub “Settings” 的 SSH Keys 中。
然后把公钥 id_ed25519.pub 的内容复制到 GitHub “Settings” 的 SSH Keys 中。
## .gitignore 文件
+3 -3
View File
@@ -125,7 +125,7 @@ DataInputStream 装饰者提供了对更多数据类型进行输入的操作,
UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-16le,le 指的是 Little Endian,也就是小端。
Java 的内存编码使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。
Java 的 char 类型占 16 位,存放的是字符的 UTF-16 编码,这不是指 Java 只支持这一种编码方式。常用的中文和英文字符都能用一个 char 存储,编号超过 U+FFFF 的字符(例如一部分生僻字和 emoji)要用两个 char 表示。
### String 的编码方式
@@ -138,7 +138,7 @@ String str2 = new String(bytes, "UTF-8");
System.out.println(str2);
```
在调用无参数 getBytes() 方法时,默认的编码方式不是 UTF-16be。双字节编码的好处是可以使用一个 char 存储中文和英文,而将 String 转为 bytes[] 字节数组就不再需要这个好处,因此也就不再需要双字节编码。getBytes() 的默认编码方式与平台有关,一般为 UTF-8。
在调用无参数 getBytes() 方法时,默认的编码方式不是 UTF-16。双字节编码的好处是可以使用一个 char 存储中文和英文,而将 String 转为 bytes[] 字节数组就不再需要这个好处,因此也就不再需要双字节编码。JDK 18 起 getBytes() 默认使用 UTF-8(JEP 400),之前的版本与平台有关。
```java
byte[] bytes = str1.getBytes();
@@ -254,7 +254,7 @@ InetAddress.getByAddress(byte[] address);
```java
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.baidu.com");
URL url = URI.create("http://www.baidu.com").toURL();
/* 字节流 */
InputStream is = url.openStream();
+5 -5
View File
@@ -228,7 +228,7 @@ SAS(Serial Attached SCSI)是新一代的 SCSI 技术,和 SATA 硬盘相同
Linux 中每个硬件都被当做一个文件,包括磁盘。磁盘以磁盘接口类型进行命名,常见磁盘的文件名如下:
- IDE 磁盘:/dev/hd[a-d]
- IDE 磁盘:/dev/hd[a-d](旧驱动的命名,Linux 5.14 移除了旧的 IDE 驱动,现在由 libata 驱动 IDE 磁盘,也命名为 /dev/sd*)
- SATA/SCSI/SAS 磁盘:/dev/sd[a-p]
- NVMe 磁盘:/dev/nvme0n1、/dev/nvme1n1
@@ -278,7 +278,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
#### 2. UEFI
BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
BIOS 只会执行 MBR 中的开机管理程序,本身不读取分区表,从 GPT 磁盘启动要依靠支持 GPT 的开机管理程序(例如 GRUB);UEFI 可以直接读取 GPT 分区表。
## 四、文件系统
@@ -450,7 +450,7 @@ rmdir [-p] 目录名称
```text
## touch [-acdmt] filename
-a : 更新 atime
-c : 更新 ctime,若该文件不存在则不建立新文件
-c : 若该文件不存在则不建立新文件
-m : 更新 mtime
-d : 后面可以接更新日期而不使用当前日期,也可以使用 --date="日期或时间"
-t : 后面可以接更新时间而不使用当前时间,格式为[YYYYMMDDhhmm]
@@ -760,7 +760,7 @@ $ xz [-dtlkc#] filename
$ tar [-z|-j|-J] [cv] [-f 新建的 tar 文件] filename... ==打包压缩
$ tar [-z|-j|-J] [tv] [-f 已有的 tar 文件] ==查看
$ tar [-z|-j|-J] [xv] [-f 已有的 tar 文件] [-C 目录] ==解压缩
-z :使用 zip;
-z :使用 gzip;
-j :使用 bzip2;
-J :使用 xz;
-c :新建打包文件;
@@ -785,7 +785,7 @@ $ tar [-z|-j|-J] [xv] [-f 已有的 tar 文件] [-C 目录] ==解压缩
- 命令历史:记录使用过的命令
- 命令与文件补全:快捷键:tab
- 命令别名:例如 ll 通常是 ls -l 或者 ls -alF 的别名,具体取决于发行版的配置
- 命令别名:例如 Ubuntu 默认的 ~/.bashrc 中,ll 是 ls -alF 的别名
- shell scripts
- 通配符:例如 ls -l /usr/bin/X\* 列出 /usr/bin 下面所有以 X 开头的文件
+1 -1
View File
@@ -764,7 +764,7 @@ VALUES
### Solution
```sql
CREATE FUNCTION getNthHighestSalary ( N INT ) RETURNS INT BEGIN
CREATE FUNCTION getNthHighestSalary ( N INT ) RETURNS INT READS SQL DATA BEGIN
SET N = N - 1;
RETURN (
+8 -7
View File
@@ -42,7 +42,7 @@
模式定义了数据如何存储、存储什么样的数据以及数据如何分解等信息,数据库和表都有模式。
主键的值不允许修改,也不允许复用(不能将已经删除的主键值赋给新数据行的主键)。
主键的值一般不修改,也不复用(不把已经删除的主键值赋给新数据行的主键),这是普遍遵循的习惯,数据库本身并不禁止。
SQL(Structured Query Language),标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL。各个 DBMS 都有自己的实现,如 PL/SQL、Transact-SQL 等。
@@ -403,7 +403,7 @@ HAVING num >= 2;
## 十四、子查询
子查询中只能返回一个字段的数据。
作为 IN 等条件与一个字段比较的子查询,只能返回一个字段的数据;MySQL 也支持 (col1, col2) IN (SELECT x, y ...) 这样同时比较多个字段。
可以将子查询的结果作为 WHERE 语句的过滤条件:
@@ -581,9 +581,7 @@ WHERE col5 = val;
包含 in、out 和 inout 三种参数。
给变量赋值都需要用 select into 语句。
每次只能给一个变量赋值,不支持集合的操作。
可以用 SET 或者 SELECT ... INTO 给变量赋值。SELECT ... INTO 可以一次给多个变量赋值,但查询结果只能有一行,否则报错 1172(Result consisted of more than one row),多行结果要用下面的游标逐行处理。
```sql
delimiter //
@@ -633,7 +631,10 @@ create procedure myprocedure(out ret int)
repeat
fetch mycursor into ret;
select ret;
# 最后一次 fetch 没有取到数据时 done 已经为 1,不能再输出 ret
if not done then
select ret;
end if;
until done end repeat;
close mycursor;
@@ -658,7 +659,7 @@ SELECT @result; -- 获取结果
DELETE 触发器包含一个名为 OLD 的虚拟表,并且是只读的。
UPDATE 触发器包含一个名为 NEW 和一个名为 OLD 的虚拟表,其中 NEW 是可以被修改的,而 OLD 是只读的。
UPDATE 触发器包含一个名为 NEW 和一个名为 OLD 的虚拟表,其中 NEW 只能在 BEFORE 触发器中修改(SET NEW.col = ...),而 OLD 是只读的。
MySQL 的触发器可以使用 CALL 语句调用存储过程,但是该存储过程不能向客户端返回数据,也不能使用动态 SQL。
+1 -1
View File
@@ -62,7 +62,7 @@ Spring Cloud 与 Spring Boot 的关系:Spring Boot 用来快速构建单个服
| --- | --- | --- | --- |
| 服务的实例在哪里 | DiscoveryClient 接口 | Nacos | Eureka |
| 选择哪个实例 | Spring Cloud LoadBalancer | Nacos 的权重负载均衡 | Ribbon |
| 怎么调用其它服务 | OpenFeign | — | — |
| 怎么调用其它服务 | OpenFeign | — | Feign |
| 配置的集中管理和动态修改 | Spring Cloud Config | Nacos | Archaius |
| 外部请求从哪里进入 | Spring Cloud Gateway | — | Zuul |
| 下游故障时怎么保护自己 | Spring Cloud Circuit Breaker(Resilience4j) | Sentinel | Hystrix |
+4 -4
View File
@@ -188,9 +188,9 @@ strSQL = "SELECT * FROM users;"
Java 中的 PreparedStatement 是预先编译的 SQL 语句,可以传入适当参数并且多次执行。SQL 语句的结构在预编译时已经确定,传入的参数只会被当作数据,因此可以防止 SQL 注入的发生。
```java
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE userid=? AND password=?");
stmt.setString(1, userid);
stmt.setString(2, password);
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE name = ? AND pw = ?");
stmt.setString(1, name);
stmt.setString(2, pw);
ResultSet rs = stmt.executeQuery();
```
@@ -204,7 +204,7 @@ Query SELECT * FROM users WHERE name = '1'' OR ''1''=''1' AND pw = '1'' OR ''
#### 2. 单引号转换
将传入的参数中的单引号转换为连续两个单引号。PHP 的 Magic Quotes 曾经自动完成这个功能,但是因为不可靠已经被移除,应该使用数据库驱动提供的转义函数,并且只在无法使用参数化查询时使用。
将传入的参数中的单引号转换为连续两个单引号,或者在单引号前加反斜线(MySQL 默认两种都支持)。PHP 的 Magic Quotes 曾经自动给单引号等字符加反斜线,但是因为不可靠,已经在 PHP 5.4 中移除,应该使用数据库驱动提供的转义函数,并且只在无法使用参数化查询时使用。
#### 3. 最小权限
+1 -1
View File
@@ -52,7 +52,7 @@ gcc -o hello hello.c
- 可执行目标文件:可以直接在内存中执行;
- 可重定位目标文件:可与其它可重定位目标文件在链接阶段合并,创建一个可执行目标文件;
- 共享目标文件:这是一种特殊的可重定位目标文件,可以在运行时被动态加载进内存并链接;
- 共享目标文件:这是一种特殊的可重定位目标文件,可以在加载或者运行时被动态加载进内存并链接;
## 动态链接
+2 -2
View File
@@ -52,7 +52,7 @@
### 2. 分组交换
每个分组都有首部和尾部,包含了源地址和目的地址等控制信息,在同一个传输线路上同时传输多个分组互相不会影响,因此在同一条传输线路上允许同时传输多个分组,也就是说分组交换不需要占用传输线路。
每个分组都有首部,包含了源地址和目的地址等控制信息,在同一个传输线路上同时传输多个分组互相不会影响,因此在同一条传输线路上允许同时传输多个分组,也就是说分组交换不需要独占传输线路。
在一个邮局通信系统中,邮局收到一份邮件之后,先存储下来,然后把相同目的地的邮件一起转发到下一个目的地,这个过程就是存储转发过程,分组交换也使用了存储转发过程。
@@ -123,7 +123,7 @@ TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接
在向下的过程中,需要添加下层协议所需要的首部或者尾部,而在向上的过程中不断拆开首部和尾部。
路由器只有下面三层协议,因为路由器位于网络核心中,不需要为进程或者应用程序提供服务,因此也就不需要传输层和应用层。
路由器转发分组时只用到下面三层协议,因为路由器位于网络核心中,转发时不需要为进程或者应用程序提供服务,因此也就不需要传输层和应用层;路由器运行的路由协议另当别论,例如 BGP 使用 TCP 传输。
## 参考资料
+1 -1
View File
@@ -23,7 +23,7 @@
<div align="center"> <img src="pics/modulation.png" width="720px"/> </div><br>
实际的系统中还会把振幅和相位组合起来使用,例如正交振幅调制(Quadrature Amplitude Modulation, QAM)用 16 种不同的振幅和相位组合表示 4 个比特,一个码元就能传输更多的数据。
实际的系统中还会把振幅和相位组合起来使用,例如正交振幅调制(Quadrature Amplitude Modulation, QAM)中的 16-QAM 用 16 种不同的振幅和相位组合表示 4 个比特,一个码元就能传输更多的数据。
## 参考资料
+3 -2
View File
@@ -136,7 +136,8 @@ CSMA/CD 表示载波监听多点接入 / 碰撞检测。
PPP 的帧格式:
- F 字段为帧的定界符;
- A 和 C 字段暂时没有意义;
- A 和 C 字段的值是固定的,分别为 0xFF 和 0x03,不携带信息;
- 协议字段指明信息部分是哪种协议的数据,例如 0x0021 表示 IP 数据报;
- FCS 字段是使用 CRC 的检验序列;
- 信息部分的长度不超过 1500 字节。
@@ -192,7 +193,7 @@ MAC 地址是链路层地址,长度为 6 字节(48 位),用于唯一标
<div align="center"> <img src="pics/vlan-broadcast.png" width="760px"/> </div><br>
使用 VLAN 干线连接来建立虚拟局域网,每台交换机上的一个特殊接口被设置为干线接口,以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q,它在标准以太网帧上加进了 4 字节首部 VLAN 标签,用于表示该帧属于哪一个虚拟局域网。
使用 VLAN 干线连接来建立虚拟局域网,每台交换机上的一个特殊接口被设置为干线接口,以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q,它在标准以太网帧的源地址和类型字段之间插入了 4 字节的 VLAN 标签,用于表示该帧属于哪一个虚拟局域网。
<div align="center"> <img src="pics/vlan-tag.png" width="760px"/> </div><br>
+17 -16
View File
@@ -11,7 +11,7 @@
<div align="center"> <img src="pics/dp-singleton.png" width="760px"/> </div><br>
### 实现
#### Ⅰ 懒汉式-线程不安全
#### 1. 懒汉式-线程不安全
以下实现中,私有静态变量 uniqueInstance 被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。
@@ -34,7 +34,7 @@ public class Singleton {
}
```
#### Ⅱ 饿汉式-线程安全
#### 2. 饿汉式-线程安全
线程不安全问题主要是由于 uniqueInstance 被实例化多次,采取直接实例化 uniqueInstance 的方式就不会产生线程不安全问题。
@@ -44,7 +44,7 @@ public class Singleton {
private static Singleton uniqueInstance = new Singleton();
```
#### Ⅲ 懒汉式-线程安全
#### 3. 懒汉式-线程安全
只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了实例化多次 uniqueInstance。
@@ -59,7 +59,7 @@ public static synchronized Singleton getUniqueInstance() {
}
```
#### Ⅳ 双重校验锁-线程安全
#### 4. 双重校验锁-线程安全
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
@@ -98,15 +98,15 @@ if (uniqueInstance == null) {
uniqueInstance 采用 volatile 关键字修饰也是很有必要的, `uniqueInstance = new Singleton();` 这段代码其实是分为三步执行:
1. 为 uniqueInstance 分配内存空间
2. 初始化 uniqueInstance
1. 为对象分配内存空间
2. 初始化对象
3. 将 uniqueInstance 指向分配的内存地址
但是由于 JVM 具有重排序的特性,执行顺序有可能变成 1>3>2。重排序在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T<sub>1</sub> 执行了 1 和 3,此时 T<sub>2</sub> 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。
使用 volatile 可以禁止 JVM 的重排序,保证在多线程环境下也能正常运行。
#### Ⅴ 静态内部类实现
#### 5. 静态内部类实现
当 Singleton 类被加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()` 方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
@@ -128,9 +128,11 @@ public class Singleton {
}
```
#### Ⅵ 枚举实现
#### 6. 枚举实现
```java
import java.lang.reflect.Constructor;
public enum Singleton {
INSTANCE;
@@ -159,14 +161,13 @@ public enum Singleton {
System.out.println(firstSingleton.getObjName());
System.out.println(secondSingleton.getObjName());
// 反射获取实例测试
// 通过反射调用构造函数创建新的实例会失败
try {
Singleton[] enumConstants = Singleton.class.getEnumConstants();
for (Singleton enumConstant : enumConstants) {
System.out.println(enumConstant.getObjName());
}
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
constructor.newInstance("INSTANCE2", 1);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
}
}
@@ -176,7 +177,7 @@ public enum Singleton {
firstName
secondName
secondName
secondName
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
```
该实现可以防止反射攻击。在其它实现中,通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public,然后调用构造函数从而实例化对象,如果要防止这种攻击,需要在构造函数中添加防止多次实例化的代码。该实现是由 JVM 保证只会实例化一次,因此不会出现上述的反射攻击。
@@ -192,7 +193,7 @@ secondName
### JDK 中的应用
- [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
- [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
- [java.lang.System#getSecurityManager()](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
- [java.lang.System#getSecurityManager()](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)(JDK 17 起已废弃,JEP 411)
## 参考资料
+1 -1
View File
@@ -73,7 +73,7 @@ ExtrinsicState: y
```
### JDK 中的应用
Java 利用缓存来加速大量小对象的访问时间。
Java 利用缓存复用大量的小对象,减少对象的创建和内存占用。
- java.lang.Integer#valueOf(int)
- java.lang.Boolean#valueOf(boolean)
+1 -1
View File
@@ -87,7 +87,7 @@ public class ImageViewer {
public static void main(String[] args) throws Exception {
String image = "http://image.jpg";
URL url = new URL(image);
URL url = URI.create(image).toURL();
HighResolutionImage highResolutionImage = new HighResolutionImage(url);
ImageProxy imageProxy = new ImageProxy(highResolutionImage);
imageProxy.showImage();
+1 -1
View File
@@ -119,7 +119,7 @@ public class Client {
### JDK 中的应用
- [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
- [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
- [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)(开源库,不属于 JDK)
- [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html)
## 参考资料
+1 -1
View File
@@ -1,7 +1,7 @@
## 备忘录(Memento)
### 意图
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到之前保存的状态。
### 类图
- Originator:原始对象
-1
View File
@@ -52,7 +52,6 @@ public class ConcreteFactory2 extends Factory {
- [java.nio.charset.Charset](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
- [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-)
- [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-)
- [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--)
## 参考资料
+1 -1
View File
@@ -92,7 +92,7 @@ Tea.addCondiments
### JDK 中的应用
- java.util.Collections#sort()
- java.io.InputStream#skip()
- java.io.InputStream#read()
- java.io.InputStream#read(byte[], int, int)
- java.util.AbstractList#indexOf()
## 参考资料
+2
View File
@@ -10,6 +10,8 @@
以下是一个简易的 StringBuilder 实现,参考了 JDK 1.8 源码。
```java
import java.util.Arrays;
public class AbstractStringBuilder {
protected char[] value;
+1 -1
View File
@@ -80,7 +80,7 @@ public class Leaf extends Component {
@Override
public void add(Component component) {
throw new UnsupportedOperationException(); // 牺牲透明性换取单一职责原则,这样就不用考虑是叶子节点还是组合节点
throw new UnsupportedOperationException(); // 牺牲单一职责原则换取透明性,这样就不用考虑是叶子节点还是组合节点
}
@Override
+3 -3
View File
@@ -124,10 +124,10 @@ StatisticsDisplay.update: 1.0 1.0 1.0
```
### JDK 中的应用
- [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html)
- [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html)(JDK 9 起已废弃)
- [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html)
- [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html)
- [RxJava](https://github.com/ReactiveX/RxJava)
- [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html)(Servlet API,不属于 JDK)
- [RxJava](https://github.com/ReactiveX/RxJava)(开源库,不属于 JDK)
## 参考资料
+5 -5
View File
@@ -12,7 +12,7 @@
### 实现
以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一棵解析树,用来检验一个文本是否满足解析树定义的规则。
例如一棵解析树为 D And (A Or (B C)),文本 "D A" 满足该解析树定义的规则。
例如一棵解析树为 D And (A Or (B Or C)),文本 "D A" 满足该解析树定义的规则。
这里的 Context 指的是 String。
@@ -89,11 +89,11 @@ public class Client {
Expression terminal2 = new TerminalExpression("B");
Expression terminal3 = new TerminalExpression("C");
Expression terminal4 = new TerminalExpression("D");
// B C
// B Or C
Expression alternation1 = new OrExpression(terminal2, terminal3);
// A Or (B C)
// A Or (B Or C)
Expression alternation2 = new OrExpression(terminal1, alternation1);
// D And (A Or (B C))
// D And (A Or (B Or C))
return new AndExpression(terminal4, alternation2);
}
@@ -116,7 +116,7 @@ false
- [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
- [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html)
- All subclasses of [java.text.Format](http://docs.oracle.com/javase/8/docs/api/java/text/Format.html)
- [javax.el.ELResolver](http://docs.oracle.com/javaee/7/api/javax/el/ELResolver.html)
- [javax.el.ELResolver](http://docs.oracle.com/javaee/7/api/javax/el/ELResolver.html)(EL API,不属于 JDK)
## 参考资料
+2 -2
View File
@@ -121,8 +121,8 @@ request2 is handle by ConcreteHandler2
### JDK 中的应用
- [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
- [Apache Commons Chain](https://commons.apache.org/dormant/commons-chain/)
- [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)
- [Apache Commons Chain](https://commons.apache.org/dormant/commons-chain/)(开源库,不属于 JDK)
- [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)(Servlet API,不属于 JDK)
## 参考资料
+1 -1
View File
@@ -6,7 +6,7 @@
### 类图
- Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
- Iterator 主要定义了 hasNext() 和 next() 方法;
- Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。
- Client 依赖 Aggregate,为了迭代遍历 Aggregate,也需要依赖 Iterator。
<div align="center"> <img src="pics/dp-iterator.png" width="760px"/> </div><br>
-1
View File
@@ -63,7 +63,6 @@ public class Client {
- [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
- [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
- [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-)
- [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-)
## 参考资料
+2 -2
View File
@@ -149,7 +149,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
#### 4. 网络层
在操作系统内核进程获取网络数据包,根据负载均衡算法计算源服务器的 IP 地址,并修改请求数据包的目的 IP 地址,最后进行转发。
在操作系统内核中获取网络数据包,根据负载均衡算法计算源服务器的 IP 地址,并修改请求数据包的目的 IP 地址,最后进行转发。
源服务器返回的响应也需要经过负载均衡服务器,通常是让负载均衡服务器同时作为集群的网关服务器来实现。对应 LVS 的 NAT 模式。
@@ -169,7 +169,7 @@ HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服
这是一种三角传输模式,被称为直接路由,对应 LVS 的 DR 模式,要求源服务器和负载均衡服务器位于同一个局域网内。对于提供下载和视频服务的网站来说,直接路由避免了大量的网络传输数据经过负载均衡服务器。
网络层和链路层的方式不解析应用层协议,属于四层负载均衡。链路层是目前大型网站使用最广的负载均衡转发方式,在 Linux 平台可以使用的负载均衡服务器为 LVS(Linux Virtual Server),通常用 LVS 做四层负载均衡,再用 Nginx 做七层负载均衡。
网络层和链路层的方式不解析应用层协议,属于四层负载均衡。链路层负载均衡的响应不经过负载均衡服务器,性能很好,在 Linux 平台可以使用的负载均衡服务器为 LVS(Linux Virtual Server),通常用 LVS 做四层负载均衡,再用 Nginx 做七层负载均衡。
参考:
+4 -4
View File
@@ -246,11 +246,11 @@ School "1" - "*" Student
### 依赖关系 (Dependency)
和关联关系不同的是,依赖关系是在运行过程中起作用的。A 类和 B 类是依赖关系主要有三种形式:
和关联关系不同的是,依赖关系是在运行过程中起作用的。A 类依赖 B 类主要有三种形式:
- A 类是 B 类方法的局部变量;
- A 类是 B 类方法的参数;
- A 类向 B 类发送消息,从而影响 B 类发生变化。
- B 类是 A 类方法中的局部变量;
- B 类是 A 类方法的参数;
- A 类向 B 类发送消息(调用 B 类的方法),从而影响 B 类发生变化。
<div align="center"> <img src="pics/uml-dependency.png" width="640px"/> </div><br>