diff --git a/docs/notes/Git.md b/docs/notes/Git.md
index de8bbf35..06c52b54 100644
--- a/docs/notes/Git.md
+++ b/docs/notes/Git.md
@@ -24,7 +24,7 @@ Git 属于分布式版本控制系统,而 SVN 属于集中式。
集中式版本控制有安全性问题,当中心服务器挂了所有人都没办法工作了。
-集中式版本控制需要连网才能工作,如果网速过慢,那么提交一个文件的会慢的无法让人忍受。而分布式版本控制不需要连网就能工作。
+集中式版本控制需要连网才能工作,如果网速过慢,那么提交一个文件会慢的无法让人忍受。而分布式版本控制不需要连网就能工作。
分布式版本控制新建分支、合并分支操作速度非常快,而集中式版本控制新建一个分支相当于复制一份完整代码。
@@ -38,7 +38,7 @@ Github 就是一个中心服务器。
新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git,它属于 Git 的版本库。
-Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 中存有所有分支,使用一个 HEAD 指针指向当前分支。
+Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 存储所有分支信息,使用一个 HEAD 指针指向当前分支。
@@ -62,7 +62,7 @@ Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本
-新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
+新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支,表示新分支成为当前分支。
@@ -114,7 +114,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。
-可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈上,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
+可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈中,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
```
$ git stash
diff --git a/docs/notes/Leetcode-Database 题解.md b/docs/notes/Leetcode-Database 题解.md
index 7cc32aca..8b83690e 100644
--- a/docs/notes/Leetcode-Database 题解.md
+++ b/docs/notes/Leetcode-Database 题解.md
@@ -48,6 +48,8 @@ https://leetcode.com/problems/big-countries/description/
## SQL Schema
+SQL Schema 用于在本地环境下创建表结构并导入数据,从而方便在本地环境解答。
+
```sql
DROP TABLE
IF
@@ -125,6 +127,8 @@ VALUES
'm' ^ 'm' ^ 'f' = 'f'
```
+
+
```sql
UPDATE salary
SET sex = CHAR ( ASCII(sex) ^ ASCII( 'm' ) ^ ASCII( 'f' ) );
@@ -301,6 +305,8 @@ VALUES
## Solution
+对 Email 进行分组,如果相同 Email 的数量大于等于 2,则表示该 Email 重复。
+
```sql
SELECT
Email
@@ -324,9 +330,9 @@ https://leetcode.com/problems/delete-duplicate-emails/description/
+----+---------+
| Id | Email |
+----+---------+
-| 1 | a@b.com |
-| 2 | c@d.com |
-| 3 | a@b.com |
+| 1 | john@example.com |
+| 2 | bob@example.com |
+| 3 | john@example.com |
+----+---------+
```
@@ -347,6 +353,8 @@ https://leetcode.com/problems/delete-duplicate-emails/description/
## Solution
+只保留相同 Email 中 Id 最小的那一个,然后删除其它的。
+
连接:
```sql
@@ -437,7 +445,7 @@ VALUES
## Solution
-使用左外连接。
+涉及到 Person 和 Address 两个表,在对这两个表执行连接操作时,因为要保留 Person 表中的信息,即使在 Address 表中没有关联的信息也要保留。此时可以用左外连接,将 Person 表放在 LEFT JOIN 的左边。
```sql
SELECT
@@ -797,10 +805,43 @@ VALUES
## Solution
+要统计某个 score 的排名,只要统计大于该 score 的 score 数量,然后加 1。
+
+| score | 大于该 score 的 score 数量 | 排名 |
+| :---: | :---: | :---: |
+| 4.1 | 2 | 3 |
+| 4.2 | 1 | 2 |
+| 4.3 | 0 | 1 |
+
+但是在本题中,相同的 score 只算一个排名:
+
+| score | 排名 |
+| :---: | :---: |
+| 4.1 | 3 |
+| 4.1 | 3 |
+| 4.2 | 2 |
+| 4.2 | 2 |
+| 4.3 | 1 |
+| 4.3 | 1 |
+
+可以按 score 进行分组,将同一个分组中的 score 只当成一个。
+
+但是如果分组字段只有 score 的话,那么相同的 score 最后的结果只会有一个,例如上面的 6 个记录最后只取出 3 个。
+
+| score | 排名 |
+| :---: | :---: |
+| 4.1 | 3 |
+| 4.2 | 2 |
+| 4.3 | 1 |
+
+所以在分组中需要加入 Id,每个记录显示一个结果。综上,需要使用 score 和 id 两个分组字段。
+
+在下面的实现中,首先将 Scores 表根据 score 字段进行自连接,得到一个新表,然后在新表上对 id 和 score 进行分组。
+
```sql
SELECT
- S1.score,
- COUNT( DISTINCT S2.score ) Rank
+ S1.score 'Score',
+ COUNT( DISTINCT S2.score ) 'Rank'
FROM
Scores S1
INNER JOIN Scores S2
@@ -931,6 +972,8 @@ VALUES
使用多个 union。
```sql
+# 处理偶数 id,让 id 减 1
+# 例如 2,4,6,... 变成 1,3,5,...
SELECT
s1.id - 1 AS id,
s1.student
@@ -938,6 +981,8 @@ FROM
seat s1
WHERE
s1.id MOD 2 = 0 UNION
+# 处理奇数 id,让 id 加 1。但是如果最大的 id 为奇数,则不做处理
+# 例如 1,3,5,... 变成 2,4,6,...
SELECT
s2.id + 1 AS id,
s2.student
@@ -946,6 +991,7 @@ FROM
WHERE
s2.id MOD 2 = 1
AND s2.id != ( SELECT max( s3.id ) FROM seat s3 ) UNION
+# 如果最大的 id 为奇数,单独取出这个数
SELECT
s4.id AS id,
s4.student
diff --git a/docs/notes/代码可读性.md b/docs/notes/代码可读性.md
index 462f7103..f6995f62 100644
--- a/docs/notes/代码可读性.md
+++ b/docs/notes/代码可读性.md
@@ -70,7 +70,7 @@ int c = 111; // 注释
# 五、为何编写注释
-阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是并不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
+阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
不能因为有注释就随便起个名字,而是争取起个好名字而不写注释。
diff --git a/docs/notes/构建工具.md b/docs/notes/构建工具.md
index ab14eb64..d3d3f941 100644
--- a/docs/notes/构建工具.md
+++ b/docs/notes/构建工具.md
@@ -32,10 +32,10 @@
# 二、Java 主流构建工具
-主要包括 Ant、Maven 和 Gradle。
+Ant 具有编译、测试和打包功能,其后出现的 Maven 在 Ant 的功能基础上又新增了依赖管理功能,而最新的 Maven 又在 Maven 的功能基础上新增了对 Groovy 语言的支持。
-
+
Gradle 和 Maven 的区别是,它使用 Groovy 这种特定领域语言(DSL)来管理构建脚本,而不再使用 XML 这种标记性语言。因为项目如果庞大的话,XML 很容易就变得臃肿。
@@ -82,7 +82,7 @@ dependencies {
- 本地仓库用来存储项目的依赖库;
- 中央仓库是下载依赖库的默认位置;
-- 远程仓库,因为并非所有的库存储在中央仓库,或者中央仓库访问速度很慢,远程仓库是中央仓库的补充。
+- 远程仓库,因为并非所有的依赖库都在中央仓库,或者中央仓库访问速度很慢,远程仓库是中央仓库的补充。
## POM
@@ -99,7 +99,6 @@ POM 代表项目对象模型,它是一个 XML 文件,保存在项目根目
[groupId, artifactId, version, packaging, classifier] 称为一个项目的坐标,其中 groupId、artifactId、version 必须定义,packaging 可选(默认为 Jar),classifier 不能直接定义的,需要结合插件使用。
-
- groupId:项目组 Id,必须全球唯一;
- artifactId:项目 Id,即项目名;
- version:项目版本;
diff --git a/docs/notes/计算机操作系统 - 概述.md b/docs/notes/计算机操作系统 - 概述.md
index d2c12d92..4813d72b 100644
--- a/docs/notes/计算机操作系统 - 概述.md
+++ b/docs/notes/计算机操作系统 - 概述.md
@@ -36,15 +36,15 @@
有两种共享方式:互斥共享和同时共享。
-互斥共享的资源称为临界资源,例如打印机等,在同一时间只允许一个进程访问,需要用同步机制来实现对临界资源的访问。
+互斥共享的资源称为临界资源,例如打印机等,在同一时刻只允许一个进程访问,需要用同步机制来实现互斥访问。
## 3. 虚拟
虚拟技术把一个物理实体转换为多个逻辑实体。
-主要有两种虚拟技术:时分复用技术和空分复用技术。
+主要有两种虚拟技术:时(时间)分复用技术和空(空间)分复用技术。
-多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换。
+多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一小个时间片并快速切换。
虚拟内存使用了空分复用技术,它将物理内存抽象为地址空间,每个进程都有各自的地址空间。地址空间的页被映射到物理内存,地址空间的页并不需要全部在物理内存中,当使用到一个没有在物理内存的页时,执行页面置换算法,将该页置换到内存中。
diff --git a/docs/notes/设计模式.md b/docs/notes/设计模式.md
index bf448c41..e781102c 100644
--- a/docs/notes/设计模式.md
+++ b/docs/notes/设计模式.md
@@ -131,7 +131,7 @@ public class Singleton {
}
```
-考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句。
+考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句:第一个 if 语句用来避免 uniqueInstance 已经被实例化之后的加锁操作,而第二个 if 语句进行了加锁,所以只能有一个线程进入,就不会出现 uniqueInstance == null 时两个线程同时进行实例化操作。
```java
if (uniqueInstance == null) {
@@ -153,7 +153,7 @@ uniqueInstance 采用 volatile 关键字修饰也是很有必要的, `uniqueIn
#### Ⅴ 静态内部类实现
-当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()` 方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
+当 Singleton 类被加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()` 方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
@@ -224,10 +224,10 @@ secondName
secondName
```
-该实现在多次序列化再进行反序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。
-
该实现可以防止反射攻击。在其它实现中,通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public,然后调用构造函数从而实例化对象,如果要防止这种攻击,需要在构造函数中添加防止多次实例化的代码。该实现是由 JVM 保证只会实例化一次,因此不会出现上述的反射攻击。
+该实现在多次序列化和序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。
+
### Examples
- Logger Classes
diff --git a/docs/notes/面向对象思想.md b/docs/notes/面向对象思想.md
index a5af462c..d6910f48 100644
--- a/docs/notes/面向对象思想.md
+++ b/docs/notes/面向对象思想.md
@@ -21,13 +21,13 @@
## 封装
-利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
+利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外的接口使其与外部发生联系。用户无需关心对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
优点:
- 减少耦合:可以独立地开发、测试、优化、使用、理解和修改
- 减轻维护的负担:可以更容易被程序员理解,并且在调试的时候可以不影响其他模块
-- 有效地调节性能:可以通过剖析确定哪些模块影响了系统的性能
+- 有效地调节性能:可以通过剖析来确定哪些模块影响了系统的性能
- 提高软件的可重用性
- 降低了构建大型系统的风险:即使整个系统不可用,但是这些独立的模块却有可能是可用的
@@ -94,21 +94,27 @@ public class Instrument {
System.out.println("Instument is playing...");
}
}
+```
+```java
public class Wind extends Instrument {
public void play() {
System.out.println("Wind is playing...");
}
}
+```
+```java
public class Percussion extends Instrument {
public void play() {
System.out.println("Percussion is playing...");
}
}
+```
+```java
public class Music {
public static void main(String[] args) {
@@ -122,6 +128,11 @@ public class Music {
}
```
+```
+Wind is playing...
+Percussion is playing...
+```
+
# 二、类图
以下类图使用 [PlantUML](https://www.planttext.com/) 绘制,更多语法及使用请参考:http://plantuml.com/ 。
diff --git a/notes/Git.md b/notes/Git.md
index bb50bf57..21781af7 100644
--- a/notes/Git.md
+++ b/notes/Git.md
@@ -24,7 +24,7 @@ Git 属于分布式版本控制系统,而 SVN 属于集中式。
集中式版本控制有安全性问题,当中心服务器挂了所有人都没办法工作了。
-集中式版本控制需要连网才能工作,如果网速过慢,那么提交一个文件的会慢的无法让人忍受。而分布式版本控制不需要连网就能工作。
+集中式版本控制需要连网才能工作,如果网速过慢,那么提交一个文件会慢的无法让人忍受。而分布式版本控制不需要连网就能工作。
分布式版本控制新建分支、合并分支操作速度非常快,而集中式版本控制新建一个分支相当于复制一份完整代码。
@@ -38,7 +38,7 @@ Github 就是一个中心服务器。
新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git,它属于 Git 的版本库。
-Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 中存有所有分支,使用一个 HEAD 指针指向当前分支。
+Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 存储所有分支信息,使用一个 HEAD 指针指向当前分支。
@@ -62,7 +62,7 @@ Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本
-新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
+新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支,表示新分支成为当前分支。
@@ -114,7 +114,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。
-可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈上,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
+可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈中,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
```
$ git stash
diff --git a/notes/Leetcode-Database 题解.md b/notes/Leetcode-Database 题解.md
index 7cc32aca..8b83690e 100644
--- a/notes/Leetcode-Database 题解.md
+++ b/notes/Leetcode-Database 题解.md
@@ -48,6 +48,8 @@ https://leetcode.com/problems/big-countries/description/
## SQL Schema
+SQL Schema 用于在本地环境下创建表结构并导入数据,从而方便在本地环境解答。
+
```sql
DROP TABLE
IF
@@ -125,6 +127,8 @@ VALUES
'm' ^ 'm' ^ 'f' = 'f'
```
+
+
```sql
UPDATE salary
SET sex = CHAR ( ASCII(sex) ^ ASCII( 'm' ) ^ ASCII( 'f' ) );
@@ -301,6 +305,8 @@ VALUES
## Solution
+对 Email 进行分组,如果相同 Email 的数量大于等于 2,则表示该 Email 重复。
+
```sql
SELECT
Email
@@ -324,9 +330,9 @@ https://leetcode.com/problems/delete-duplicate-emails/description/
+----+---------+
| Id | Email |
+----+---------+
-| 1 | a@b.com |
-| 2 | c@d.com |
-| 3 | a@b.com |
+| 1 | john@example.com |
+| 2 | bob@example.com |
+| 3 | john@example.com |
+----+---------+
```
@@ -347,6 +353,8 @@ https://leetcode.com/problems/delete-duplicate-emails/description/
## Solution
+只保留相同 Email 中 Id 最小的那一个,然后删除其它的。
+
连接:
```sql
@@ -437,7 +445,7 @@ VALUES
## Solution
-使用左外连接。
+涉及到 Person 和 Address 两个表,在对这两个表执行连接操作时,因为要保留 Person 表中的信息,即使在 Address 表中没有关联的信息也要保留。此时可以用左外连接,将 Person 表放在 LEFT JOIN 的左边。
```sql
SELECT
@@ -797,10 +805,43 @@ VALUES
## Solution
+要统计某个 score 的排名,只要统计大于该 score 的 score 数量,然后加 1。
+
+| score | 大于该 score 的 score 数量 | 排名 |
+| :---: | :---: | :---: |
+| 4.1 | 2 | 3 |
+| 4.2 | 1 | 2 |
+| 4.3 | 0 | 1 |
+
+但是在本题中,相同的 score 只算一个排名:
+
+| score | 排名 |
+| :---: | :---: |
+| 4.1 | 3 |
+| 4.1 | 3 |
+| 4.2 | 2 |
+| 4.2 | 2 |
+| 4.3 | 1 |
+| 4.3 | 1 |
+
+可以按 score 进行分组,将同一个分组中的 score 只当成一个。
+
+但是如果分组字段只有 score 的话,那么相同的 score 最后的结果只会有一个,例如上面的 6 个记录最后只取出 3 个。
+
+| score | 排名 |
+| :---: | :---: |
+| 4.1 | 3 |
+| 4.2 | 2 |
+| 4.3 | 1 |
+
+所以在分组中需要加入 Id,每个记录显示一个结果。综上,需要使用 score 和 id 两个分组字段。
+
+在下面的实现中,首先将 Scores 表根据 score 字段进行自连接,得到一个新表,然后在新表上对 id 和 score 进行分组。
+
```sql
SELECT
- S1.score,
- COUNT( DISTINCT S2.score ) Rank
+ S1.score 'Score',
+ COUNT( DISTINCT S2.score ) 'Rank'
FROM
Scores S1
INNER JOIN Scores S2
@@ -931,6 +972,8 @@ VALUES
使用多个 union。
```sql
+# 处理偶数 id,让 id 减 1
+# 例如 2,4,6,... 变成 1,3,5,...
SELECT
s1.id - 1 AS id,
s1.student
@@ -938,6 +981,8 @@ FROM
seat s1
WHERE
s1.id MOD 2 = 0 UNION
+# 处理奇数 id,让 id 加 1。但是如果最大的 id 为奇数,则不做处理
+# 例如 1,3,5,... 变成 2,4,6,...
SELECT
s2.id + 1 AS id,
s2.student
@@ -946,6 +991,7 @@ FROM
WHERE
s2.id MOD 2 = 1
AND s2.id != ( SELECT max( s3.id ) FROM seat s3 ) UNION
+# 如果最大的 id 为奇数,单独取出这个数
SELECT
s4.id AS id,
s4.student
diff --git a/notes/代码可读性.md b/notes/代码可读性.md
index 0be113e9..0ed55a6b 100644
--- a/notes/代码可读性.md
+++ b/notes/代码可读性.md
@@ -70,7 +70,7 @@ int c = 111; // 注释
# 五、为何编写注释
-阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是并不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
+阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
不能因为有注释就随便起个名字,而是争取起个好名字而不写注释。
diff --git a/notes/构建工具.md b/notes/构建工具.md
index bf287fd9..588755c1 100644
--- a/notes/构建工具.md
+++ b/notes/构建工具.md
@@ -32,10 +32,10 @@
# 二、Java 主流构建工具
-主要包括 Ant、Maven 和 Gradle。
+Ant 具有编译、测试和打包功能,其后出现的 Maven 在 Ant 的功能基础上又新增了依赖管理功能,而最新的 Maven 又在 Maven 的功能基础上新增了对 Groovy 语言的支持。
-
+
Gradle 和 Maven 的区别是,它使用 Groovy 这种特定领域语言(DSL)来管理构建脚本,而不再使用 XML 这种标记性语言。因为项目如果庞大的话,XML 很容易就变得臃肿。
@@ -82,7 +82,7 @@ dependencies {
- 本地仓库用来存储项目的依赖库;
- 中央仓库是下载依赖库的默认位置;
-- 远程仓库,因为并非所有的库存储在中央仓库,或者中央仓库访问速度很慢,远程仓库是中央仓库的补充。
+- 远程仓库,因为并非所有的依赖库都在中央仓库,或者中央仓库访问速度很慢,远程仓库是中央仓库的补充。
## POM
@@ -99,7 +99,6 @@ POM 代表项目对象模型,它是一个 XML 文件,保存在项目根目
[groupId, artifactId, version, packaging, classifier] 称为一个项目的坐标,其中 groupId、artifactId、version 必须定义,packaging 可选(默认为 Jar),classifier 不能直接定义的,需要结合插件使用。
-
- groupId:项目组 Id,必须全球唯一;
- artifactId:项目 Id,即项目名;
- version:项目版本;
diff --git a/notes/计算机操作系统 - 概述.md b/notes/计算机操作系统 - 概述.md
index 2528750d..dec63667 100644
--- a/notes/计算机操作系统 - 概述.md
+++ b/notes/计算机操作系统 - 概述.md
@@ -36,15 +36,15 @@
有两种共享方式:互斥共享和同时共享。
-互斥共享的资源称为临界资源,例如打印机等,在同一时间只允许一个进程访问,需要用同步机制来实现对临界资源的访问。
+互斥共享的资源称为临界资源,例如打印机等,在同一时刻只允许一个进程访问,需要用同步机制来实现互斥访问。
## 3. 虚拟
虚拟技术把一个物理实体转换为多个逻辑实体。
-主要有两种虚拟技术:时分复用技术和空分复用技术。
+主要有两种虚拟技术:时(时间)分复用技术和空(空间)分复用技术。
-多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换。
+多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一小个时间片并快速切换。
虚拟内存使用了空分复用技术,它将物理内存抽象为地址空间,每个进程都有各自的地址空间。地址空间的页被映射到物理内存,地址空间的页并不需要全部在物理内存中,当使用到一个没有在物理内存的页时,执行页面置换算法,将该页置换到内存中。
diff --git a/notes/设计模式.md b/notes/设计模式.md
index 2c4ebc5f..cddc1d34 100644
--- a/notes/设计模式.md
+++ b/notes/设计模式.md
@@ -131,7 +131,7 @@ public class Singleton {
}
```
-考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句。
+考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句:第一个 if 语句用来避免 uniqueInstance 已经被实例化之后的加锁操作,而第二个 if 语句进行了加锁,所以只能有一个线程进入,就不会出现 uniqueInstance == null 时两个线程同时进行实例化操作。
```java
if (uniqueInstance == null) {
@@ -153,7 +153,7 @@ uniqueInstance 采用 volatile 关键字修饰也是很有必要的, `uniqueIn
#### Ⅴ 静态内部类实现
-当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()` 方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
+当 Singleton 类被加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()` 方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
@@ -224,10 +224,10 @@ secondName
secondName
```
-该实现在多次序列化再进行反序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。
-
该实现可以防止反射攻击。在其它实现中,通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public,然后调用构造函数从而实例化对象,如果要防止这种攻击,需要在构造函数中添加防止多次实例化的代码。该实现是由 JVM 保证只会实例化一次,因此不会出现上述的反射攻击。
+该实现在多次序列化和序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。
+
### Examples
- Logger Classes
diff --git a/notes/面向对象思想.md b/notes/面向对象思想.md
index 1c44cb89..19ec6e8b 100644
--- a/notes/面向对象思想.md
+++ b/notes/面向对象思想.md
@@ -21,13 +21,13 @@
## 封装
-利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
+利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外的接口使其与外部发生联系。用户无需关心对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
优点:
- 减少耦合:可以独立地开发、测试、优化、使用、理解和修改
- 减轻维护的负担:可以更容易被程序员理解,并且在调试的时候可以不影响其他模块
-- 有效地调节性能:可以通过剖析确定哪些模块影响了系统的性能
+- 有效地调节性能:可以通过剖析来确定哪些模块影响了系统的性能
- 提高软件的可重用性
- 降低了构建大型系统的风险:即使整个系统不可用,但是这些独立的模块却有可能是可用的
@@ -94,21 +94,27 @@ public class Instrument {
System.out.println("Instument is playing...");
}
}
+```
+```java
public class Wind extends Instrument {
public void play() {
System.out.println("Wind is playing...");
}
}
+```
+```java
public class Percussion extends Instrument {
public void play() {
System.out.println("Percussion is playing...");
}
}
+```
+```java
public class Music {
public static void main(String[] args) {
@@ -122,6 +128,11 @@ public class Music {
}
```
+```
+Wind is playing...
+Percussion is playing...
+```
+
# 二、类图
以下类图使用 [PlantUML](https://www.planttext.com/) 绘制,更多语法及使用请参考:http://plantuml.com/ 。