diff --git a/.gitignore b/.gitignore
index c91a56b6bc..9fdf53235c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
-.DS_Store
-*.txt
+.DS_Store
+*.txt
+!tencent13147342467085209222.txt
+desktop.ini
\ No newline at end of file
diff --git a/README.md b/README.md
index 810ab82459..e7c9e6eecb 100644
--- a/README.md
+++ b/README.md
@@ -1,154 +1,142 @@
-
-
-| 算法 | 操作系统 | 网络 | 面向对象 | 数据库 | Java | 系统设计 | 工具 | 编码实践 | 后记 |
-| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
-| [:pencil2:](#pencil2-算法) | [:computer:](#computer-操作系统)|[:cloud:](#cloud-网络) | [:art:](#art-面向对象) |[:floppy_disk:](#floppy_disk-数据库)| [:coffee:](#coffee-java)| [:bulb:](#bulb-系统设计)| [:wrench:](#wrench-工具)| [:watermelon:](#watermelon-编码实践)| [:memo:](#memo-后记) |
-
-
-
-
-

-
-

-
- 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。推荐使用 https://cyc2018.github.io/CS-Notes 进行阅读,从而获得更好的阅读体验。你也可以订阅
面试进阶指南,包含了学习指导和面试技巧,让你更轻松拿到满意的 Offer。
欢迎关注公众号“CyC2018”,每天发布一道高频基础知识面试题,让你在闲暇时间也能学习进步!公众号也提供了一个学习打卡圈子,记录你每天的学习收获,见证你的成长!

-
-
-
-
-
-## :pencil2: 算法
-
-- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/剑指%20Offer%20题解%20-%20目录.md)
-- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode%20题解%20-%20目录.md)
-- [算法](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/算法%20-%20目录.md)
-
-## :computer: 操作系统
-
-- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机操作系统%20-%20目录.md)
-- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Linux.md)
-
-## :cloud: 网络
-
-- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机网络%20-%20目录.md)
-- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/HTTP.md)
-- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Socket.md)
-
-## :art: 面向对象
-
-- [设计模式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/设计模式.md)
-- [面向对象思想](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/面向对象思想.md)
-
-## :floppy_disk: 数据库
-
-- [数据库系统原理](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/数据库系统原理.md)
-- [SQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/SQL.md)
-- [Leetcode-Database 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode-Database%20题解.md)
-- [MySQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/MySQL.md)
-- [Redis](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Redis.md)
-
-## :coffee: Java
-
-- [Java 基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20基础.md)
-- [Java 容器](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20容器.md)
-- [Java 并发](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20并发.md)
-- [Java 虚拟机](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20虚拟机.md)
-- [Java I/O](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20IO.md)
-
-## :bulb: 系统设计
-
-- [系统设计基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/系统设计基础.md)
-- [分布式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/分布式.md)
-- [集群](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/集群.md)
-- [攻击技术](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/攻击技术.md)
-- [缓存](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/缓存.md)
-- [消息队列](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/消息队列.md)
-
-## :wrench: 工具
-
-- [Git](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Git.md)
-- [Docker](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Docker.md)
-- [构建工具](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/构建工具.md)
-- [正则表达式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/正则表达式.md)
-
-## :watermelon: 编码实践
-
-- [代码可读性](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码可读性.md)
-- [代码风格规范](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码风格规范.md)
-
-## :memo: 后记
-
-### 内推信息
-
-[Job-Recommend](https://github.com/CyC2018/Job-Recommend)
-
-### QQ 群
-
-为大家提供一个学习交流平台,在这里你可以自由地讨论技术问题。
-
-
-
-### 后端面试指南
-
-
-
-
-
-### 排版
-
-笔记内容按照 [中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines) 进行排版,以保证内容的可读性。
-
-不使用 `![]()` 这种方式来引用图片,而是用 `
` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 [GFM](https://github.github.com/gfm/) 不支持 ` ![]() ` 这种方法让图片居中显示,只能使用 `` 达到居中的效果。
-
-在线排版工具:[Text-Typesetting](https://github.com/CyC2018/Text-Typesetting)。
-
-### 上传方案
-
-为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括提取图片、Markdown 文档转换、Git 同步。进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。
-
-GFM 转换工具:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
-
-### License
-
-本仓库内容将网上的资料随意拼凑而来,除了少部分引用书上和技术文档的原文,其余都是我的原创。在您引用本仓库内容或者对内容进行修改演绎时,请署名并以相同方式共享,谢谢。
-
-
-
-### Logo
-
-Power by [logomakr](https://logomakr.com/).
-
-### 致谢
-
-感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR,请与我联系。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+| 算法 | 操作系统 | 网络 |面向对象| 数据库 | Java |系统设计| 工具 |编码实践| 后记 |
+| :---: | :----: | :---: | :----: | :----: | :----: | :----: | :----: | :----: | :----: |
+| [:pencil2:](#pencil2-算法) | [:computer:](#computer-操作系统) | [:cloud:](#cloud-网络) | [:art:](#art-面向对象) | [:floppy_disk:](#floppy_disk-数据库) |[:coffee:](#coffee-java)| [:bulb:](#bulb-系统设计) |[:wrench:](#wrench-工具)| [:watermelon:](#watermelon-编码实践) |[:memo:](#memo-后记)|
+
+
+
+
+

+
+
+
+
+## :pencil2: 算法
+
+- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/notes/剑指%20Offer%20题解%20-%20目录.md)
+- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20题解%20-%20目录.md)
+- [算法](https://github.com/CyC2018/CS-Notes/blob/master/notes/算法%20-%20目录.md)
+- [字节跳动内推](assets/内推.md)
+
+## :computer: 操作系统
+
+- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/notes/计算机操作系统%20-%20目录.md)
+- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/notes/Linux.md)
+
+## :cloud: 网络
+
+- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/notes/计算机网络%20-%20目录.md)
+- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/notes/HTTP.md)
+- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/notes/Socket.md)
+
+## :floppy_disk: 数据库
+
+- [数据库系统原理](https://github.com/CyC2018/CS-Notes/blob/master/notes/数据库系统原理.md)
+- [SQL 语法](https://github.com/CyC2018/CS-Notes/blob/master/notes/SQL%20语法.md)
+- [SQL 练习](https://github.com/CyC2018/CS-Notes/blob/master/notes/SQL%20练习.md)
+- [MySQL](https://github.com/CyC2018/CS-Notes/blob/master/notes/MySQL.md)
+- [Redis](https://github.com/CyC2018/CS-Notes/blob/master/notes/Redis.md)
+
+## :coffee: Java
+
+- [Java 基础](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20基础.md)
+- [Java 容器](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20容器.md)
+- [Java 并发](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20并发.md)
+- [Java 虚拟机](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20虚拟机.md)
+- [Java I/O](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20IO.md)
+
+## :bulb: 系统设计
+
+- [系统设计基础](https://github.com/CyC2018/CS-Notes/blob/master/notes/系统设计基础.md)
+- [分布式](https://github.com/CyC2018/CS-Notes/blob/master/notes/分布式.md)
+- [集群](https://github.com/CyC2018/CS-Notes/blob/master/notes/集群.md)
+- [攻击技术](https://github.com/CyC2018/CS-Notes/blob/master/notes/攻击技术.md)
+- [缓存](https://github.com/CyC2018/CS-Notes/blob/master/notes/缓存.md)
+- [消息队列](https://github.com/CyC2018/CS-Notes/blob/master/notes/消息队列.md)
+
+## :art: 面向对象
+
+- [面向对象思想](https://github.com/CyC2018/CS-Notes/blob/master/notes/面向对象思想.md)
+- [设计模式](https://github.com/CyC2018/CS-Notes/blob/master/notes/设计模式%20-%20目录.md)
+
+## :wrench: 工具
+
+- [Git](https://github.com/CyC2018/CS-Notes/blob/master/notes/Git.md)
+- [Docker](https://github.com/CyC2018/CS-Notes/blob/master/notes/Docker.md)
+- [构建工具](https://github.com/CyC2018/CS-Notes/blob/master/notes/构建工具.md)
+- [正则表达式](https://github.com/CyC2018/CS-Notes/blob/master/notes/正则表达式.md)
+
+## :watermelon: 编码实践
+
+- [代码可读性](https://github.com/CyC2018/CS-Notes/blob/master/notes/代码可读性.md)
+- [代码风格规范](https://github.com/CyC2018/CS-Notes/blob/master/notes/代码风格规范.md)
+
+## :memo: 后记
+
+### 排版
+
+笔记内容按照 [中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines/blob/master/README.zh-CN.md) 进行排版,以保证内容的可读性。
+
+不使用 `![]()` 这种方式来引用图片,而是用 `
` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 [GFM](https://github.github.com/gfm/) 不支持 ` ![]() ` 这种方法让图片居中显示,只能使用 `` 达到居中的效果。
+
+在线排版工具:[Text-Typesetting](https://github.com/CyC2018/Text-Typesetting)。
+
+### License
+
+本仓库的内容不是将网上的资料随意拼凑而来,除了少部分引用书上和技术文档的原文(这部分内容都在末尾的参考链接中加了出处),其余都是我的原创。在您引用本仓库内容或者对内容进行修改演绎时,请署名并以相同方式共享,谢谢。
+
+转载文章请在开头明显处标明该页面地址,公众号等其它转载请联系 zhengyc101@163.com。
+
+Logo:[logomakr](https://logomakr.com/)
+
+
+
+### 致谢
+
+感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR,请与我联系。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/download-html.png b/assets/download-html.png
new file mode 100644
index 0000000000..75c5ec1a30
Binary files /dev/null and b/assets/download-html.png differ
diff --git a/assets/download-markdown.png b/assets/download-markdown.png
new file mode 100644
index 0000000000..df18175c0d
Binary files /dev/null and b/assets/download-markdown.png differ
diff --git a/assets/download-pdf.png b/assets/download-pdf.png
new file mode 100644
index 0000000000..3b14a633f2
Binary files /dev/null and b/assets/download-pdf.png differ
diff --git a/assets/download.md b/assets/download.md
new file mode 100644
index 0000000000..c28bfa444b
--- /dev/null
+++ b/assets/download.md
@@ -0,0 +1,33 @@
+# 目的
+
+考虑到有部分读者的网络环境较差,有时候在线访问速度很慢,导致阅读体验不佳。另外,PDF 等格式的离线版本相比于网页在线版本更方便做笔记。因此提供离线阅读版本给大家下载。
+
+# 内容
+
+有三种格式的离线版本:PDF、Markdown 和 HTML 。
+
+## PDF
+
+优点是方便做笔记;缺点是不能显示 GIF 图片(所以“剑指 Offer 题解”不建议使用 PDF 进行阅读),以及显示效果不佳。
+
+
+
+## Markdown
+
+优点是能很好地显示 GIF 图片,显示效果也很好;缺点是由于将所有内容整合在同一个文件中,导致实时渲染有点卡顿。
+
+
+
+## HTML
+
+优点是和 Markdown 的显示效果几乎一致,同时不需要 Markdown 的实时渲染,因此浏览速度更快;缺点是目录功能还不是很完善。
+
+如果想在安卓手机端阅读,推荐使用这种格式,将 html 文件和图片文件都复制到手机上,用浏览器打开 html 文件并存成书签,以后就可以快速地离线阅读。
+
+
+
+# 如何下载
+
+离线版本由公众号 **CyC2018** 发布,最新版本也会在上面及时发布,在后台回复 **CyC** 即可获取下载链接。
+
+
diff --git a/assets/group1.png b/assets/group1.png
deleted file mode 100644
index 4615c5f93a..0000000000
Binary files a/assets/group1.png and /dev/null differ
diff --git "a/assets/\344\273\212\346\227\245\345\244\264\346\235\241\346\213\233\350\201\230\346\265\267\346\212\245.png" "b/assets/\344\273\212\346\227\245\345\244\264\346\235\241\346\213\233\350\201\230\346\265\267\346\212\245.png"
new file mode 100644
index 0000000000..3c30d5cb6a
Binary files /dev/null and "b/assets/\344\273\212\346\227\245\345\244\264\346\235\241\346\213\233\350\201\230\346\265\267\346\212\245.png" differ
diff --git "a/assets/\345\205\254\344\274\227\345\217\267.jpg" "b/assets/\345\205\254\344\274\227\345\217\267.jpg"
deleted file mode 100644
index ab57e6b2dd..0000000000
Binary files "a/assets/\345\205\254\344\274\227\345\217\267.jpg" and /dev/null differ
diff --git "a/assets/\345\205\254\344\274\227\345\217\2671.jpg" "b/assets/\345\205\254\344\274\227\345\217\2671.jpg"
deleted file mode 100644
index 14e98bfca0..0000000000
Binary files "a/assets/\345\205\254\344\274\227\345\217\2671.jpg" and /dev/null differ
diff --git "a/assets/\345\205\254\344\274\227\345\217\267\344\272\214\347\273\264\347\240\201-2.png" "b/assets/\345\205\254\344\274\227\345\217\267\344\272\214\347\273\264\347\240\201-2.png"
new file mode 100644
index 0000000000..fec66b80ca
Binary files /dev/null and "b/assets/\345\205\254\344\274\227\345\217\267\344\272\214\347\273\264\347\240\201-2.png" differ
diff --git "a/assets/\345\205\254\344\274\227\345\217\267\346\265\267\346\212\2457.png" "b/assets/\345\205\254\344\274\227\345\217\267\346\265\267\346\212\2457.png"
new file mode 100644
index 0000000000..8f33bd5d20
Binary files /dev/null and "b/assets/\345\205\254\344\274\227\345\217\267\346\265\267\346\212\2457.png" differ
diff --git "a/assets/\345\206\205\346\216\250.md" "b/assets/\345\206\205\346\216\250.md"
new file mode 100644
index 0000000000..2c3fd6fdaa
--- /dev/null
+++ "b/assets/\345\206\205\346\216\250.md"
@@ -0,0 +1,3 @@
+https://job.toutiao.com/s/iVYD4ht
+
+
diff --git "a/assets/\345\260\217\344\270\223\346\240\217.jpg" "b/assets/\345\260\217\344\270\223\346\240\217.jpg"
deleted file mode 100644
index 5c1c880ffd..0000000000
Binary files "a/assets/\345\260\217\344\270\223\346\240\217.jpg" and /dev/null differ
diff --git "a/assets/\347\211\233\345\256\242\347\275\221.png" "b/assets/\347\211\233\345\256\242\347\275\221.png"
deleted file mode 100644
index 02f8199710..0000000000
Binary files "a/assets/\347\211\233\345\256\242\347\275\221.png" and /dev/null differ
diff --git "a/assets/\347\237\245\344\271\216.jpg" "b/assets/\347\237\245\344\271\216.jpg"
deleted file mode 100644
index 92cc845960..0000000000
Binary files "a/assets/\347\237\245\344\271\216.jpg" and /dev/null differ
diff --git "a/assets/\347\237\245\350\257\206\346\230\237\347\220\203.png" "b/assets/\347\237\245\350\257\206\346\230\237\347\220\203.png"
deleted file mode 100644
index 097f6a1cb2..0000000000
Binary files "a/assets/\347\237\245\350\257\206\346\230\237\347\220\203.png" and /dev/null differ
diff --git a/docs/README.md b/docs/README.md
index 96b3365314..756b142235 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,62 +1,2 @@
-- [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
-
-## ✏️ 算法
-
-- [剑指 Offer 题解](notes/剑指%20Offer%20题解%20-%20目录1.md)
-- [Leetcode 题解](notes/Leetcode%20题解%20-%20目录1.md)
-- [算法](notes/算法%20-%20目录1.md)
-- [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
-
-## 💻 操作系统
-
-- [计算机操作系统](notes/计算机操作系统%20-%20目录1.md)
-- [Linux](notes/Linux.md)
-
-## ☁️ 网络
-
-- [计算机网络](notes/计算机网络%20-%20目录1.md)
-- [HTTP](notes/HTTP.md)
-- [Socket](notes/Socket.md)
-
-## 🎨 面向对象
-
-- [设计模式](notes/设计模式.md)
-- [面向对象思想](notes/面向对象思想.md)
-
-## 💾 数据库
-
-- [数据库系统原理](notes/数据库系统原理.md)
-- [SQL](notes/SQL.md)
-- [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md)
-- [MySQL](notes/MySQL.md)
-- [Redis](notes/Redis.md)
-
-## ☕️ Java
-
-- [Java 基础](notes/Java%20基础.md)
-- [Java 容器](notes/Java%20容器.md)
-- [Java 并发](notes/Java%20并发.md)
-- [Java 虚拟机](notes/Java%20虚拟机.md)
-- [Java I/O](notes/Java%20IO.md)
-
-## 💡 系统设计
-
-- [系统设计基础](notes/系统设计基础.md)
-- [分布式](notes/分布式.md)
-- [集群](notes/集群.md)
-- [攻击技术](notes/攻击技术.md)
-- [缓存](notes/缓存.md)
-- [消息队列](notes/消息队列.md)
-
-## 🔧 工具
-
-- [Git](notes/Git.md)
-- [Docker](notes/Docker.md)
-- [正则表达式](notes/正则表达式.md)
-- [构建工具](notes/构建工具.md)
-
-
-
-欢迎关注 公众号 “CyC2018” ,每天发布一道高频基础知识面试题,让你在闲暇时间也能学习进步!公众号也提供了一个学习打卡圈子,记录你每天的学习收获,见证你的成长!
-
-
+# 😃 该网站已迁移至 >>> [www.cyc2018.xyz](http://www.cyc2018.xyz)
+
diff --git a/docs/_404.md b/docs/_404.md
new file mode 100644
index 0000000000..831dac82e5
--- /dev/null
+++ b/docs/_404.md
@@ -0,0 +1 @@
+# 😃 该网站已迁移至 >>> [www.cyc2018.xyz](http://www.cyc2018.xyz)
\ No newline at end of file
diff --git a/docs/_coverpage.md b/docs/_coverpage.md
index 6906cd0d7b..df3eaa882a 100644
--- a/docs/_coverpage.md
+++ b/docs/_coverpage.md
@@ -1,12 +1,11 @@
-
-
-# CS-Notes
-
-- 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。
-
-
-
-[](https://github.com/CyC2018/CS-Notes) [](https://github.com/CyC2018/CS-Notes)
-
-[Get Started](README.md)
-
+
+
+
+- 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。
+
+
+
+[](https://github.com/CyC2018/CS-Notes) [](https://github.com/CyC2018/CS-Notes)
+
+[开始阅读](http://www.cyc2018.xyz)
+
diff --git a/docs/_style/style.css b/docs/_style/style.css
deleted file mode 100644
index 0b87ac126c..0000000000
--- a/docs/_style/style.css
+++ /dev/null
@@ -1,81 +0,0 @@
-/*隐藏头部的目录*/
-#main>ul:nth-child(1) {
- display: none;
-}
-
-#main>ul:nth-child(2) {
- display: none;
-}
-
-.markdown-section h1 {
- margin: 3rem 0 2rem 0;
-}
-
-.markdown-section h2 {
- margin: 2rem 0 1rem;
-}
-
-.content,
-.sidebar,
-.markdown-section,
-body,
-.search input,
-.sidebar-toggle {
- background-color: rgba(243, 242, 238, 1) !important;
-}
-
-body {
- /*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/
-}
-
-.markdown-section>p {
- font-size: 16px !important;
-}
-
-.markdown-section pre>code {
- font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important;
- font-size: .9rem !important;
-
-}
-
-/*.anchor span {
- color: rgb(66, 185, 131);
-}*/
-
-section.cover h1 {
- margin: 0;
-}
-
-body>section>div.cover-main>ul>li>a {
- color: #42b983;
-}
-
-.markdown-section img {
- box-shadow: 7px 9px 10px #aaa !important;
-}
-
-
-pre {
- background-color: #f3f2ee !important;
-}
-
-@media (min-width:600px) {
- pre code {
- /*box-shadow: 2px 1px 20px 2px #aaa;*/
- /*border-radius: 10px !important;*/
- padding-left: 20px !important;
- }
-}
-
-@media (max-width:600px) {
- pre {
- padding-left: 0px !important;
- padding-right: 0px !important;
- }
-}
-
-.markdown-section pre {
- padding-left: 0 !important;
- padding-right: 0px !important;
- box-shadow: 2px 1px 20px 2px #aaa;
-}
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
index 3a23ed3ab1..c810d4c988 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,397 +1,440 @@
-
-
-
-
-
- CS-Notes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ CS-Notes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/notes/Docker.md b/docs/notes/Docker.md
deleted file mode 100644
index b0945c54c3..0000000000
--- a/docs/notes/Docker.md
+++ /dev/null
@@ -1,97 +0,0 @@
-
-* [一、解决的问题](#一解决的问题)
-* [二、与虚拟机的比较](#二与虚拟机的比较)
-* [三、优势](#三优势)
-* [四、使用场景](#四使用场景)
-* [五、镜像与容器](#五镜像与容器)
-* [参考资料](#参考资料)
-
-
-
-# 一、解决的问题
-
-由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。
-
-Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其他机器中。
-
-
-
-# 二、与虚拟机的比较
-
-虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
-
-
-
-
-
-## 启动速度
-
-启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢;
-
-而启动 Docker 相当于启动宿主操作系统上的一个进程。
-
-## 占用资源
-
-虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU,一台机器只能开启几十个的虚拟机。
-
-而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
-
-# 三、优势
-
-除了启动速度快以及占用资源少之外,Docker 具有以下优势:
-
-## 更容易迁移
-
-提供一致性的运行环境,可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
-
-## 更容易维护
-
-使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。
-
-## 更容易扩展
-
-可以使用基础镜像进一步扩展得到新的镜像,并且官方和开源社区提供了大量的镜像,通过扩展这些镜像可以非常容易得到我们想要的镜像。
-
-# 四、使用场景
-
-## 持续集成
-
-持续集成指的是频繁地将代码集成到主干上,这样能够更快地发现错误。
-
-Docker 具有轻量级以及隔离性的特点,在将代码集成到一个 Docker 中不会对其它 Docker 产生影响。
-
-## 提供可伸缩的云服务
-
-根据应用的负载情况,可以很容易地增加或者减少 Docker。
-
-## 搭建微服务架构
-
-Docker 轻量级的特点使得它很适合用于部署、维护、组合微服务。
-
-# 五、镜像与容器
-
-镜像是一种静态的结构,可以看成面向对象里面的类,而容器是镜像的一个实例。
-
-镜像包含着容器运行时所需要的代码以及其它组件,它是一种分层结构,每一层都是只读的(read-only layers)。构建镜像时,会一层一层构建,前一层是后一层的基础。镜像的这种分层存储结构很适合镜像的复用以及定制。
-
-构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。
-
-
-
-# 参考资料
-
-- [DOCKER 101: INTRODUCTION TO DOCKER WEBINAR RECAP](https://blog.docker.com/2017/08/docker-101-introduction-docker-webinar-recap/)
-- [Docker 入门教程](http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
-- [Docker container vs Virtual machine](http://www.bogotobogo.com/DevOps/Docker/Docker_Container_vs_Virtual_Machine.php)
-- [How to Create Docker Container using Dockerfile](https://linoxide.com/linux-how-to/dockerfile-create-docker-container/)
-- [理解 Docker(2):Docker 镜像](http://www.cnblogs.com/sammyliu/p/5877964.html)
-- [为什么要使用 Docker?](https://yeasy.gitbooks.io/docker_practice/introduction/why.html)
-- [What is Docker](https://www.docker.com/what-docker)
-- [持续集成是什么?](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html)
-
-
-
-
-
-欢迎关注公众号,获取最新文章!
-
diff --git a/docs/notes/Git.md b/docs/notes/Git.md
deleted file mode 100644
index a728f27f5c..0000000000
--- a/docs/notes/Git.md
+++ /dev/null
@@ -1,166 +0,0 @@
-
-* [集中式与分布式](#集中式与分布式)
-* [中心服务器](#中心服务器)
-* [工作流](#工作流)
-* [分支实现](#分支实现)
-* [冲突](#冲突)
-* [Fast forward](#fast-forward)
-* [分支管理策略](#分支管理策略)
-* [储藏(Stashing)](#储藏stashing)
-* [SSH 传输设置](#ssh-传输设置)
-* [.gitignore 文件](#gitignore-文件)
-* [Git 命令一览](#git-命令一览)
-* [参考资料](#参考资料)
-
-
-
-# 集中式与分布式
-
-Git 属于分布式版本控制系统,而 SVN 属于集中式。
-
-
-
-集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。
-
-集中式版本控制有安全性问题,当中心服务器挂了所有人都没办法工作了。
-
-集中式版本控制需要连网才能工作,如果网速过慢,那么提交一个文件的会慢的无法让人忍受。而分布式版本控制不需要连网就能工作。
-
-分布式版本控制新建分支、合并分支操作速度非常快,而集中式版本控制新建一个分支相当于复制一份完整代码。
-
-# 中心服务器
-
-中心服务器用来交换每个用户的修改,没有中心服务器也能工作,但是中心服务器能够 24 小时保持开机状态,这样就能更方便的交换修改。
-
-Github 就是一个中心服务器。
-
-# 工作流
-
-新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git,它属于 Git 的版本库。
-
-Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 中存有所有分支,使用一个 HEAD 指针指向当前分支。
-
-
-
-- git add files 把文件的修改添加到暂存区
-- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
-- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
-- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
-
-
-
-可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
-
-- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
-- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
-
-
-
-# 分支实现
-
-使用指针将每个提交连接成一条时间线,HEAD 指针指向当前分支指针。
-
-
-
-新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
-
-
-
-每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
-
-
-
-合并分支也只需要改变指针即可。
-
-
-
-# 冲突
-
-当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
-
-
-
-Git 会使用 <<<<<<< ,======= ,>>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
-
-```
-<<<<<<< HEAD
-Creating a new branch is quick & simple.
-=======
-Creating a new branch is quick AND simple.
->>>>>>> feature1
-```
-
-# Fast forward
-
-"快进式合并"(fast-farward merge),会直接将 master 分支指向合并的分支,这种模式下进行分支合并会丢失分支信息,也就不能在分支历史上看出分支信息。
-
-可以在合并时加上 --no-ff 参数来禁用 Fast forward 模式,并且加上 -m 参数让合并时产生一个新的 commit。
-
-```
-$ git merge --no-ff -m "merge with no-ff" dev
-```
-
-
-
-# 分支管理策略
-
-master 分支应该是非常稳定的,只用来发布新版本;
-
-日常开发在开发分支 dev 上进行。
-
-
-
-# 储藏(Stashing)
-
-在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。
-
-可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈上,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。
-
-```
-$ git stash
-Saved working directory and index state \ "WIP on master: 049d078 added the index file"
-HEAD is now at 049d078 added the index file (To restore them type "git stash apply")
-```
-
-该功能可以用于 bug 分支的实现。如果当前正在 dev 分支上进行开发,但是此时 master 上有个 bug 需要修复,但是 dev 分支上的开发还未完成,不想立即提交。在新建 bug 分支并切换到 bug 分支之前就需要使用 git stash 将 dev 分支的未提交修改储藏起来。
-
-# SSH 传输设置
-
-Git 仓库和 Github 中心仓库之间的传输是通过 SSH 加密。
-
-如果工作区下没有 .ssh 目录,或者该目录下没有 id_rsa 和 id_rsa.pub 这两个文件,可以通过以下命令来创建 SSH Key:
-
-```
-$ ssh-keygen -t rsa -C "youremail@example.com"
-```
-
-然后把公钥 id_rsa.pub 的内容复制到 Github "Account settings" 的 SSH Keys 中。
-
-# .gitignore 文件
-
-忽略以下文件:
-
-- 操作系统自动生成的文件,比如缩略图;
-- 编译生成的中间文件,比如 Java 编译产生的 .class 文件;
-- 自己的敏感信息,比如存放口令的配置文件。
-
-不需要全部自己编写,可以到 [https://github.com/github/gitignore](https://github.com/github/gitignore) 中进行查询。
-
-# Git 命令一览
-
-
-
-比较详细的地址:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
-
-# 参考资料
-
-- [Git - 简明指南](http://rogerdudler.github.io/git-guide/index.zh.html)
-- [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
-- [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
-- [Learn Git Branching](https://learngitbranching.js.org/)
-
-
-
-
-欢迎关注公众号,获取最新文章!
-
diff --git a/docs/notes/HTTP.md b/docs/notes/HTTP.md
deleted file mode 100644
index 3bcdafb813..0000000000
--- a/docs/notes/HTTP.md
+++ /dev/null
@@ -1,885 +0,0 @@
-
-* [一 、基础概念](#一-基础概念)
- * [URI](#uri)
- * [请求和响应报文](#请求和响应报文)
-* [二、HTTP 方法](#二http-方法)
- * [GET](#get)
- * [HEAD](#head)
- * [POST](#post)
- * [PUT](#put)
- * [PATCH](#patch)
- * [DELETE](#delete)
- * [OPTIONS](#options)
- * [CONNECT](#connect)
- * [TRACE](#trace)
-* [三、HTTP 状态码](#三http-状态码)
- * [1XX 信息](#1xx-信息)
- * [2XX 成功](#2xx-成功)
- * [3XX 重定向](#3xx-重定向)
- * [4XX 客户端错误](#4xx-客户端错误)
- * [5XX 服务器错误](#5xx-服务器错误)
-* [四、HTTP 首部](#四http-首部)
- * [通用首部字段](#通用首部字段)
- * [请求首部字段](#请求首部字段)
- * [响应首部字段](#响应首部字段)
- * [实体首部字段](#实体首部字段)
-* [五、具体应用](#五具体应用)
- * [连接管理](#连接管理)
- * [Cookie](#cookie)
- * [缓存](#缓存)
- * [内容协商](#内容协商)
- * [内容编码](#内容编码)
- * [范围请求](#范围请求)
- * [分块传输编码](#分块传输编码)
- * [多部分对象集合](#多部分对象集合)
- * [虚拟主机](#虚拟主机)
- * [通信数据转发](#通信数据转发)
-* [六、HTTPS](#六https)
- * [加密](#加密)
- * [认证](#认证)
- * [完整性保护](#完整性保护)
- * [HTTPS 的缺点](#https-的缺点)
-* [七、HTTP/2.0](#七http20)
- * [HTTP/1.x 缺陷](#http1x-缺陷)
- * [二进制分帧层](#二进制分帧层)
- * [服务端推送](#服务端推送)
- * [首部压缩](#首部压缩)
-* [八、HTTP/1.1 新特性](#八http11-新特性)
-* [九、GET 和 POST 比较](#九get-和-post-比较)
- * [作用](#作用)
- * [参数](#参数)
- * [安全](#安全)
- * [幂等性](#幂等性)
- * [可缓存](#可缓存)
- * [XMLHttpRequest](#xmlhttprequest)
-* [参考资料](#参考资料)
-
-
-
-# 一 、基础概念
-
-## URI
-
-URI 包含 URL 和 URN。
-
-
-
-## 请求和响应报文
-
-### 1. 请求报文
-
-
-
-### 2. 响应报文
-
-
-
-# 二、HTTP 方法
-
-客户端发送的 **请求报文** 第一行为请求行,包含了方法字段。
-
-## GET
-
-> 获取资源
-
-当前网络请求中,绝大部分使用的是 GET 方法。
-
-## HEAD
-
-> 获取报文首部
-
-和 GET 方法类似,但是不返回报文实体主体部分。
-
-主要用于确认 URL 的有效性以及资源更新的日期时间等。
-
-## POST
-
-> 传输实体主体
-
-POST 主要用来传输数据,而 GET 主要用来获取资源。
-
-更多 POST 与 GET 的比较请见第九章。
-
-## PUT
-
-> 上传文件
-
-由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
-
-```html
-PUT /new.html HTTP/1.1
-Host: example.com
-Content-type: text/html
-Content-length: 16
-
-New File
-```
-
-## PATCH
-
-> 对资源进行部分修改
-
-PUT 也可以用于修改资源,但是只能完全替代原始资源,PATCH 允许部分修改。
-
-```html
-PATCH /file.txt HTTP/1.1
-Host: www.example.com
-Content-Type: application/example
-If-Match: "e0023aa4e"
-Content-Length: 100
-
-[description of changes]
-```
-
-## DELETE
-
-> 删除文件
-
-与 PUT 功能相反,并且同样不带验证机制。
-
-```html
-DELETE /file.html HTTP/1.1
-```
-
-## OPTIONS
-
-> 查询支持的方法
-
-查询指定的 URL 能够支持的方法。
-
-会返回 `Allow: GET, POST, HEAD, OPTIONS` 这样的内容。
-
-## CONNECT
-
-> 要求在与代理服务器通信时建立隧道
-
-使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
-
-```html
-CONNECT www.example.com:443 HTTP/1.1
-```
-
-
-
-## TRACE
-
-> 追踪路径
-
-服务器会将通信路径返回给客户端。
-
-发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。
-
-通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪)。
-
-# 三、HTTP 状态码
-
-服务器返回的 **响应报文** 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
-
-| 状态码 | 类别 | 含义 |
-| :---: | :---: | :---: |
-| 1XX | Informational(信息性状态码) | 接收的请求正在处理 |
-| 2XX | Success(成功状态码) | 请求正常处理完毕 |
-| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
-| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
-| 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
-
-## 1XX 信息
-
-- **100 Continue** :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
-
-## 2XX 成功
-
-- **200 OK**
-
-- **204 No Content** :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
-
-- **206 Partial Content** :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。
-
-## 3XX 重定向
-
-- **301 Moved Permanently** :永久性重定向
-
-- **302 Found** :临时性重定向
-
-- **303 See Other** :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
-
-- 注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
-
-- **304 Not Modified** :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
-
-- **307 Temporary Redirect** :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
-
-## 4XX 客户端错误
-
-- **400 Bad Request** :请求报文中存在语法错误。
-
-- **401 Unauthorized** :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
-
-- **403 Forbidden** :请求被拒绝。
-
-- **404 Not Found**
-
-## 5XX 服务器错误
-
-- **500 Internal Server Error** :服务器正在执行请求时发生错误。
-
-- **503 Service Unavailable** :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
-
-# 四、HTTP 首部
-
-有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。
-
-各种首部字段及其含义如下(不需要全记,仅供查阅):
-
-## 通用首部字段
-
-| 首部字段名 | 说明 |
-| :--: | :--: |
-| Cache-Control | 控制缓存的行为 |
-| Connection | 控制不再转发给代理的首部字段、管理持久连接|
-| Date | 创建报文的日期时间 |
-| Pragma | 报文指令 |
-| Trailer | 报文末端的首部一览 |
-| Transfer-Encoding | 指定报文主体的传输编码方式 |
-| Upgrade | 升级为其他协议 |
-| Via | 代理服务器的相关信息 |
-| Warning | 错误通知 |
-
-## 请求首部字段
-
-| 首部字段名 | 说明 |
-| :--: | :--: |
-| Accept | 用户代理可处理的媒体类型 |
-| Accept-Charset | 优先的字符集 |
-| Accept-Encoding | 优先的内容编码 |
-| Accept-Language | 优先的语言(自然语言) |
-| Authorization | Web 认证信息 |
-| Expect | 期待服务器的特定行为 |
-| From | 用户的电子邮箱地址 |
-| Host | 请求资源所在服务器 |
-| If-Match | 比较实体标记(ETag) |
-| If-Modified-Since | 比较资源的更新时间 |
-| If-None-Match | 比较实体标记(与 If-Match 相反) |
-| If-Range | 资源未更新时发送实体 Byte 的范围请求 |
-| If-Unmodified-Since | 比较资源的更新时间(与 If-Modified-Since 相反) |
-| Max-Forwards | 最大传输逐跳数 |
-| Proxy-Authorization | 代理服务器要求客户端的认证信息 |
-| Range | 实体的字节范围请求 |
-| Referer | 对请求中 URI 的原始获取方 |
-| TE | 传输编码的优先级 |
-| User-Agent | HTTP 客户端程序的信息 |
-
-## 响应首部字段
-
-| 首部字段名 | 说明 |
-| :--: | :--: |
-| Accept-Ranges | 是否接受字节范围请求 |
-| Age | 推算资源创建经过时间 |
-| ETag | 资源的匹配信息 |
-| Location | 令客户端重定向至指定 URI |
-| Proxy-Authenticate | 代理服务器对客户端的认证信息 |
-| Retry-After | 对再次发起请求的时机要求 |
-| Server | HTTP 服务器的安装信息 |
-| Vary | 代理服务器缓存的管理信息 |
-| WWW-Authenticate | 服务器对客户端的认证信息 |
-
-## 实体首部字段
-
-| 首部字段名 | 说明 |
-| :--: | :--: |
-| Allow | 资源可支持的 HTTP 方法 |
-| Content-Encoding | 实体主体适用的编码方式 |
-| Content-Language | 实体主体的自然语言 |
-| Content-Length | 实体主体的大小 |
-| Content-Location | 替代对应资源的 URI |
-| Content-MD5 | 实体主体的报文摘要 |
-| Content-Range | 实体主体的位置范围 |
-| Content-Type | 实体主体的媒体类型 |
-| Expires | 实体主体过期的日期时间 |
-| Last-Modified | 资源的最后修改日期时间 |
-
-# 五、具体应用
-
-## 连接管理
-
-
-
-### 1. 短连接与长连接
-
-当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。
-
-长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。
-
-- 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 `Connection : close`;
-- 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 `Connection : Keep-Alive`。
-
-### 2. 流水线
-
-默认情况下,HTTP 请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。
-
-流水线是在同一条长连接上发出连续的请求,而不用等待响应返回,这样可以避免连接延迟。
-
-## Cookie
-
-HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。
-
-Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。
-
-Cookie 曾一度用于客户端数据的存储,因为当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API(本地存储和会话存储)或 IndexedDB。
-
-### 1. 用途
-
-- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
-- 个性化设置(如用户自定义设置、主题等)
-- 浏览器行为跟踪(如跟踪分析用户行为等)
-
-### 2. 创建过程
-
-服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。
-
-```html
-HTTP/1.0 200 OK
-Content-type: text/html
-Set-Cookie: yummy_cookie=choco
-Set-Cookie: tasty_cookie=strawberry
-
-[page content]
-```
-
-客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。
-
-```html
-GET /sample_page.html HTTP/1.1
-Host: www.example.org
-Cookie: yummy_cookie=choco; tasty_cookie=strawberry
-```
-
-### 3. 分类
-
-- 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
-- 持久性 Cookie:指定一个特定的过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。
-
-```html
-Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
-```
-
-### 4. 作用域
-
-Domain 标识指定了哪些主机可以接受 Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了 Domain,则一般包含子域名。例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如 developer.mozilla.org)。
-
-Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。例如,设置 Path=/docs,则以下地址都会匹配:
-
-- /docs
-- /docs/Web/
-- /docs/Web/HTTP
-
-### 5. JavaScript
-
-通过 `document.cookie` 属性可创建新的 Cookie,也可通过该属性访问非 HttpOnly 标记的 Cookie。
-
-```html
-document.cookie = "yummy_cookie=choco";
-document.cookie = "tasty_cookie=strawberry";
-console.log(document.cookie);
-```
-
-### 6. HttpOnly
-
-标记为 HttpOnly 的 Cookie 不能被 JavaScript 脚本调用。跨站脚本攻击 (XSS) 常常使用 JavaScript 的 `document.cookie` API 窃取用户的 Cookie 信息,因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。
-
-```html
-Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
-```
-
-### 7. Secure
-
-标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障。
-
-### 8. Session
-
-除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。
-
-Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。
-
-使用 Session 维护用户登录状态的过程如下:
-
-- 用户进行登录时,用户提交包含用户名和密码的表单,放入 HTTP 请求报文中;
-- 服务器验证该用户名和密码,如果正确则把用户信息存储到 Redis 中,它在 Redis 中的 Key 称为 Session ID;
-- 服务器返回的响应报文的 Set-Cookie 首部字段包含了这个 Session ID,客户端收到响应报文之后将该 Cookie 值存入浏览器中;
-- 客户端之后对同一个服务器进行请求时会包含该 Cookie 值,服务器收到之后提取出 Session ID,从 Redis 中取出用户信息,继续之前的业务操作。
-
-应该注意 Session ID 的安全性问题,不能让它被恶意攻击者轻易获取,那么就不能产生一个容易被猜到的 Session ID 值。此外,还需要经常重新生成 Session ID。在对安全性要求极高的场景下,例如转账等操作,除了使用 Session 管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证码等方式。
-
-### 9. 浏览器禁用 Cookie
-
-此时无法使用 Cookie 来保存用户信息,只能使用 Session。除此之外,不能再将 Session ID 存放到 Cookie 中,而是使用 URL 重写技术,将 Session ID 作为 URL 的参数进行传递。
-
-### 10. Cookie 与 Session 选择
-
-- Cookie 只能存储 ASCII 码字符串,而 Session 则可以存取任何类型的数据,因此在考虑数据复杂性时首选 Session;
-- Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;
-- 对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。
-
-## 缓存
-
-### 1. 优点
-
-- 缓解服务器压力;
-- 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存在地理位置上也有可能比源服务器来得近,例如浏览器缓存。
-
-### 2. 实现方法
-
-- 让代理服务器进行缓存;
-- 让客户端浏览器进行缓存。
-
-### 3. Cache-Control
-
-HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。
-
-**3.1 禁止进行缓存**
-
-no-store 指令规定不能对请求或响应的任何一部分进行缓存。
-
-```html
-Cache-Control: no-store
-```
-
-**3.2 强制确认缓存**
-
-no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效才将能使用该缓存对客户端的请求进行响应。
-
-```html
-Cache-Control: no-cache
-```
-
-**3.3 私有缓存和公共缓存**
-
-private 指令规定了将资源作为私有缓存,只能被单独用户所使用,一般存储在用户浏览器中。
-
-```html
-Cache-Control: private
-```
-
-public 指令规定了将资源作为公共缓存,可以被多个用户所使用,一般存储在代理服务器中。
-
-```html
-Cache-Control: public
-```
-
-**3.4 缓存过期机制**
-
-max-age 指令出现在请求报文中,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。
-
-max-age 指令出现在响应报文中,表示缓存资源在缓存服务器中保存的时间。
-
-```html
-Cache-Control: max-age=31536000
-```
-
-Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。
-
-```html
-Expires: Wed, 04 Jul 2012 08:26:05 GMT
-```
-
-- 在 HTTP/1.1 中,会优先处理 max-age 指令;
-- 在 HTTP/1.0 中,max-age 指令会被忽略掉。
-
-### 4. 缓存验证
-
-需要先了解 ETag 首部字段的含义,它是资源的唯一标识。URL 不能唯一表示资源,例如 `http://www.google.com/` 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。
-
-```html
-ETag: "82e22293907ce725faf67773957acd12"
-```
-
-可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。
-
-```html
-If-None-Match: "82e22293907ce725faf67773957acd12"
-```
-
-Last-Modified 首部字段也可以用于缓存验证,它包含在源服务器发送的响应报文中,指示源服务器对资源的最后修改时间。但是它是一种弱校验器,因为只能精确到一秒,所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 OK。如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的 304 Not Modified 响应。
-
-```html
-Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
-```
-
-```html
-If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
-```
-
-## 内容协商
-
-通过内容协商返回最合适的内容,例如根据浏览器的默认语言选择返回中文界面还是英文界面。
-
-### 1. 类型
-
-**1.1 服务端驱动型**
-
-客户端设置特定的 HTTP 首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language,服务器根据这些字段返回特定的资源。
-
-它存在以下问题:
-
-- 服务器很难知道客户端浏览器的全部信息;
-- 客户端提供的信息相当冗长(HTTP/2 协议的首部压缩机制缓解了这个问题),并且存在隐私风险(HTTP 指纹识别技术);
-- 给定的资源需要返回不同的展现形式,共享缓存的效率会降低,而服务器端的实现会越来越复杂。
-
-**1.2 代理驱动型**
-
-服务器返回 300 Multiple Choices 或者 406 Not Acceptable,客户端从中选出最合适的那个资源。
-
-### 2. Vary
-
-```html
-Vary: Accept-Language
-```
-
-在使用内容协商的情况下,只有当缓存服务器中的缓存满足内容协商条件时,才能使用该缓存,否则应该向源服务器请求该资源。
-
-例如,一个客户端发送了一个包含 Accept-Language 首部字段的请求之后,源服务器返回的响应包含 `Vary: Accept-Language` 内容,缓存服务器对这个响应进行缓存之后,在客户端下一次访问同一个 URL 资源,并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存。
-
-## 内容编码
-
-内容编码将实体主体进行压缩,从而减少传输的数据量。
-
-常用的内容编码有:gzip、compress、deflate、identity。
-
-浏览器发送 Accept-Encoding 首部,其中包含有它所支持的压缩算法,以及各自的优先级。服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法。由于该内容协商过程是基于编码类型来选择资源的展现形式的,在响应的 Vary 首部至少要包含 Content-Encoding。
-
-## 范围请求
-
-如果网络出现中断,服务器只发送了一部分数据,范围请求可以使得客户端只请求服务器未发送的那部分数据,从而避免服务器重新发送所有数据。
-
-### 1. Range
-
-在请求报文中添加 Range 首部字段指定请求的范围。
-
-```html
-GET /z4d4kWk.jpg HTTP/1.1
-Host: i.imgur.com
-Range: bytes=0-1023
-```
-
-请求成功的话服务器返回的响应包含 206 Partial Content 状态码。
-
-```html
-HTTP/1.1 206 Partial Content
-Content-Range: bytes 0-1023/146515
-Content-Length: 1024
-...
-(binary content)
-```
-
-### 2. Accept-Ranges
-
-响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求,可以处理使用 bytes,否则使用 none。
-
-```html
-Accept-Ranges: bytes
-```
-
-### 3. 响应状态码
-
-- 在请求成功的情况下,服务器会返回 206 Partial Content 状态码。
-- 在请求的范围越界的情况下,服务器会返回 416 Requested Range Not Satisfiable 状态码。
-- 在不支持范围请求的情况下,服务器会返回 200 OK 状态码。
-
-## 分块传输编码
-
-Chunked Transfer Coding,可以把数据分割成多块,让浏览器逐步显示页面。
-
-## 多部分对象集合
-
-一份报文主体内可含有多种类型的实体同时发送,每个部分之间用 boundary 字段定义的分隔符进行分隔,每个部分都可以有首部字段。
-
-例如,上传多个表单时可以使用如下方式:
-
-```html
-Content-Type: multipart/form-data; boundary=AaB03x
-
---AaB03x
-Content-Disposition: form-data; name="submit-name"
-
-Larry
---AaB03x
-Content-Disposition: form-data; name="files"; filename="file1.txt"
-Content-Type: text/plain
-
-... contents of file1.txt ...
---AaB03x--
-```
-
-## 虚拟主机
-
-HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器。
-
-## 通信数据转发
-
-### 1. 代理
-
-代理服务器接受客户端的请求,并且转发给其它服务器。
-
-使用代理的主要目的是:
-
-- 缓存
-- 负载均衡
-- 网络访问控制
-- 访问日志记录
-
-代理服务器分为正向代理和反向代理两种:
-
-- 用户察觉得到正向代理的存在。
-
-
-
-- 而反向代理一般位于内部网络中,用户察觉不到。
-
-
-
-### 2. 网关
-
-与代理服务器不同的是,网关服务器会将 HTTP 转化为其它协议进行通信,从而请求其它非 HTTP 服务器的服务。
-
-### 3. 隧道
-
-使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。
-
-# 六、HTTPS
-
-HTTP 有以下安全性问题:
-
-- 使用明文进行通信,内容可能会被窃听;
-- 不验证通信方的身份,通信方的身份有可能遭遇伪装;
-- 无法证明报文的完整性,报文有可能遭篡改。
-
-HTTPS 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是说 HTTPS 使用了隧道进行通信。
-
-通过使用 SSL,HTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
-
-
-
-## 加密
-
-### 1. 对称密钥加密
-
-对称密钥加密(Symmetric-Key Encryption),加密和解密使用同一密钥。
-
-- 优点:运算速度快;
-- 缺点:无法安全地将密钥传输给通信方。
-
-
-
-### 2.非对称密钥加密
-
-非对称密钥加密,又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥。
-
-公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。
-
-非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确。
-
-- 优点:可以更安全地将公开密钥传输给通信发送方;
-- 缺点:运算速度慢。
-
-
-
-### 3. HTTPS 采用的加密方式
-
-HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
-
-
-
-## 认证
-
-通过使用 **证书** 来对通信方进行认证。
-
-数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。
-
-服务器的运营人员向 CA 提出公开密钥的申请,CA 在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起。
-
-进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
-
-
-
-## 完整性保护
-
-SSL 提供报文摘要功能来进行完整性保护。
-
-HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。
-
-HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。
-
-## HTTPS 的缺点
-
-- 因为需要进行加密解密等过程,因此速度会更慢;
-- 需要支付证书授权的高额费用。
-
-# 七、HTTP/2.0
-
-## HTTP/1.x 缺陷
-
-HTTP/1.x 实现简单是以牺牲性能为代价的:
-
-- 客户端需要使用多个连接才能实现并发和缩短延迟;
-- 不会压缩请求和响应首部,从而导致不必要的网络流量;
-- 不支持有效的资源优先级,致使底层 TCP 连接的利用率低下。
-
-## 二进制分帧层
-
-HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
-
-
-
-在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
-
-- 一个数据流(Stream)都有一个唯一标识符和可选的优先级信息,用于承载双向信息。
-- 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
-- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
-
-
-
-## 服务端推送
-
-HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
-
-
-
-## 首部压缩
-
-HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。
-
-HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输。
-
-不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
-
-
-
-# 八、HTTP/1.1 新特性
-
-详细内容请见上文
-
-- 默认是长连接
-- 支持流水线
-- 支持同时打开多个 TCP 连接
-- 支持虚拟主机
-- 新增状态码 100
-- 支持分块传输编码
-- 新增缓存处理指令 max-age
-
-# 九、GET 和 POST 比较
-
-## 作用
-
-GET 用于获取资源,而 POST 用于传输实体主体。
-
-## 参数
-
-GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看。
-
-因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参考支持标准字符集。
-
-```
-GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
-```
-
-```
-POST /test/demo_form.asp HTTP/1.1
-Host: w3schools.com
-name1=value1&name2=value2
-```
-
-## 安全
-
-安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。
-
-GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
-
-安全的方法除了 GET 之外还有:HEAD、OPTIONS。
-
-不安全的方法除了 POST 之外还有 PUT、DELETE。
-
-## 幂等性
-
-幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。
-
-所有的安全方法也都是幂等的。
-
-在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。
-
-GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的:
-
-```
-GET /pageX HTTP/1.1
-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 -> Adds a 1nd row
-POST /add_row HTTP/1.1 -> Adds a 2nd row
-POST /add_row HTTP/1.1 -> Adds a 3rd row
-```
-
-DELETE /idX/delete HTTP/1.1 是幂等的,即便不同的请求接收到的状态码不一样:
-
-```
-DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists
-DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted
-DELETE /idX/delete HTTP/1.1 -> Returns 404
-```
-
-## 可缓存
-
-如果要对响应进行缓存,需要满足以下条件:
-
-- 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。
-- 响应报文的状态码是可缓存的,包括:200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。
-- 响应报文的 Cache-Control 首部字段没有指定不进行缓存。
-
-## XMLHttpRequest
-
-为了阐述 POST 和 GET 的另一个区别,需要先了解 XMLHttpRequest:
-
-> XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。XMLHttpRequest 在 AJAX 中被大量使用。
-
-- 在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做,例如火狐就不会。
-- 而 GET 方法 Header 和 Data 会一起发送。
-
-# 参考资料
-
-- 上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014.
-- [MDN : HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)
-- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
-- [htmlspecialchars](http://php.net/manual/zh/function.htmlspecialchars.php)
-- [Difference between file URI and URL in java](http://java2db.com/java-io/how-to-get-and-the-difference-between-file-uri-and-url-in-java)
-- [How to Fix SQL Injection Using Java PreparedStatement & CallableStatement](https://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement)
-- [浅谈 HTTP 中 Get 与 Post 的区别](https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html)
-- [Are http:// and www really necessary?](https://www.webdancers.com/are-http-and-www-necesary/)
-- [HTTP (HyperText Transfer Protocol)](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html)
-- [Web-VPN: Secure Proxies with SPDY & Chrome](https://www.igvita.com/2011/12/01/web-vpn-secure-proxies-with-spdy-chrome/)
-- [File:HTTP persistent connection.svg](http://en.wikipedia.org/wiki/File:HTTP_persistent_connection.svg)
-- [Proxy server](https://en.wikipedia.org/wiki/Proxy_server)
-- [What Is This HTTPS/SSL Thing And Why Should You Care?](https://www.x-cart.com/blog/what-is-https-and-ssl.html)
-- [What is SSL Offloading?](https://securebox.comodo.com/ssl-sniffing/ssl-offloading/)
-- [Sun Directory Server Enterprise Edition 7.0 Reference - Key Encryption](https://docs.oracle.com/cd/E19424-01/820-4811/6ng8i26bn/index.html)
-- [An Introduction to Mutual SSL Authentication](https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication)
-- [The Difference Between URLs and URIs](https://danielmiessler.com/study/url-uri/)
-- [Cookie 与 Session 的区别](https://juejin.im/entry/5766c29d6be3ff006a31b84e#comment)
-- [COOKIE 和 SESSION 有什么区别](https://www.zhihu.com/question/19786827)
-- [Cookie/Session 的机制与安全](https://harttle.land/2015/08/10/cookie-session.html)
-- [HTTPS 证书原理](https://shijianan.com/2017/06/11/https/)
-- [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 (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)
-- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
-- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
-
-
-
-
-欢迎关注公众号,获取最新文章!
-
diff --git "a/docs/notes/Java \345\237\272\347\241\200.md" "b/docs/notes/Java \345\237\272\347\241\200.md"
deleted file mode 100644
index 0072eec972..0000000000
--- "a/docs/notes/Java \345\237\272\347\241\200.md"
+++ /dev/null
@@ -1,1402 +0,0 @@
-
-* [一、数据类型](#一数据类型)
- * [基本类型](#基本类型)
- * [包装类型](#包装类型)
- * [缓存池](#缓存池)
-* [二、String](#二string)
- * [概览](#概览)
- * [不可变的好处](#不可变的好处)
- * [String, StringBuffer and StringBuilder](#string,-stringbuffer-and-stringbuilder)
- * [String Pool](#string-pool)
- * [new String("abc")](#new-string"abc")
-* [三、运算](#三运算)
- * [参数传递](#参数传递)
- * [float 与 double](#float-与-double)
- * [隐式类型转换](#隐式类型转换)
- * [switch](#switch)
-* [四、继承](#四继承)
- * [访问权限](#访问权限)
- * [抽象类与接口](#抽象类与接口)
- * [super](#super)
- * [重写与重载](#重写与重载)
-* [五、Object 通用方法](#五object-通用方法)
- * [概览](#概览)
- * [equals()](#equals)
- * [hashCode()](#hashcode)
- * [toString()](#tostring)
- * [clone()](#clone)
-* [六、关键字](#六关键字)
- * [final](#final)
- * [static](#static)
-* [七、反射](#七反射)
-* [八、异常](#八异常)
-* [九、泛型](#九泛型)
-* [十、注解](#十注解)
-* [十一、特性](#十一特性)
- * [Java 各版本的新特性](#java-各版本的新特性)
- * [Java 与 C++ 的区别](#java-与-c-的区别)
- * [JRE or JDK](#jre-or-jdk)
-* [参考资料](#参考资料)
-
-
-
-# 一、数据类型
-
-## 基本类型
-
-- byte/8
-- char/16
-- short/16
-- int/32
-- float/32
-- long/64
-- double/64
-- boolean/\~
-
-boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 并不直接支持 boolean 数组,而是使用 byte 数组来表示 int 数组。
-
-- [Primitive Data Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
-- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
-
-## 包装类型
-
-基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
-
-```java
-Integer x = 2; // 装箱
-int y = x; // 拆箱
-```
-
-## 缓存池
-
-new Integer(123) 与 Integer.valueOf(123) 的区别在于:
-
-- new Integer(123) 每次都会新建一个对象;
-- Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
-
-```java
-Integer x = new Integer(123);
-Integer y = new Integer(123);
-System.out.println(x == y); // false
-Integer z = Integer.valueOf(123);
-Integer k = Integer.valueOf(123);
-System.out.println(z == k); // true
-```
-
-valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。
-
-```java
-public static Integer valueOf(int i) {
- if (i >= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
-}
-```
-
-在 Java 8 中,Integer 缓存池的大小默认为 -128\~127。
-
-```java
-static final int low = -128;
-static final int high;
-static final Integer cache[];
-
-static {
- // high value may be configured by property
- int h = 127;
- String integerCacheHighPropValue =
- sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
- if (integerCacheHighPropValue != null) {
- try {
- int i = parseInt(integerCacheHighPropValue);
- i = Math.max(i, 127);
- // Maximum array size is Integer.MAX_VALUE
- h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
- } catch( NumberFormatException nfe) {
- // If the property cannot be parsed into an int, ignore it.
- }
- }
- high = h;
-
- cache = new Integer[(high - low) + 1];
- int j = low;
- for(int k = 0; k < cache.length; k++)
- cache[k] = new Integer(j++);
-
- // range [-128, 127] must be interned (JLS7 5.1.7)
- assert IntegerCache.high >= 127;
-}
-```
-
-编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。
-
-```java
-Integer m = 123;
-Integer n = 123;
-System.out.println(m == n); // true
-```
-
-基本类型对应的缓冲池如下:
-
-- boolean values true and false
-- all byte values
-- short values between -128 and 127
-- int values between -128 and 127
-- char in the range \u0000 to \u007F
-
-在使用这些基本类型对应的包装类型时,就可以直接使用缓冲池中的对象。
-
-[StackOverflow : Differences between new Integer(123), Integer.valueOf(123) and just 123
-](https://stackoverflow.com/questions/9030817/differences-between-new-integer123-integer-valueof123-and-just-123)
-
-# 二、String
-
-## 概览
-
-String 被声明为 final,因此它不可被继承。
-
-在 Java 8 中,String 内部使用 char 数组存储数据。
-
-```java
-public final class String
- implements java.io.Serializable, Comparable, CharSequence {
- /** The value is used for character storage. */
- private final char value[];
-}
-```
-
-在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 `coder` 来标识使用了哪种编码。
-
-```java
-public final class String
- implements java.io.Serializable, Comparable, CharSequence {
- /** The value is used for character storage. */
- private final byte[] value;
-
- /** The identifier of the encoding used to encode the bytes in {@code value}. */
- private final byte coder;
-}
-```
-
-value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
-
-## 不可变的好处
-
-**1. 可以缓存 hash 值**
-
-因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
-
-**2. String Pool 的需要**
-
-如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
-
-
-
-**3. 安全性**
-
-String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。
-
-**4. 线程安全**
-
-String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
-
-[Program Creek : Why String is immutable in Java?](https://www.programcreek.com/2013/04/why-string-is-immutable-in-java/)
-
-## String, StringBuffer and StringBuilder
-
-**1. 可变性**
-
-- String 不可变
-- StringBuffer 和 StringBuilder 可变
-
-**2. 线程安全**
-
-- String 不可变,因此是线程安全的
-- StringBuilder 不是线程安全的
-- StringBuffer 是线程安全的,内部使用 synchronized 进行同步
-
-[StackOverflow : String, StringBuffer, and StringBuilder](https://stackoverflow.com/questions/2971315/string-stringbuffer-and-stringbuilder)
-
-## String Pool
-
-字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。
-
-当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
-
-下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern() 方法取得一个字符串引用。intern() 首先把 s1 引用的字符串放到 String Pool 中,然后返回这个字符串引用。因此 s3 和 s4 引用的是同一个字符串。
-
-```java
-String s1 = new String("aaa");
-String s2 = new String("aaa");
-System.out.println(s1 == s2); // false
-String s3 = s1.intern();
-String s4 = s1.intern();
-System.out.println(s3 == s4); // true
-```
-
-如果是采用 "bbb" 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。
-
-```java
-String s5 = "bbb";
-String s6 = "bbb";
-System.out.println(s5 == s6); // true
-```
-
-在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。
-
-- [StackOverflow : What is String interning?](https://stackoverflow.com/questions/10578984/what-is-string-interning)
-- [深入解析 String#intern](https://tech.meituan.com/in_depth_understanding_string_intern.html)
-
-## new String("abc")
-
-使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 "abc" 字符串对象)。
-
-- "abc" 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 "abc" 字符串字面量;
-- 而使用 new 的方式会在堆中创建一个字符串对象。
-
-创建一个测试类,其 main 方法中使用这种方式来创建字符串对象。
-
-```java
-public class NewStringTest {
- public static void main(String[] args) {
- String s = new String("abc");
- }
-}
-```
-
-使用 javap -verbose 进行反编译,得到以下内容:
-
-```java
-// ...
-Constant pool:
-// ...
- #2 = Class #18 // java/lang/String
- #3 = String #19 // abc
-// ...
- #18 = Utf8 java/lang/String
- #19 = Utf8 abc
-// ...
-
- public static void main(java.lang.String[]);
- descriptor: ([Ljava/lang/String;)V
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=2, args_size=1
- 0: new #2 // class java/lang/String
- 3: dup
- 4: ldc #3 // String abc
- 6: invokespecial #4 // Method java/lang/String."":(Ljava/lang/String;)V
- 9: astore_1
-// ...
-```
-
-在 Constant Pool 中,#19 存储这字符串字面量 "abc",#3 是 String Pool 的字符串对象,它指向 #19 这个字符串字面量。在 main 方法中,0: 行使用 new #2 在堆中创建一个字符串对象,并且使用 ldc #3 将 String Pool 中的字符串对象作为 String 构造函数的参数。
-
-以下是 String 构造函数的源码,可以看到,在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组。
-
-```java
-public String(String original) {
- this.value = original.value;
- this.hash = original.hash;
-}
-```
-
-# 三、运算
-
-## 参数传递
-
-Java 的参数是以值传递的形式传入方法中,而不是引用传递。
-
-以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。在将一个参数传入一个方法时,本质上是将对象的地址以值的方式传递到形参中。因此在方法中使指针引用其它对象,那么这两个指针此时指向的是完全不同的对象,在一方改变其所指向对象的内容时对另一方没有影响。
-
-```java
-public class Dog {
-
- String name;
-
- Dog(String name) {
- this.name = name;
- }
-
- String getName() {
- return this.name;
- }
-
- void setName(String name) {
- this.name = name;
- }
-
- String getObjectAddress() {
- return super.toString();
- }
-}
-```
-
-```java
-public class PassByValueExample {
- public static void main(String[] args) {
- Dog dog = new Dog("A");
- System.out.println(dog.getObjectAddress()); // Dog@4554617c
- func(dog);
- System.out.println(dog.getObjectAddress()); // Dog@4554617c
- System.out.println(dog.getName()); // A
- }
-
- private static void func(Dog dog) {
- System.out.println(dog.getObjectAddress()); // Dog@4554617c
- dog = new Dog("B");
- System.out.println(dog.getObjectAddress()); // Dog@74a14482
- System.out.println(dog.getName()); // B
- }
-}
-```
-
-如果在方法中改变对象的字段值会改变原对象该字段值,因为改变的是同一个地址指向的内容。
-
-```java
-class PassByValueExample {
- public static void main(String[] args) {
- Dog dog = new Dog("A");
- func(dog);
- System.out.println(dog.getName()); // B
- }
-
- private static void func(Dog dog) {
- dog.setName("B");
- }
-}
-```
-
-[StackOverflow: Is Java “pass-by-reference” or “pass-by-value”?](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value)
-
-## float 与 double
-
-Java 不能隐式执行向下转型,因为这会使得精度降低。
-
-1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。
-
-```java
-// float f = 1.1;
-```
-
-1.1f 字面量才是 float 类型。
-
-```java
-float f = 1.1f;
-```
-
-## 隐式类型转换
-
-因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。
-
-```java
-short s1 = 1;
-// s1 = s1 + 1;
-```
-
-但是使用 += 或者 ++ 运算符可以执行隐式类型转换。
-
-```java
-s1 += 1;
-// s1++;
-```
-
-上面的语句相当于将 s1 + 1 的计算结果进行了向下转型:
-
-```java
-s1 = (short) (s1 + 1);
-```
-
-[StackOverflow : Why don't Java's +=, -=, *=, /= compound assignment operators require casting?](https://stackoverflow.com/questions/8710619/why-dont-javas-compound-assignment-operators-require-casting)
-
-## switch
-
-从 Java 7 开始,可以在 switch 条件判断语句中使用 String 对象。
-
-```java
-String s = "a";
-switch (s) {
- case "a":
- System.out.println("aaa");
- break;
- case "b":
- System.out.println("bbb");
- break;
-}
-```
-
-switch 不支持 long,是因为 switch 的设计初衷是对那些只有少数的几个值进行等值判断,如果值过于复杂,那么还是用 if 比较合适。
-
-```java
-// long x = 111;
-// switch (x) { // Incompatible types. Found: 'long', required: 'char, byte, short, int, Character, Byte, Short, Integer, String, or an enum'
-// case 111:
-// System.out.println(111);
-// break;
-// case 222:
-// System.out.println(222);
-// break;
-// }
-```
-
-[StackOverflow : Why can't your switch statement data type be long, Java?](https://stackoverflow.com/questions/2676210/why-cant-your-switch-statement-data-type-be-long-java)
-
-# 四、继承
-
-## 访问权限
-
-Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。
-
-可以对类或类中的成员(字段以及方法)加上访问修饰符。
-
-- 类可见表示其它类可以用这个类创建实例对象。
-- 成员可见表示其它类可以用这个类的实例对象访问到该成员;
-
-protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。
-
-设计良好的模块会隐藏所有的实现细节,把它的 API 与它的实现清晰地隔离开来。模块之间只通过它们的 API 进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问。
-
-如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里氏替换原则。
-
-字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。例如下面的例子中,AccessExample 拥有 id 公有字段,如果在某个时刻,我们想要使用 int 存储 id 字段,那么就需要修改所有的客户端代码。
-
-```java
-public class AccessExample {
- public String id;
-}
-```
-
-可以使用公有的 getter 和 setter 方法来替换公有字段,这样的话就可以控制对字段的修改行为。
-
-
-```java
-public class AccessExample {
-
- private int id;
-
- public String getId() {
- return id + "";
- }
-
- public void setId(String id) {
- this.id = Integer.valueOf(id);
- }
-}
-```
-
-但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。
-
-```java
-public class AccessWithInnerClassExample {
-
- private class InnerClass {
- int x;
- }
-
- private InnerClass innerClass;
-
- public AccessWithInnerClassExample() {
- innerClass = new InnerClass();
- }
-
- public int getValue() {
- return innerClass.x; // 直接访问
- }
-}
-```
-
-## 抽象类与接口
-
-**1. 抽象类**
-
-抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
-
-抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。
-
-```java
-public abstract class AbstractClassExample {
-
- protected int x;
- private int y;
-
- public abstract void func1();
-
- public void func2() {
- System.out.println("func2");
- }
-}
-```
-
-```java
-public class AbstractExtendClassExample extends AbstractClassExample {
- @Override
- public void func1() {
- System.out.println("func1");
- }
-}
-```
-
-```java
-// AbstractClassExample ac1 = new AbstractClassExample(); // 'AbstractClassExample' is abstract; cannot be instantiated
-AbstractClassExample ac2 = new AbstractExtendClassExample();
-ac2.func1();
-```
-
-**2. 接口**
-
-接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
-
-从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
-
-接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。
-
-接口的字段默认都是 static 和 final 的。
-
-```java
-public interface InterfaceExample {
-
- void func1();
-
- default void func2(){
- System.out.println("func2");
- }
-
- int x = 123;
- // int y; // Variable 'y' might not have been initialized
- public int z = 0; // Modifier 'public' is redundant for interface fields
- // private int k = 0; // Modifier 'private' not allowed here
- // protected int l = 0; // Modifier 'protected' not allowed here
- // private void fun3(); // Modifier 'private' not allowed here
-}
-```
-
-```java
-public class InterfaceImplementExample implements InterfaceExample {
- @Override
- public void func1() {
- System.out.println("func1");
- }
-}
-```
-
-```java
-// InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
-InterfaceExample ie2 = new InterfaceImplementExample();
-ie2.func1();
-System.out.println(InterfaceExample.x);
-```
-
-**3. 比较**
-
-- 从设计层面上看,抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
-- 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
-- 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
-- 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
-
-**4. 使用选择**
-
-使用接口:
-
-- 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法;
-- 需要使用多重继承。
-
-使用抽象类:
-
-- 需要在几个相关的类中共享代码。
-- 需要能控制继承来的成员的访问权限,而不是都为 public。
-- 需要继承非静态和非常量字段。
-
-在很多情况下,接口优先于抽象类。因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。
-
-- [深入理解 abstract class 和 interface](https://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/)
-- [When to Use Abstract Class and Interface](https://dzone.com/articles/when-to-use-abstract-class-and-intreface)
-
-## super
-
-- 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
-- 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。
-
-```java
-public class SuperExample {
-
- protected int x;
- protected int y;
-
- public SuperExample(int x, int y) {
- this.x = x;
- this.y = y;
- }
-
- public void func() {
- System.out.println("SuperExample.func()");
- }
-}
-```
-
-```java
-public class SuperExtendExample extends SuperExample {
-
- private int z;
-
- public SuperExtendExample(int x, int y, int z) {
- super(x, y);
- this.z = z;
- }
-
- @Override
- public void func() {
- super.func();
- System.out.println("SuperExtendExample.func()");
- }
-}
-```
-
-```java
-SuperExample e = new SuperExtendExample(1, 2, 3);
-e.func();
-```
-
-```html
-SuperExample.func()
-SuperExtendExample.func()
-```
-
-[Using the Keyword super](https://docs.oracle.com/javase/tutorial/java/IandI/super.html)
-
-## 重写与重载
-
-**1. 重写(Override)**
-
-存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
-
-为了满足里式替换原则,重写有有以下两个限制:
-
-- 子类方法的访问权限必须大于等于父类方法;
-- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
-
-使用 @Override 注解,可以让编译器帮忙检查是否满足上面的两个限制条件。
-
-**2. 重载(Overload)**
-
-存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。
-
-应该注意的是,返回值不同,其它都相同不算是重载。
-
-**3. 实例**
-
-```java
-class A {
- public String show(D obj) {
- return ("A and D");
- }
-
- public String show(A obj) {
- return ("A and A");
- }
-}
-
-class B extends A {
- public String show(B obj) {
- return ("B and B");
- }
-
- public String show(A obj) {
- return ("B and A");
- }
-}
-
-class C extends B {
-}
-
-class D extends B {
-}
-```
-
-```java
-public class Test {
-
- public static void main(String[] args) {
- A a1 = new A();
- A a2 = new B();
- B b = new B();
- C c = new C();
- D d = new D();
- System.out.println(a1.show(b)); // A and A
- System.out.println(a1.show(c)); // A and A
- System.out.println(a1.show(d)); // A and D
- System.out.println(a2.show(b)); // B and A
- System.out.println(a2.show(c)); // B and A
- System.out.println(a2.show(d)); // A and D
- System.out.println(b.show(b)); // B and B
- System.out.println(b.show(c)); // B and B
- System.out.println(b.show(d)); // A and D
- }
-}
-```
-
-涉及到重写时,方法调用的优先级为:
-
-- this.show(O)
-- super.show(O)
-- this.show((super)O)
-- super.show((super)O)
-
-# 五、Object 通用方法
-
-## 概览
-
-```java
-
-public native int hashCode()
-
-public boolean equals(Object obj)
-
-protected native Object clone() throws CloneNotSupportedException
-
-public String toString()
-
-public final native Class> getClass()
-
-protected void finalize() throws Throwable {}
-
-public final native void notify()
-
-public final native void notifyAll()
-
-public final native void wait(long timeout) throws InterruptedException
-
-public final void wait(long timeout, int nanos) throws InterruptedException
-
-public final void wait() throws InterruptedException
-```
-
-## equals()
-
-**1. 等价关系**
-
-Ⅰ 自反性
-
-```java
-x.equals(x); // true
-```
-
-Ⅱ 对称性
-
-```java
-x.equals(y) == y.equals(x); // true
-```
-
-Ⅲ 传递性
-
-```java
-if (x.equals(y) && y.equals(z))
- x.equals(z); // true;
-```
-
-Ⅳ 一致性
-
-多次调用 equals() 方法结果不变
-
-```java
-x.equals(y) == x.equals(y); // true
-```
-
-Ⅴ 与 null 的比较
-
-对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
-
-```java
-x.equals(null); // false;
-```
-
-**2. 等价与相等**
-
-- 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
-- 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
-
-```java
-Integer x = new Integer(1);
-Integer y = new Integer(1);
-System.out.println(x.equals(y)); // true
-System.out.println(x == y); // false
-```
-
-**3. 实现**
-
-- 检查是否为同一个对象的引用,如果是直接返回 true;
-- 检查是否是同一个类型,如果不是,直接返回 false;
-- 将 Object 对象进行转型;
-- 判断每个关键域是否相等。
-
-```java
-public class EqualExample {
-
- private int x;
- private int y;
- private int z;
-
- public EqualExample(int x, int y, int z) {
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- EqualExample that = (EqualExample) o;
-
- if (x != that.x) return false;
- if (y != that.y) return false;
- return z == that.z;
- }
-}
-```
-
-## hashCode()
-
-hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
-
-在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
-
-下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。
-
-```java
-EqualExample e1 = new EqualExample(1, 1, 1);
-EqualExample e2 = new EqualExample(1, 1, 1);
-System.out.println(e1.equals(e2)); // true
-HashSet set = new HashSet<>();
-set.add(e1);
-set.add(e2);
-System.out.println(set.size()); // 2
-```
-
-理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来。可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。
-
-一个数与 31 相乘可以转换成移位和减法:`31*x == (x<<5)-x`,编译器会自动进行这个优化。
-
-```java
-@Override
-public int hashCode() {
- int result = 17;
- result = 31 * result + x;
- result = 31 * result + y;
- result = 31 * result + z;
- return result;
-}
-```
-
-## toString()
-
-默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。
-
-```java
-public class ToStringExample {
-
- private int number;
-
- public ToStringExample(int number) {
- this.number = number;
- }
-}
-```
-
-```java
-ToStringExample example = new ToStringExample(123);
-System.out.println(example.toString());
-```
-
-```html
-ToStringExample@4554617c
-```
-
-## clone()
-
-**1. cloneable**
-
-clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。
-
-```java
-public class CloneExample {
- private int a;
- private int b;
-}
-```
-
-```java
-CloneExample e1 = new CloneExample();
-// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'
-```
-
-重写 clone() 得到以下实现:
-
-```java
-public class CloneExample {
- private int a;
- private int b;
-
- @Override
- public CloneExample clone() throws CloneNotSupportedException {
- return (CloneExample)super.clone();
- }
-}
-```
-
-```java
-CloneExample e1 = new CloneExample();
-try {
- CloneExample e2 = e1.clone();
-} catch (CloneNotSupportedException e) {
- e.printStackTrace();
-}
-```
-
-```html
-java.lang.CloneNotSupportedException: CloneExample
-```
-
-以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。
-
-应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
-
-```java
-public class CloneExample implements Cloneable {
- private int a;
- private int b;
-
- @Override
- public Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
-}
-```
-
-**2. 浅拷贝**
-
-拷贝对象和原始对象的引用类型引用同一个对象。
-
-```java
-public class ShallowCloneExample implements Cloneable {
-
- private int[] arr;
-
- public ShallowCloneExample() {
- arr = new int[10];
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
-
- public void set(int index, int value) {
- arr[index] = value;
- }
-
- public int get(int index) {
- return arr[index];
- }
-
- @Override
- protected ShallowCloneExample clone() throws CloneNotSupportedException {
- return (ShallowCloneExample) super.clone();
- }
-}
-```
-
-```java
-ShallowCloneExample e1 = new ShallowCloneExample();
-ShallowCloneExample e2 = null;
-try {
- e2 = e1.clone();
-} catch (CloneNotSupportedException e) {
- e.printStackTrace();
-}
-e1.set(2, 222);
-System.out.println(e2.get(2)); // 222
-```
-
-**3. 深拷贝**
-
-拷贝对象和原始对象的引用类型引用不同对象。
-
-```java
-public class DeepCloneExample implements Cloneable {
-
- private int[] arr;
-
- public DeepCloneExample() {
- arr = new int[10];
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
-
- public void set(int index, int value) {
- arr[index] = value;
- }
-
- public int get(int index) {
- return arr[index];
- }
-
- @Override
- protected DeepCloneExample clone() throws CloneNotSupportedException {
- DeepCloneExample result = (DeepCloneExample) super.clone();
- result.arr = new int[arr.length];
- for (int i = 0; i < arr.length; i++) {
- result.arr[i] = arr[i];
- }
- return result;
- }
-}
-```
-
-```java
-DeepCloneExample e1 = new DeepCloneExample();
-DeepCloneExample e2 = null;
-try {
- e2 = e1.clone();
-} catch (CloneNotSupportedException e) {
- e.printStackTrace();
-}
-e1.set(2, 222);
-System.out.println(e2.get(2)); // 2
-```
-
-**4. clone() 的替代方案**
-
-使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
-
-```java
-public class CloneConstructorExample {
-
- private int[] arr;
-
- public CloneConstructorExample() {
- arr = new int[10];
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
-
- public CloneConstructorExample(CloneConstructorExample original) {
- arr = new int[original.arr.length];
- for (int i = 0; i < original.arr.length; i++) {
- arr[i] = original.arr[i];
- }
- }
-
- public void set(int index, int value) {
- arr[index] = value;
- }
-
- public int get(int index) {
- return arr[index];
- }
-}
-```
-
-```java
-CloneConstructorExample e1 = new CloneConstructorExample();
-CloneConstructorExample e2 = new CloneConstructorExample(e1);
-e1.set(2, 222);
-System.out.println(e2.get(2)); // 2
-```
-
-# 六、关键字
-
-## final
-
-**1. 数据**
-
-声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
-
-- 对于基本类型,final 使数值不变;
-- 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
-
-```java
-final int x = 1;
-// x = 2; // cannot assign value to final variable 'x'
-final A y = new A();
-y.a = 1;
-```
-
-**2. 方法**
-
-声明方法不能被子类重写。
-
-private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。
-
-**3. 类**
-
-声明类不允许被继承。
-
-## static
-
-**1. 静态变量**
-
-- 静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
-- 实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
-
-```java
-public class A {
-
- private int x; // 实例变量
- private static int y; // 静态变量
-
- public static void main(String[] args) {
- // int x = A.x; // Non-static field 'x' cannot be referenced from a static context
- A a = new A();
- int x = a.x;
- int y = A.y;
- }
-}
-```
-
-**2. 静态方法**
-
-静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
-
-```java
-public abstract class A {
- public static void func1(){
- }
- // public abstract static void func2(); // Illegal combination of modifiers: 'abstract' and 'static'
-}
-```
-
-只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。
-
-```java
-public class A {
-
- private static int x;
- private int y;
-
- public static void func1(){
- int a = x;
- // int b = y; // Non-static field 'y' cannot be referenced from a static context
- // int b = this.y; // 'A.this' cannot be referenced from a static context
- }
-}
-```
-
-**3. 静态语句块**
-
-静态语句块在类初始化时运行一次。
-
-```java
-public class A {
- static {
- System.out.println("123");
- }
-
- public static void main(String[] args) {
- A a1 = new A();
- A a2 = new A();
- }
-}
-```
-
-```html
-123
-```
-
-**4. 静态内部类**
-
-非静态内部类依赖于外部类的实例,而静态内部类不需要。
-
-```java
-public class OuterClass {
-
- class InnerClass {
- }
-
- static class StaticInnerClass {
- }
-
- public static void main(String[] args) {
- // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
- OuterClass outerClass = new OuterClass();
- InnerClass innerClass = outerClass.new InnerClass();
- StaticInnerClass staticInnerClass = new StaticInnerClass();
- }
-}
-```
-
-静态内部类不能访问外部类的非静态的变量和方法。
-
-**5. 静态导包**
-
-在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。
-
-```java
-import static com.xxx.ClassName.*
-```
-
-**6. 初始化顺序**
-
-静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
-
-```java
-public static String staticField = "静态变量";
-```
-
-```java
-static {
- System.out.println("静态语句块");
-}
-```
-
-```java
-public String field = "实例变量";
-```
-
-```java
-{
- System.out.println("普通语句块");
-}
-```
-
-最后才是构造函数的初始化。
-
-```java
-public InitialOrderTest() {
- System.out.println("构造函数");
-}
-```
-
-存在继承的情况下,初始化顺序为:
-
-- 父类(静态变量、静态语句块)
-- 子类(静态变量、静态语句块)
-- 父类(实例变量、普通语句块)
-- 父类(构造函数)
-- 子类(实例变量、普通语句块)
-- 子类(构造函数)
-
-
-# 七、反射
-
-每个类都有一个 **Class** 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
-
-类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 `Class.forName("com.mysql.jdbc.Driver")` 这种方式来控制类的加载,该方法会返回一个 Class 对象。
-
-反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。
-
-Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
-
-- **Field** :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
-- **Method** :可以使用 invoke() 方法调用与 Method 对象关联的方法;
-- **Constructor** :可以用 Constructor 创建新的对象。
-
-**反射的优点:**
-
-* **可扩展性** :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
-* **类浏览器和可视化开发环境** :一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
-* **调试器和测试工具** : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。
-
-**反射的缺点:**
-
-尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。
-
-* **性能开销** :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
-
-* **安全限制** :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
-
-* **内部暴露** :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
-
-
-- [Trail: The Reflection API](https://docs.oracle.com/javase/tutorial/reflect/index.html)
-- [深入解析 Java 反射(1)- 基础](http://www.sczyh30.com/posts/Java/java-reflection-1/)
-
-# 八、异常
-
-Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: **Error** 和 **Exception**。其中 Error 用来表示 JVM 无法处理的错误,Exception 分为两种:
-
-- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
-- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
-
-
-
-- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
-- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
-
-# 九、泛型
-
-```java
-public class Box {
- // T stands for "Type"
- private T t;
- public void set(T t) { this.t = t; }
- public T get() { return t; }
-}
-```
-
-- [Java 泛型详解](http://www.importnew.com/24029.html)
-- [10 道 Java 泛型面试题](https://cloud.tencent.com/developer/article/1033693)
-
-# 十、注解
-
-Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
-
-[注解 Annotation 实现原理与自定义注解例子](https://www.cnblogs.com/acm-bingzi/p/javaAnnotation.html)
-
-# 十一、特性
-
-## Java 各版本的新特性
-
-**New highlights in Java SE 8**
-
-1. Lambda Expressions
-2. Pipelines and Streams
-3. Date and Time API
-4. Default Methods
-5. Type Annotations
-6. Nashhorn JavaScript Engine
-7. Concurrent Accumulators
-8. Parallel operations
-9. PermGen Error Removed
-
-**New highlights in Java SE 7**
-
-1. Strings in Switch Statement
-2. Type Inference for Generic Instance Creation
-3. Multiple Exception Handling
-4. Support for Dynamic Languages
-5. Try with Resources
-6. Java nio Package
-7. Binary Literals, Underscore in literals
-8. Diamond Syntax
-
-- [Difference between Java 1.8 and Java 1.7?](http://www.selfgrowth.com/articles/difference-between-java-18-and-java-17)
-- [Java 8 特性](http://www.importnew.com/19345.html)
-
-## Java 与 C++ 的区别
-
-- Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即支持面向对象也支持面向过程。
-- Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
-- Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
-- Java 支持自动垃圾回收,而 C++ 需要手动回收。
-- Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
-- Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
-- Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
-- Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。
-
-[What are the main differences between Java and C++?](http://cs-fundamentals.com/tech-interview/java/differences-between-java-and-cpp.php)
-
-## JRE or JDK
-
-- JRE is the JVM program, Java application need to run on JRE.
-- JDK is a superset of JRE, JRE + tools for developing java programs. e.g, it provides the compiler "javac"
-
-# 参考资料
-
-- Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
-- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
-
-
-
-
-欢迎关注公众号,获取最新文章!
-
diff --git "a/docs/notes/Java \350\231\232\346\213\237\346\234\272.md" "b/docs/notes/Java \350\231\232\346\213\237\346\234\272.md"
deleted file mode 100644
index efa5ca5a67..0000000000
--- "a/docs/notes/Java \350\231\232\346\213\237\346\234\272.md"
+++ /dev/null
@@ -1,747 +0,0 @@
-
-* [一、运行时数据区域](#一运行时数据区域)
- * [程序计数器](#程序计数器)
- * [Java 虚拟机栈](#java-虚拟机栈)
- * [本地方法栈](#本地方法栈)
- * [堆](#堆)
- * [方法区](#方法区)
- * [运行时常量池](#运行时常量池)
- * [直接内存](#直接内存)
-* [二、垃圾收集](#二垃圾收集)
- * [判断一个对象是否可被回收](#判断一个对象是否可被回收)
- * [引用类型](#引用类型)
- * [垃圾收集算法](#垃圾收集算法)
- * [垃圾收集器](#垃圾收集器)
-* [三、内存分配与回收策略](#三内存分配与回收策略)
- * [Minor GC 和 Full GC](#minor-gc-和-full-gc)
- * [内存分配策略](#内存分配策略)
- * [Full GC 的触发条件](#full-gc-的触发条件)
-* [四、类加载机制](#四类加载机制)
- * [类的生命周期](#类的生命周期)
- * [类加载过程](#类加载过程)
- * [类初始化时机](#类初始化时机)
- * [类与类加载器](#类与类加载器)
- * [类加载器分类](#类加载器分类)
- * [双亲委派模型](#双亲委派模型)
- * [自定义类加载器实现](#自定义类加载器实现)
-* [参考资料](#参考资料)
-
-
-
-# 一、运行时数据区域
-
-
-
-## 程序计数器
-
-记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。
-
-## Java 虚拟机栈
-
-每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
-
-
-
-可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
-
-```java
-java -Xss512M HackTheJava
-```
-
-该区域可能抛出以下异常:
-
-- 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常;
-- 栈进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。
-
-## 本地方法栈
-
-本地方法栈与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
-
-本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
-
-
-
-## 堆
-
-所有对象都在这里分配内存,是垃圾收集的主要区域("GC 堆")。
-
-现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法。可以将堆分成两块:
-
-- 新生代(Young Generation)
-- 老年代(Old Generation)
-
-堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。
-
-可以通过 -Xms 和 -Xmx 这两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。
-
-```java
-java -Xms1M -Xmx2M HackTheJava
-```
-
-## 方法区
-
-用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
-
-和堆一样不需要连续的内存,并且可以动态扩展,动态扩展失败一样会抛出 OutOfMemoryError 异常。
-
-对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。
-
-HotSpot 虚拟机把它当成永久代来进行垃圾回收。但很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。
-
-## 运行时常量池
-
-运行时常量池是方法区的一部分。
-
-Class 文件中的常量池(编译器生成的字面量和符号引用)会在类加载后被放入这个区域。
-
-除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。
-
-## 直接内存
-
-在 JDK 1.4 中新引入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在堆内存和堆外内存来回拷贝数据。
-
-# 二、垃圾收集
-
-垃圾收集主要是针对堆和方法区进行。程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。
-
-## 判断一个对象是否可被回收
-
-### 1. 引用计数算法
-
-为对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。
-
-在两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收。正是因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法。
-
-```java
-public class Test {
-
- public Object instance = null;
-
- public static void main(String[] args) {
- Test a = new Test();
- Test b = new Test();
- a.instance = b;
- b.instance = a;
- }
-}
-```
-
-### 2. 可达性分析算法
-
-以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
-
-Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般包含以下内容:
-
-- 虚拟机栈中局部变量表中引用的对象
-- 本地方法栈中 JNI 中引用的对象
-- 方法区中类静态属性引用的对象
-- 方法区中的常量引用的对象
-
-
-
-### 3. 方法区的回收
-
-因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,所以在方法区上进行回收性价比不高。
-
-主要是对常量池的回收和对类的卸载。
-
-为了避免内存溢出,在大量使用反射和动态代理的场景都需要虚拟机具备类卸载功能。
-
-类的卸载条件很多,需要满足以下三个条件,并且满足了条件也不一定会被卸载:
-
-- 该类所有的实例都已经被回收,此时堆中不存在该类的任何实例。
-- 加载该类的 ClassLoader 已经被回收。
-- 该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
-
-### 4. finalize()
-
-类似 C++ 的析构函数,用于关闭外部资源。但是 try-finally 等方式可以做得更好,并且该方法运行代价很高,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。
-
-当一个对象可被回收时,如果需要执行该对象的 finalize() 方法,那么就有可能在该方法中让对象重新被引用,从而实现自救。自救只能进行一次,如果回收的对象之前调用了 finalize() 方法自救,后面回收时不会再调用该方法。
-
-## 引用类型
-
-无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关。
-
-Java 提供了四种强度不同的引用类型。
-
-### 1. 强引用
-
-被强引用关联的对象不会被回收。
-
-使用 new 一个新对象的方式来创建强引用。
-
-```java
-Object obj = new Object();
-```
-
-### 2. 软引用
-
-被软引用关联的对象只有在内存不够的情况下才会被回收。
-
-使用 SoftReference 类来创建软引用。
-
-```java
-Object obj = new Object();
-SoftReference