diff --git a/README.md b/README.md index 6e75f41..860f932 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ # 🔥 微信公众号 : 码上Java - - -> 关注微信订阅号: 码上Java 回复关键字 : 1 领取后端面试大礼包(简历模板、面试题、Java、数据结构、算法、数据库、python、操作系统、网络等) - [![QQ群](https://img.shields.io/badge/QQ%E7%BE%A4-660108379-yellowgreen.svg)](https://jq.qq.com/?_wv=1027&k=5HPYvQk) ![微信公众号](https://img.shields.io/badge/微信公众号-码上Java-yellowgreen.svg) [![GitHubPages](https://img.shields.io/badge/在线阅读-GitHubPages-yellowgreen.svg)](https://msjavacoder.github.io/msJava) @@ -11,110 +7,10 @@ ![version-v2.0.0](https://img.shields.io/badge/version-v2.0.0-green.svg) ![license-GPL](https://img.shields.io/badge/license-GPL-blue.svg) -| ♨ | ⭕ | 🔐 | 💈 | 💻 | 🚏 | 🔭 | 🏖 | 📰 | 📮 | 🔍 | 🗽 | 🚀 | 🌈 | ☎ | -| :-----------------------------: | :-------------: | :----------------------------: | :---------: | :-----------: | :---------------------: | --------------- | --------------- | :---------------------------------: | :-----------------: | :-----------------------: | :---------------: | ----------------- | :-----------------: | :---------------------: | -| [Java核心基础](#♨-java核心基础) | [集合](#⭕-集合) | [多线程](#%f0%9f%94%90-多线程) | [IO](#💈-io) | [JVM](#💻-jvm) | [设计模式](#🚏-设计模式) | [网络](#🔭-网络) | [框架](#🏖-框架) | [数据结构与算法](#📰-数据结构与算法) | [数据库](#📰-数据库) | [算法](#📰-数据结构与算法) | [Redis](#🗽-redis) | [Linux](#🚀-linux) | [面试题](#🌈-面试题) | [联系作者](#☎-联系作者) | - ---- - -### ♨ Java核心基础 - -- [理解基本数据类型与包装类](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解基本数据类型与包装类.md) -- [理解类与Object](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解类与Object.md) -- [理解泛型与迭代器](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解泛型与迭代器.md) -- [理解Java关键字](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/Java关键字理解.md) -- [理解String字符串](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解String字符串.md) -- [浅克隆和深克隆](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/浅克隆和深克隆.md) -- [理解动态代理](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解动态代理.md) -- [理解抽象类与接口](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解抽象类与接口.md) -- [理解异常处理](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解异常处理.md) -- [理解数据结构队列](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解数据结构队列.md) -- [理解内部类与枚举类](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/各种内部类和枚举类.md) -- [理解克隆与序列化应用](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解克隆与序列化应用.md) -- ··· - ---- - -### ⭕ 集合 - -- [理解集合Collection](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解集合Collection.md) -- [理解集合Map](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解集合Map.md) -- [HashMap原理分析](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解HashMap底层实现原理.md) -- [HashMap为什么是线程不安全的](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解HashMap为什么是线程不安全的.md) -- [ConcurrentHashMap实现原理](https://github.com/msJavaCoder/msJava/blob/master/docs/Java万岁/Java-基础不牢地动山摇/理解ConcurrentHashMap底层实现原理.md) -- ··· - ---- - - -### 🔐 并发编程 -- [理解线程与死锁](https://github.com/msJavaCoder/msJava/blob/master/docs/并发编程/理解线程与死锁.md) -- [理解Java中的各种锁](https://github.com/msJavaCoder/msJava/blob/master/docs/并发编程/理解Java中的各种锁.md) -- [理解ThreadLocal](https://github.com/msJavaCoder/msJava/blob/master/docs/并发编程/理解ThreadLocal.md) -- [理解synchronized关键字](https://github.com/msJavaCoder/msJava/blob/master/docs/并发编程/理解synchronized关键字.md) -- [理解线程安全synchronized与ReentrantLock](https://github.com/msJavaCoder/msJava/blob/master/docs/并发编程/理解线程安全synchronized与ReentrantLock.md) -- [理解线程池](https://github.com/msJavaCoder/msJava/blob/master/docs/并发编程/理解线程池.md) -- ··· - ---- - -### 💻 JVM -- [Java运行时内存划分](https://github.com/msJavaCoder/msJava/blob/master/docs/JVM/Java运行时内存划分.md) -- [类加载机制](https://github.com/msJavaCoder/msJava/blob/master/docs/JVM/类加载机制.md) -- [垃圾回收器](https://github.com/msJavaCoder/msJava/blob/master/docs/JVM/垃圾回收器.md) -- [垃圾回收算法](https://github.com/msJavaCoder/msJava/blob/master/docs/JVM/垃圾回收算法.md) -- [JVM确认可回收对象的方式](https://github.com/msJavaCoder/msJava/blob/master/docs/JVM/JVM确认可回收对象的方式.md) -- ··· - ---- - - -### 🚏 设计模式 -- [设计模式总结](https://github.com/msJavaCoder/msJava/blob/master/设计模式/设计模式总结.md) -- [单例模式及Java实现](https://github.com/msJavaCoder/msJava/blob/master/设计模式/单例模式及Java实现.md) -- [工厂模式及Java实现](https://github.com/msJavaCoder/msJava/blob/master/设计模式/工厂模式及Java实现.md) -- [抽象工长及Java实现](https://github.com/msJavaCoder/msJava/blob/master/设计模式/抽象工长及Java实现.md) -- [代理模式及Java实现](https://github.com/msJavaCoder/msJava/blob/master/设计模式/代理模式及Java实现.md) -- [适配器模式及Java实现](https://github.com/msJavaCoder/msJava/blob/master/设计模式/适配器模式及Java实现.md) -- ··· - ---- - -### 🔭 网络 - -- [理解网络协议分层](https://github.com/msJavaCoder/msJava/blob/master/docs/计算机网络/理解网络协议分层.md) -- [理解TCP和UDP](https://github.com/msJavaCoder/msJava/blob/master/docs/计算机网络/理解TCP和UDP.md) -- [理解HTTP与HTTPS](https://github.com/msJavaCoder/msJava/blob/master/docs/计算机网络/理解HTTP与HTTPS.md) -- ··· - --- - - -### 🌈 面试题 -- [Java核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/Java核心面试题汇总.md) -- [Spring核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/Spring面试题汇总.md) -- [SpringMVC核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/SpringMVC面试题汇总.md) -- [MyBatis核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/MyBatis面试题汇总.md) -- [SpringBoot核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/SpringBoot面试题汇总.md) -- [MySQL核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/MySQL面试题汇总.md) -- [常见算法核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/算法常用面试题汇总.md) -- [常见JVM核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/JVM面试题汇总.md) -- [设计模式核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/设计模式常见面试题汇总.md) -- [消息队列核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/消息队列面试题汇总.md) -- [分布式核心面试题](https://github.com/msJavaCoder/msJava/blob/master/docs/面试题/分布式框架面试题汇总.md) -- ··· +![ms-Java.webp](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/码上Java.webp) --- -### 🚮 踩坑记录 -- [IDEAMaven依赖成功导入但仍然报错找不到包解决方案](https://github.com/msJavaCoder/msJava/blob/master/docs/踩坑记录/IDEAMaven依赖成功导入但仍然报错找不到包解决方案.md) -- ··· - - - ### ☎ 联系作者 - -> 关注微信订阅号: 码上Java 🔥🔥🔥 - ---- - +> 关注微信订阅号: 码上Java 🔥🔥🔥 \ No newline at end of file diff --git a/_coverpage.md b/_coverpage.md index b25d3e8..c1e5be2 100644 --- a/_coverpage.md +++ b/_coverpage.md @@ -1,15 +1,18 @@ ![logo](https://docsify.js.org/_media/icon.svg) -

Java后端面试核心知识体系

-

愿你的明天永远热泪盈眶 😀

+

JAVA后端核心知识体系

+

风儿哪儿吹,不要问跟风的人。💯

![QQ群](https://img.shields.io/badge/QQ%E7%BE%A4-660108379-yellowgreen.svg) ![微信公众号](https://img.shields.io/badge/微信公众号-码上Java-yellowgreen.svg) ![version-v2.0.0](https://img.shields.io/badge/version-v2.0.0-green.svg) ![license-GPL](https://img.shields.io/badge/license-GPL-blue.svg) - [GitHub](https://github.com/msJavaCoder/msJava) [开始阅读](#🔥-微信公众号-:-码上java) + +![GGIxB.jpg](https://s.im5i.com/2021/04/14/GGIxB.jpg) + +![color](#000000) \ No newline at end of file diff --git a/_navbar.md b/_navbar.md index e69de29..795d8fa 100644 --- a/_navbar.md +++ b/_navbar.md @@ -0,0 +1,39 @@ + * Java + * [Java核心基础](docs/Java核心基础/README.md) + * [Java源码分析](docs/Java源码分析/README.md) + * [Java性能优化](docs/Java性能优化/README.md) + * [Java并发编程](docs/Java并发编程/README.md) + * [Java虚拟机](docs/Java虚拟机/README.md) + + * 主流框架 + * Spring + * SpringMVC + * MyBatis + * [SpringBoot](docs/SpringBoot/README.md) + * SpringCloud + + * 数据库 + * [MySQL](docs/MySQL/README.md) + * [Redis](docs/Redis/README.md) + + + + * 数据结构与算法 + * [排序算法](docs/算法与数据结构/排序算法.md) + * [数据结构](docs/算法与数据结构/README.md) + * [剑指offer](docs/算法与数据结构/剑指offer题解.md) + + * 计算机基础 + * 操作系统 + * 计算机组成原理 + * 计算机网络 + + * 项目实战 + * 个人博客 + * wiki知识库 + * ··· + + * [面试题](docs/面试题/README.md) + + * [首页](/) + diff --git a/_sidebar.md b/_sidebar.md index a5cc84c..63bbb3b 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,100 +1,47 @@ -* 网络 - * [理解网络协议分层](docs/计算机网络/网络协议分层.md) - * [理解TCP和UDP](docs/计算机网络/理解TCP和UDP.md) - * [理解HTTP和HTTPS](docs/计算机网络/理解HTTP与HTTPS.md) - * ... - -* Java核心基础 - * [理解基本数据类型与包装类](docs/Java万岁/Java-基础不牢地动山摇/理解基本数据类型与包装类.md) - * [理解类与Object](docs/Java万岁/Java-基础不牢地动山摇/理解类与Object.md) - * [理解泛型与迭代器](docs/Java万岁/Java-基础不牢地动山摇/理解泛型与迭代器.md) - * [理解Java关键字](docs/Java万岁/Java-基础不牢地动山摇/理解Java关键字.md) - * [理解String字符串](docs/Java万岁/Java-基础不牢地动山摇/理解String字符串.md) - * [理解动态代理](docs/Java万岁/Java-基础不牢地动山摇/理解动态代理.md) - * [理解抽象类与接口](docs/Java万岁/Java-基础不牢地动山摇/理解抽象类与接口.md) - * [理解异常处理](docs/Java万岁/Java-基础不牢地动山摇/理解异常处理.md) - * [理解数据结构队列](docs/Java万岁/Java-基础不牢地动山摇/理解数据结构队列.md) - * [理解内部类与枚举类](docs/Java万岁/Java-基础不牢地动山摇/理解各种内部类和枚举类.md) - * [理解克隆与序列化应用](docs/Java万岁/Java-基础不牢地动山摇/理解克隆与序列化应用.md) - * ... - -* 集合 - * [理解集合Collection](docs/Java万岁/Java-基础不牢地动山摇/理解集合Collection.md) - * [理解集合Map](docs/Java万岁/Java-基础不牢地动山摇/理解集合Map.md) - * [理解HashMap底层实现原理](docs/Java万岁/Java-基础不牢地动山摇/理解HashMap底层实现原理.md) - * [理解HashMap为什么是线程不安全的](docs/Java万岁/Java-基础不牢地动山摇/理解HashMap为什么是线程不安全的.md) - * [理解ConcurrentHashMap底层实现原理](docs/Java万岁/Java-基础不牢地动山摇/理解ConcurrentHashMap底层实现原理.md) - * ... - -* Java源码分析 - * [ArrayList源码分析](docs/Java源码分析/ArrayList源码分析.md) - * [HashMap源码分析](docs/Java源码分析/HashMap源码分析.md) - * [TreeMap源码分析](docs/Java源码分析/TreeMap源码分析.md) - * [HashSet与TreeSet源码分析](docs/Java源码分析/HashSet与TreeSet源码分析.md) - * [LinkedHashMap源码分析](docs/Java源码分析/LinkedHashMap源码分析.md) - * [ConcurrentHashMap源码分析](docs/Java源码分析/ConcurrentHashMap源码分析.md) - * ... - -* 并发编程 - * [理解线程池](docs/并发编程/理解线程池.md) - * [理解线程与死锁](docs/并发编程/理解线程与死锁.md) - * [理解CAS优缺点](docs/并发编程/理解CAS优缺点.md) - * [理解ThreadLocal](docs/并发编程/理解ThreadLocal.md) - * [理解synchronized关键字](docs/并发编程/理解synchronized关键字.md) - * [理解Callable和Runnable的不同](docs/并发编程/理解Callable和Runnable的不同.md) - * [理解Java中的锁及其特点](docs/并发编程/理解Java中的锁及其特点.md) - * [理解JVM内存结构与Java内存模型](docs/并发编程/理解JVM内存结构与Java内存模型.md) - * [理解线程池4种拒绝策略](docs/并发编程/理解线程池4种拒绝策略.md) - * [理解线程的状态及如何进行转换的](docs/并发编程/理解线程的状态及如何进行转换的.md) - * [可能会遇到的三类线程安全问题](docs/并发编程/可能会遇到的三类线程安全问题.md) - * [哪些场景需要额外注意线程安全问题](docs/并发编程/哪些场景需要额外注意线程安全问题.md) - * [为什么说本质上实现线程的方法只有一种](docs/并发编程/为什么说本质上实现线程的方法只有一种.md) - * [理解线程安全synchronized与ReentrantLock](docs/并发编程/理解线程安全synchronized与ReentrantLock.md) - * ... - -* JVM - * [垃圾回收器](docs/JVM/垃圾回收器.md) - * [垃圾回收算法](docs/JVM/垃圾回收算法.md) - * [类加载机制](docs/JVM/类加载机制.md) - * [Java运行时内存划分](docs/JVM/Java运行时内存划分.md) - * [JVM确认可回收对象的方式](docs/JVM/JVM确认可回收对象的方式.md) - * ... - -* 数据库 - * [理解MySQL基础概念](docs/MySQL/MySQL基础概念.md) - * [教你如何使用索引](docs/MySQL/如何使用索引.md) - * [什么情况下索引会失效](docs/MySQL/什么情况下索引失效.md) - * [什么时候不需要创建索引](docs/MySQL/什么时候不需要创建索引.md) - * [常见SQL优化方式](docs/MySQL/常见SQL优化方式.md) - * [浅谈MySQL的优化方案](docs/MySQL/浅谈MySQL的优化方案.md) - * [B树与B+树详谈](docs/MySQL/B树与B+树详谈.md) - * [Hash索引与B+树索引的区别](docs/MySQL/Hash索引与B+树索引的区别.md) - * [如何使用EXPLAIN查看执行计划](docs/MySQL/如何使用EXPLAIN查看执行计划.md) - * ... - -* SpringBoot专栏 - * ... - - -* SpringBoot常用技术整合 - * [SpringBoot-MyBatisPlus](docs/SpringBoot/基于SpringBoot集成Mybatis-Plus实现代码生成器.md) - * ... - -* 面试题 - * [Java核心面试题汇总](docs/面试题/Java核心面试题汇总.md) - * [Spring核心面试题汇总](docs/面试题/Spring面试题汇总.md) - * [SpringBoot核心面试题汇总](docs/面试题/SpringBoot面试题汇总.md) - * [SpringMVC核心面试题汇总](docs/面试题/SpringMVC面试题汇总.md) - * [MyBatis核心面试题汇总](docs/面试题/MyBatis面试题汇总.md) - * [MySQL面试题汇总](docs/面试题/MySQL面试题汇总.md) - * [算法常用面试题汇总](docs/面试题/算法常用面试题汇总.md) - * [JVM面试题汇总](docs/面试题/JVM面试题汇总.md) - * [设计模式常见面试题汇总](docs/面试题/设计模式常见面试题汇总.md) - * [消息队列面试题汇总](docs/面试题/消息队列面试题汇总.md) - * [分布式框架面试题汇总](docs/面试题/分布式框架面试题合集.md) - * ... + +* [**📕 数据结构与算法**](docs/算法与数据结构/README.md) + -* 踩坑记录 - * [Maven依赖成功导入但仍然报错找不到包解决方案](docs/踩坑记录/IDEAMaven依赖成功导入但仍然报错找不到包解决方案.md) - * ... +--- + +* [**💦 Java核心基础**](docs/Java核心基础/README.md) + +--- + +* [**🙈 Java源码分析**](docs/Java源码分析/README.md) + +--- + +* [**🐯 Java并发编程**](docs/Java并发编程/README.md) + +--- + +* [**🐷 Java虚拟机**](docs/Java虚拟机/README.md) + +--- + +* [**🌱 SpringBoot**](docs/SpringBoot/README.md) + + +--- + +* [**📚 MySQL**](docs/MySQL/README.md) + +--- + +* **🌀 Redis** + + +--- + +* [**📑 设计模式**](docs/设计模式/README.md) + +--- + +* [**👀 面试题**](docs/面试题/README.md) + +--- + +* **🔨 杂谈** +--- diff --git "a/docs/JVM/JVM\347\241\256\350\256\244\345\217\257\345\233\236\346\224\266\345\257\271\350\261\241\347\232\204\346\226\271\345\274\217.md" "b/docs/JVM/JVM\347\241\256\350\256\244\345\217\257\345\233\236\346\224\266\345\257\271\350\261\241\347\232\204\346\226\271\345\274\217.md" deleted file mode 100644 index 7d209ae..0000000 --- "a/docs/JVM/JVM\347\241\256\350\256\244\345\217\257\345\233\236\346\224\266\345\257\271\350\261\241\347\232\204\346\226\271\345\274\217.md" +++ /dev/null @@ -1,17 +0,0 @@ -# 如何确定垃圾 - -+ 引用计数法 - -在Java中如果要操作对象,就必须先获取该对象的引用,因此可以通过引用计数法来判断一个对象是否可以被回收。在为一个对象添加一个引用时,引用计数器就加1;为对象删除一个引用时,引用计数器就减1;如果一个对象的引用计数为0,则说明该对象没有被引用,可以回收。**优点是垃圾回收比较及时,实时性比较高,只要对象计数器为 0,则可以直接进行回收操作;而缺点是无法解决循环引用的问题。** - -+ 可达性分析 - -以一系列GC ROOTS的点作为起点向下搜索,当一个对象到任何GC ROOTS都没有引用链相连时,说明该对象可以回收。 - -在 Java 中可以作为 **CG Roots 的对象**,主要包含以下几个: - -1. 所有被同步锁持有的对象,比如被 synchronize 持有的对象; -2. 字符串常量池里的引用(String Table); -3. 类型为引用类型的静态变量; -4. 虚拟机栈中引用对象; -5. 本地方法栈中的引用对象。 \ No newline at end of file diff --git "a/docs/JVM/Java\350\277\220\350\241\214\346\227\266\345\206\205\345\255\230\345\210\222\345\210\206.md" "b/docs/JVM/Java\350\277\220\350\241\214\346\227\266\345\206\205\345\255\230\345\210\222\345\210\206.md" deleted file mode 100644 index b99cfd8..0000000 --- "a/docs/JVM/Java\350\277\220\350\241\214\346\227\266\345\206\205\345\255\230\345\210\222\345\210\206.md" +++ /dev/null @@ -1,28 +0,0 @@ -# JVM运行内存区域 - -> JVM内存区域分为线程私有区域(程序计数器、虚拟机栈、本地方法区),线程共享区域(堆内存、方法区)和直接内存。 - -img - -+ 程序计数器 - -程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指令,每个运行中的线程都有一个独立的程序计数器,在方法正在执行时,该方法的程序计数器记录的是实时虚拟机字节码指令的地址;如果该方法执行的是Native方法,则程序计数器的值为空。 - -+ 虚拟机栈 - -虚拟机栈是描述Java方法的执行过程的内存模型,它在当前栈帧存储了局部变量表、操作数栈、动态链接、方法出口等信息。同时,栈帧用来存储部分运行时数据及其数据结构,处理动态链接方法的返回值和异常分派。 - -+ 本地方法区 - -本地方法区和虚拟机栈作用类似,区别就是本地方法栈是为Native方法服务,而虚拟机栈是为了Java方法服务。 - -+ 堆内存 - -在JVM运行过程中创建的对象和产生的数据都被存储在堆中,堆是被线程共享的内存区域,也是垃圾收集器进行垃圾回首的最主要的内存区域。 - -+ 方法区 - -方法区用于存储常量、静态变量、类信息、即时编译器编译后的机器码、运行时常量等数据。 - - - diff --git "a/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/README.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/README.md" new file mode 100644 index 0000000..94e0a88 --- /dev/null +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/README.md" @@ -0,0 +1,17 @@ +# Java并发编程 + * [为什么说本质上实现线程的方法只有一种](docs/Java并发编程/为什么说本质上实现线程的方法只有一种.md) + * [可能会遇到的三类线程安全问题](docs/Java并发编程/可能会遇到的三类线程安全问题.md) + * [哪些场景需要额外注意线程安全问题](docs/Java并发编程/哪些场景需要额外注意线程安全问题.md) + * [理解Callable和Runnable的不同](docs/Java并发编程/理解Callable和Runnable的不同.md) + * [理解CAS优缺点](docs/Java并发编程/理解CAS优缺点.md) + * [理解Java中的各种锁](docs/Java并发编程/理解Java中的各种锁.md) + * [理解Java中的锁及其特点](docs/Java并发编程/理解Java中的锁及其特点.md) + * [理解JVM内存结构与Java内存模型](docs/Java并发编程/理解JVM内存结构与Java内存模型.md) + * [理解synchronized关键字](docs/Java并发编程/理解synchronized关键字.md) + * [理解ThreadLocal](docs/Java并发编程/理解ThreadLocal.md) + * [理解线程与死锁](docs/Java并发编程/理解线程与死锁.md) + * [理解线程安全synchronized与ReentrantLock](docs/Java并发编程/理解线程安全synchronized与ReentrantLock.md) + * [理解线程池](docs/Java并发编程/理解线程池.md) + * [理解线程池4种拒绝策略](docs/Java并发编程/理解线程池4种拒绝策略.md) + * [理解线程的状态及如何进行转换的](docs/Java并发编程/理解线程的状态及如何进行转换的.md) + * [第2章Java并发机制的底层原理](docs/Java并发编程/为什么说本质上实现线程的方法只有一种.md) diff --git "a/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/_sidebar.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/_sidebar.md" new file mode 100644 index 0000000..5b75b0c --- /dev/null +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/_sidebar.md" @@ -0,0 +1,17 @@ +* **👉 Java并发编程** [↩](/README) + * [为什么说本质上实现线程的方法只有一种](docs/Java并发编程/为什么说本质上实现线程的方法只有一种.md) + * [可能会遇到的三类线程安全问题](docs/Java并发编程/可能会遇到的三类线程安全问题.md) + * [哪些场景需要额外注意线程安全问题](docs/Java并发编程/哪些场景需要额外注意线程安全问题.md) + * [理解Callable和Runnable的不同](docs/Java并发编程/理解Callable和Runnable的不同.md) + * [理解CAS优缺点](docs/Java并发编程/理解CAS优缺点.md) + * [理解Java中的各种锁](docs/Java并发编程/理解Java中的各种锁.md) + * [理解Java中的锁及其特点](docs/Java并发编程/理解Java中的锁及其特点.md) + * [理解JVM内存结构与Java内存模型](docs/Java并发编程/理解JVM内存结构与Java内存模型.md) + * [理解synchronized关键字](docs/Java并发编程/理解synchronized关键字.md) + * [理解ThreadLocal](docs/Java并发编程/理解ThreadLocal.md) + * [理解线程与死锁](docs/Java并发编程/理解线程与死锁.md) + * [理解线程安全synchronized与ReentrantLock](docs/Java并发编程/理解线程安全synchronized与ReentrantLock.md) + * [理解线程池](docs/Java并发编程/理解线程池.md) + * [理解线程池4种拒绝策略](docs/Java并发编程/理解线程池4种拒绝策略.md) + * [理解线程的状态及如何进行转换的](docs/Java并发编程/理解线程的状态及如何进行转换的.md) + * [第2章Java并发机制的底层原理](docs/Java并发编程/为什么说本质上实现线程的方法只有一种.md) \ No newline at end of file diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\344\270\272\344\273\200\344\271\210\350\257\264\346\234\254\350\264\250\344\270\212\345\256\236\347\216\260\347\272\277\347\250\213\347\232\204\346\226\271\346\263\225\345\217\252\346\234\211\344\270\200\347\247\215.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\344\270\272\344\273\200\344\271\210\350\257\264\346\234\254\350\264\250\344\270\212\345\256\236\347\216\260\347\272\277\347\250\213\347\232\204\346\226\271\346\263\225\345\217\252\346\234\211\344\270\200\347\247\215.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\344\270\272\344\273\200\344\271\210\350\257\264\346\234\254\350\264\250\344\270\212\345\256\236\347\216\260\347\272\277\347\250\213\347\232\204\346\226\271\346\263\225\345\217\252\346\234\211\344\270\200\347\247\215.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\344\270\272\344\273\200\344\271\210\350\257\264\346\234\254\350\264\250\344\270\212\345\256\236\347\216\260\347\272\277\347\250\213\347\232\204\346\226\271\346\263\225\345\217\252\346\234\211\344\270\200\347\247\215.md" index 06f4100..aaa6efc 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\344\270\272\344\273\200\344\271\210\350\257\264\346\234\254\350\264\250\344\270\212\345\256\236\347\216\260\347\272\277\347\250\213\347\232\204\346\226\271\346\263\225\345\217\252\346\234\211\344\270\200\347\247\215.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\344\270\272\344\273\200\344\271\210\350\257\264\346\234\254\350\264\250\344\270\212\345\256\236\347\216\260\347\272\277\347\250\213\347\232\204\346\226\271\346\263\225\345\217\252\346\234\211\344\270\200\347\247\215.md" @@ -1,4 +1,4 @@ -# 为什么说本质上实现线程的方法只有一种? +# 👉 为什么说本质上实现线程的方法只有一种? > 在本课时我们主要学习为什么说本质上只有一种实现线程的方式?实现 Runnable 接口究竟比继承 Thread 类实现线程好在哪里? diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\345\217\257\350\203\275\344\274\232\351\201\207\345\210\260\347\232\204\344\270\211\347\261\273\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\345\217\257\350\203\275\344\274\232\351\201\207\345\210\260\347\232\204\344\270\211\347\261\273\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\345\217\257\350\203\275\344\274\232\351\201\207\345\210\260\347\232\204\344\270\211\347\261\273\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\345\217\257\350\203\275\344\274\232\351\201\207\345\210\260\347\232\204\344\270\211\347\261\273\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" index 65e0584..7a27b33 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\345\217\257\350\203\275\344\274\232\351\201\207\345\210\260\347\232\204\344\270\211\347\261\273\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\345\217\257\350\203\275\344\274\232\351\201\207\345\210\260\347\232\204\344\270\211\347\261\273\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" @@ -1,3 +1,5 @@ +# 👉 可能会遇到的三类线程安全问题 + >本文我们一起学习在实际工作中可能会遇到的三类线程安全问题。 ## 什么是线程安全 要想弄清楚有哪 3 类线程安全问题,首先需要了解什么是线程安全,线程安全经常在工作中被提到,比如:你的对象不是线程安全的,你的线程发生了安全错误,虽然线程安全经常被提到,但我们可能对线程安全并没有一个明确的定义。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\345\223\252\344\272\233\345\234\272\346\231\257\351\234\200\350\246\201\351\242\235\345\244\226\346\263\250\346\204\217\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\345\223\252\344\272\233\345\234\272\346\231\257\351\234\200\350\246\201\351\242\235\345\244\226\346\263\250\346\204\217\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" similarity index 98% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\345\223\252\344\272\233\345\234\272\346\231\257\351\234\200\350\246\201\351\242\235\345\244\226\346\263\250\346\204\217\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\345\223\252\344\272\233\345\234\272\346\231\257\351\234\200\350\246\201\351\242\235\345\244\226\346\263\250\346\204\217\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" index 25ee63f..a30ac4f 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\345\223\252\344\272\233\345\234\272\346\231\257\351\234\200\350\246\201\351\242\235\345\244\226\346\263\250\346\204\217\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\345\223\252\344\272\233\345\234\272\346\231\257\351\234\200\350\246\201\351\242\235\345\244\226\346\263\250\346\204\217\347\272\277\347\250\213\345\256\211\345\205\250\351\227\256\351\242\230.md" @@ -1,7 +1,6 @@ -> 本文我们一起学习在实际开发中哪些场景需要额外注意线程安全问题? - - +# 👉 哪些场景需要额外注意线程安全问题 +> 本文我们一起学习在实际开发中哪些场景需要额外注意线程安全问题? ## 1.访问共享变量或资源 第一种场景是访问共享变量或共享资源的时候,典型的场景有访问共享对象的属性,访问 static 静态变量,访问共享的缓存,等等。因为这些信息不仅会被一个线程访问到,还有可能被多个线程同时访问,那么就有可能在并发读写的情况下发生线程安全问题。比如我们上一课时讲过的多线程同时 i++ 的例子: diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243CAS\344\274\230\347\274\272\347\202\271.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243CAS\344\274\230\347\274\272\347\202\271.md" similarity index 98% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243CAS\344\274\230\347\274\272\347\202\271.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243CAS\344\274\230\347\274\272\347\202\271.md" index 62d4d91..1c3a819 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243CAS\344\274\230\347\274\272\347\202\271.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243CAS\344\274\230\347\274\272\347\202\271.md" @@ -1,4 +1,4 @@ -# CAS有很多优点,但它的缺点呢? +# 👉 CAS有很多优点,但它的缺点呢? > 本文我们一起学习探讨CAS的缺点。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Callable\345\222\214Runnable\347\232\204\344\270\215\345\220\214.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Callable\345\222\214Runnable\347\232\204\344\270\215\345\220\214.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Callable\345\222\214Runnable\347\232\204\344\270\215\345\220\214.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Callable\345\222\214Runnable\347\232\204\344\270\215\345\220\214.md" index 33bc68b..5d0f976 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Callable\345\222\214Runnable\347\232\204\344\270\215\345\220\214.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Callable\345\222\214Runnable\347\232\204\344\270\215\345\220\214.md" @@ -1,5 +1,5 @@ -# Callable和Runnable的不同? +# 👉 Callable和Runnable的不同? > 本文我们一起学习 Callable 和 Runnable 的不同。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243JVM\345\206\205\345\255\230\347\273\223\346\236\204\344\270\216Java\345\206\205\345\255\230\346\250\241\345\236\213.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243JVM\345\206\205\345\255\230\347\273\223\346\236\204\344\270\216Java\345\206\205\345\255\230\346\250\241\345\236\213.md" similarity index 97% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243JVM\345\206\205\345\255\230\347\273\223\346\236\204\344\270\216Java\345\206\205\345\255\230\346\250\241\345\236\213.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243JVM\345\206\205\345\255\230\347\273\223\346\236\204\344\270\216Java\345\206\205\345\255\230\346\250\241\345\236\213.md" index d9c5bd5..7c8fcff 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243JVM\345\206\205\345\255\230\347\273\223\346\236\204\344\270\216Java\345\206\205\345\255\230\346\250\241\345\236\213.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243JVM\345\206\205\345\255\230\347\273\223\346\236\204\344\270\216Java\345\206\205\345\255\230\346\250\241\345\236\213.md" @@ -1,5 +1,4 @@ - -# 不要在混淆JVM内存结构与Java内存模型了! +# 👉 不要在混淆JVM内存结构与Java内存模型了! > 本文我们一起学习什么是Java内存模型。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" index 03a4f68..2a28a65 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" @@ -1,4 +1,4 @@ -## 理解Java中的各种锁 +# 👉 理解Java中的各种锁 如果说快速理解多线程有什么捷径的话,那本文介绍的各种锁无疑是其中之一,它不但为我们开发多线程程序提供理论支持,还是面试中经常被问到的核心面试题之一。因此下面就让我们一起深入地学习一下这些锁吧。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\351\224\201\345\217\212\345\205\266\347\211\271\347\202\271.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\351\224\201\345\217\212\345\205\266\347\211\271\347\202\271.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\351\224\201\345\217\212\345\205\266\347\211\271\347\202\271.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\351\224\201\345\217\212\345\205\266\347\211\271\347\202\271.md" index 0adcda7..657c578 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\351\224\201\345\217\212\345\205\266\347\211\271\347\202\271.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243Java\344\270\255\347\232\204\351\224\201\345\217\212\345\205\266\347\211\271\347\202\271.md" @@ -1,4 +1,4 @@ -# Java中哪几种锁?分别有什么特点? +# 👉 Java中哪几种锁?分别有什么特点? > 本文中我们一起学习Java中锁的分类及其特点。 锁是用来控制多线程访问共享资源的方式,一般的讲,一个锁能够防止多个线程同时访问共享资源。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243ThreadLocal.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243ThreadLocal.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243ThreadLocal.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243ThreadLocal.md" index b78f9b6..fc69799 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243ThreadLocal.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243ThreadLocal.md" @@ -1,4 +1,4 @@ -## 理解ThreadLocal +# 👉 理解ThreadLocal **什么是 ThreadLocal?** ThreadLocal 诞生于 JDK 1.2,用于解决多线程间的数据隔离问题。也就是说 ThreadLocal 会为每一个线程创建一个单独的变量副本。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243synchronized\345\205\263\351\224\256\345\255\227.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243synchronized\345\205\263\351\224\256\345\255\227.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243synchronized\345\205\263\351\224\256\345\255\227.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243synchronized\345\205\263\351\224\256\345\255\227.md" index 779eda2..8b0626b 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243synchronized\345\205\263\351\224\256\345\255\227.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243synchronized\345\205\263\351\224\256\345\255\227.md" @@ -1,4 +1,4 @@ -# synchronized关键字原理 +# 👉 synchronized关键字原理 众所周知 `synchronized` 关键字是解决并发问题常用解决方案,有以下三种使用方式: diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\344\270\216\346\255\273\351\224\201.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\344\270\216\346\255\273\351\224\201.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\344\270\216\346\255\273\351\224\201.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\344\270\216\346\255\273\351\224\201.md" index 8637caa..68ce72c 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\344\270\216\346\255\273\351\224\201.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\344\270\216\346\255\273\351\224\201.md" @@ -1,4 +1,4 @@ -## 理解线程与死锁 +# 👉 理解线程与死锁 ### 线程介绍 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\345\256\211\345\205\250synchronized\344\270\216ReentrantLock.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\345\256\211\345\205\250synchronized\344\270\216ReentrantLock.md" similarity index 99% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\345\256\211\345\205\250synchronized\344\270\216ReentrantLock.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\345\256\211\345\205\250synchronized\344\270\216ReentrantLock.md" index 393737a..92af496 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\345\256\211\345\205\250synchronized\344\270\216ReentrantLock.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\345\256\211\345\205\250synchronized\344\270\216ReentrantLock.md" @@ -1,4 +1,4 @@ -## 理解线程安全synchronized与ReentrantLock +# 👉 理解线程安全synchronized与ReentrantLock 前面我们介绍了很多关于多线程的内容,在多线程中有一个很重要的课题需要我们攻克,那就是线程安全问题。线程安全问题指的是在多线程中,各线程之间因为同时操作所产生的数据污染或其他非预期的程序运行结果。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\240.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\240.md" similarity index 100% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\240.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\240.md" diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\2404\347\247\215\346\213\222\347\273\235\347\255\226\347\225\245.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\2404\347\247\215\346\213\222\347\273\235\347\255\226\347\225\245.md" similarity index 98% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\2404\347\247\215\346\213\222\347\273\235\347\255\226\347\225\245.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\2404\347\247\215\346\213\222\347\273\235\347\255\226\347\225\245.md" index c9a9297..90500ee 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\2404\347\247\215\346\213\222\347\273\235\347\255\226\347\225\245.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\346\261\2404\347\247\215\346\213\222\347\273\235\347\255\226\347\225\245.md" @@ -1,10 +1,9 @@ -> 本文我们一起学习线程池有哪 4 种默认的拒绝策略。 +# 👉 线程池的拒绝策略 -# 线程池的拒绝策略 +> 本文我们一起学习线程池有哪 4 种默认的拒绝策略。 若线程池中的核心线程数被用完且阻塞队列已排满,则此时线程池的资源已耗尽,线程池将没有足够的线程资源执行新的任务。为了保证操作系统的安全,线程池将通过拒绝策略处理新添加的线程任务。 - ## 1. AbortPolicy 第一种拒绝策略是 `AbortPolicy`,这种拒绝策略在拒绝任务时,会直接抛出一个类型为 RejectedExecutionException的RuntimeException,让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。 diff --git "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\347\232\204\347\212\266\346\200\201\345\217\212\345\246\202\344\275\225\350\277\233\350\241\214\350\275\254\346\215\242\347\232\204.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\347\232\204\347\212\266\346\200\201\345\217\212\345\246\202\344\275\225\350\277\233\350\241\214\350\275\254\346\215\242\347\232\204.md" similarity index 98% rename from "docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\347\232\204\347\212\266\346\200\201\345\217\212\345\246\202\344\275\225\350\277\233\350\241\214\350\275\254\346\215\242\347\232\204.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\347\232\204\347\212\266\346\200\201\345\217\212\345\246\202\344\275\225\350\277\233\350\241\214\350\275\254\346\215\242\347\232\204.md" index 3618b62..1612d62 100644 --- "a/docs/\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\347\232\204\347\212\266\346\200\201\345\217\212\345\246\202\344\275\225\350\277\233\350\241\214\350\275\254\346\215\242\347\232\204.md" +++ "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\220\206\350\247\243\347\272\277\347\250\213\347\232\204\347\212\266\346\200\201\345\217\212\345\246\202\344\275\225\350\277\233\350\241\214\350\275\254\346\215\242\347\232\204.md" @@ -1,3 +1,4 @@ +# 👉 理解线程的状态及如何进行转换的 > 本文我们一起学习线程的状态有哪些以及它们之间是如何进行转换的? 线程(Thread)是并发编程的基础,也是程序执行的最小单元,它依托进程而存在。一个进程中可以包含多个线程,多线程可以共享一块内存空间和一组系统资源,因此线程之间的切换更加节省资源、更加轻量化,也因此被称为轻量级的进程。 diff --git "a/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213\347\232\204\350\211\272\346\234\257/\347\254\2542\347\253\240Java\345\271\266\345\217\221\346\234\272\345\210\266\347\232\204\345\272\225\345\261\202\345\216\237\347\220\206.md" "b/docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\254\2542\347\253\240Java\345\271\266\345\217\221\346\234\272\345\210\266\347\232\204\345\272\225\345\261\202\345\216\237\347\220\206.md" similarity index 100% rename from "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213\347\232\204\350\211\272\346\234\257/\347\254\2542\347\253\240Java\345\271\266\345\217\221\346\234\272\345\210\266\347\232\204\345\272\225\345\261\202\345\216\237\347\220\206.md" rename to "docs/Java\345\271\266\345\217\221\347\274\226\347\250\213/\347\254\2542\347\253\240Java\345\271\266\345\217\221\346\234\272\345\210\266\347\232\204\345\272\225\345\261\202\345\216\237\347\220\206.md" diff --git "a/docs/Java\345\274\200\345\217\221\350\247\204\350\214\203/Java\345\274\200\345\217\221\346\211\213\345\206\214\345\265\251\345\261\261\347\211\210.md" "b/docs/Java\345\274\200\345\217\221\350\247\204\350\214\203/Java\345\274\200\345\217\221\346\211\213\345\206\214\345\265\251\345\261\261\347\211\210.md" new file mode 100644 index 0000000..f67b914 --- /dev/null +++ "b/docs/Java\345\274\200\345\217\221\350\247\204\350\214\203/Java\345\274\200\345\217\221\346\211\213\345\206\214\345\265\251\345\261\261\347\211\210.md" @@ -0,0 +1,255 @@ +# 👉 Java开发手册 嵩山版 + +| 版本 | 制定 | 更新日期 | 备注 | +| :---: | :----------------------------: | :--------: | :------------------------: | +| 1.7.0 | 阿里巴巴与全球 Java 社区开发者 | 2020.08.03 | 嵩山版,首次发布前后端规约 + + ## 一、 编程规约 + +### (一) 命名风格 + +1. **【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。** + + > **反例:_name / __name / $name / name_ / name$ / name__** + +2. **【强制】所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。** + + **说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,纯拼音命名方式更要避免采用。** + + > **正例:ali / alibaba / taobao / cainiao/ aliyun/ youku / hangzhou 等国际通用的名称,可视同英文。** + > + > **反例:DaZhePromotion [打折] / getPingfenByName() [评分] / String fw[福娃] / int 某变量 = 3** + +3. **【强制】代码和注释中都要避免使用任何语言的种族歧视性词语。** + + > **正例:日本人 / 印度人 / blockList / allowList / secondary** + > + > **反例:RIBENGUIZI / Asan / blackList / whiteList / slave** + +4. **【强制】类名使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等。** + + > **正例:ForceCode / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion** + > + > **反例:forcecode / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion** + +5. **【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格。** + + > **正例: localValue / getHttpMessage() / inputUserId** + +6. **【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。** + + > **正例:MAX_STOCK_COUNT / CACHE_EXPIRED_TIME 反例:MAX_COUNT / EXPIRED_TIME** + +7. **【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类 命名以它要测试的类的名称开始,以 Test 结尾。** + +8. **【强制】类型与中括号紧挨相连来表示数组。 正例:定义整形数组 int[] arrayDemo。** + + > **反例:在 main 参数中,使用 String args[]来定义。** + +9. **【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列 化错误。** + + **说明:在本文 MySQL 规约中的建表约定第一条,表达是与否的变量采用 is_xxx 的命名方式,所以,需要 在设置从 is_xxx 到 xxx 的映射关系。** + + > **反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),框架在反向解析的时 候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。** + +10. **【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用 单数形式,但是类名如果有复数含义,类名可以使用复数形式。** + + > **正例:应用工具类包名为 com.alibaba.ei.kunlun.aap.util、类名为 MessageUtils(此规则参考 spring 的 框架结构)** + +11. **【强制】避免在子父类的成员变量之间、或者不同代码块的局部变量之间采用完全相同的命名, 使可理解性降低。** + + **说明:子类、父类成员变量名相同,即使是 public 类型的变量也能够通过编译,另外,局部变量在同一方 法内的不同代码块中同名也是合法的,这些情况都要避免。对于非 setter/getter 的参数名称也要避免与成 员变量名称相同。** + + ```java + 反例: + public class ConfusingName { + public int stock; + // 非 setter/getter 的参数名称,不允许与本类成员变量同名 + public void get(String alibaba) { + if (condition) { + final int money = 666; + // ... + } + for (int i = 0; i < 10; i++) { + // 在同一方法体中,不允许与其它代码块中的 money 命名相同 + final int money = 15978; + // ... + } + } + } + class Son extends ConfusingName { + // 不允许与父类的成员变量名称相同 + public int stock; + } + ``` + +12. **【强制】杜绝完全不规范的缩写,避免望文不知义。** + + > **反例:AbstractClass“缩写”成 AbsClass;condition“缩写”成 condi;Function 缩写”成 Fu,此类 随意缩写严重降低了代码的可阅读性。** + +13. **【推荐】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组 合来表达。** + + > **正例:对某个对象引用的 volatile 字段进行原子更新的类名为 AtomicReferenceFieldUpdater。** + > + > **反例:常见的方法内变量为 int a;的定义方式**。 + +14. **【推荐】在常量与变量的命名时,表示类型的名词放在词尾,以提升辨识度。** + + > **正例:startTime / workQueue / nameList / TERMINATED_THREAD_COUNT** + > + > **反例:startedAt / QueueOfWork / listName / COUNT_TERMINATED_THREAD** + +15. **【推荐】如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式。** + + **说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。** + + > 正例: public class OrderFactory; + > + > ​ public class LoginProxy; + > + > ​ public class ResourceObserver; + +16. **【推荐】接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁 性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,确定 与接口方法相关,并且是整个应用的基础常量。** + + > 正例:接口方法签名 void commit(); 接口基础常量 String COMPANY = "alibaba"; + > + > 反例:接口方法定义 public abstract void f(); + + **说明:JDK8 中接口允许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默认实现。** + +17. **接口和实现类的命名有两套规则:** + + **1)【强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。** + + > **正例:CacheServiceImpl 实现 CacheService 接口。** + + **2)【推荐】如果是形容能力的接口名称,取对应的形容词为接口名(通常是–able 的形容词)。** + + > **正例:AbstractTranslator 实现 Translatable 接口。** + +18. **【参考】枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。** + + **说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。** + + > 正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON。 + +19. **【参考】各层命名规约:** + + **A) Service/DAO 层方法命名规约** + + **1) 获取单个对象的方法用 get 做前缀。** + + **2) 获取多个对象的方法用 list 做前缀,复数结尾,如:listObjects。** + + **3) 获取统计值的方法用 count 做前缀。** + + **4) 插入的方法用 save/insert 做前缀。** + + **5) 删除的方法用 remove/delete 做前缀。** + + **6) 修改的方法用 update 做前缀。** + + **B) 领域模型命名规约 Java 开发手册 4/59** + + **1) 数据对象:xxxDO,xxx 即为数据表名。** + + **2) 数据传输对象:xxxDTO,xxx 为业务领域相关的名称。** + + **3) 展示对象:xxxVO,xxx 一般为网页名称。** + + **4) POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。** + +### (二) 常量定义 + +1. **【强制】不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。** + + > **反例: // 本例中,开发者 A 定义了缓存的 key,然后开发者 B 使用缓存时少了下划线,即 key 是"Id#taobao"+tradeId,导致 出现故障** + > + > **String key = "Id#taobao_" + tradeId; cache.put(key, value);** + +2. **【强制】在 long 或者 Long 赋值时,数值后使用大写字母 L,不能是小写字母 l,小写容易跟 数字混淆,造成误解。** + + > **说明:Long a = 2l; 写的是数字的 21,还是 Long 型的 2?** + +3. 【**推荐】不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。** + + **说明:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解,也不利于维护。** + + > **正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 SystemConfigConsts 下。** + +4. **【推荐】常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包 内共享常量、类内共享常量。** + + **1) 跨应用共享常量:放置在二方库中,通常是 client.jar 中的 constant 目录下。** + + **2) 应用内共享常量:放置在一方库中,通常是子模块中的 constant 目录下。** + + > **反例:易懂变量也要统一定义成应用内共享常量,两位工程师在两个类中分别定义了“YES”的变量:** + > + > **类 A 中:public static final String YES = "yes";** + > + > **类 B 中:public static final String YES = "y"; A.YES.equals(B.YES),预期是 true,但实际返回为 false,导致线上问题。** + + **3) 子工程内部共享常量:即在当前子工程的 constant 目录下。** + + **4) 包内共享常量:即在当前包下单独的 constant 目录下。** + + **5) 类内共享常量:直接在类内部 private static final 定义。** + +5. + +### (三) 代码格式 + +### (四) OOP 规约 + +### (五) 日期时间 + +### (六) 集合处理 + +### (七) 并发处理 + +### (八) 控制语句 + +### (九) 注释规约 + +### (十) 前后端规约 + +### (十一) 其他 + +## 二、异常日志 + +### (一) 错误码 + +### (二) 异常处理 + +### (三) 日志规约 + +## 三、单元测试 + +## 四、安全规约 + +## 五、MySQL 数据库 + +### (一) 建表规约 + +### (二) 索引规约 + +### (三) SQL 语句 + +### (四) ORM 映射 + +## 六、工程结构 + +### (一) 应用分层 + +### (二) 二方库依赖 + +### (三) 服务器 + +## 七、设计规约 + +# 附 1:专有名词解释 + +# 附 2:错误码列表 + + + diff --git "a/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/README.md" "b/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/README.md" new file mode 100644 index 0000000..47f4eec --- /dev/null +++ "b/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/README.md" @@ -0,0 +1,3 @@ +# Java性能优化 + +* [常见Java代码优化法则](docs/Java并发编程/常见Java代码优化法则.md) diff --git "a/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/_sidebar.md" "b/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/_sidebar.md" new file mode 100644 index 0000000..828be2b --- /dev/null +++ "b/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/_sidebar.md" @@ -0,0 +1,3 @@ +* **👉 Java性能优化** [↩](/README) + * [常见Java代码优化法则](docs/Java性能优化/常见Java代码优化法则.md) + \ No newline at end of file diff --git "a/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/\345\270\270\350\247\201Java\344\273\243\347\240\201\344\274\230\345\214\226\346\263\225\345\210\231.md" "b/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/\345\270\270\350\247\201Java\344\273\243\347\240\201\344\274\230\345\214\226\346\263\225\345\210\231.md" new file mode 100644 index 0000000..2eb7417 --- /dev/null +++ "b/docs/Java\346\200\247\350\203\275\344\274\230\345\214\226/\345\270\270\350\247\201Java\344\273\243\347\240\201\344\274\230\345\214\226\346\263\225\345\210\231.md" @@ -0,0 +1,89 @@ +# 👉 常见Java代码优化法则 + +## 1.使用局部变量可避免在堆上分配 +由于堆资源是多线程共享的,是垃圾回收器工作的主要区域,过多的对象会造成 GC 压力。可以通过局部变量的方式,将变量在栈上分配。这种方式变量会随着方法执行的完毕而销毁,能够减轻 GC 的压力。 + +## 2.削弱变量的作用范围 +注意变量的作用范围,尽量减少对象的创建。如下面的代码,变量 a 每次进入方法都会创建,可以将它移动到 if 语句内部。 + +## 3.使用类名方式访问静态变量 +有的同学习惯使用对象访问静态变量,这种方式多了一步寻址操作,需要先找到变量对应的类,再找到类对应的变量。 + +## 4.字符串拼接不要使用 ”+” +字符串拼接,使用 `StringBuilder `或者` StringBuffer`,不要使用 + 号。 + +## 5.重写对象的`HashCode`,不要简单地返回固定值 +开发时重写 `HashCode` 和`Equals` 方法时,会把 `HashCode `的值返回固定的 0,而这样做是不恰当的。 + +当这些对象存入 `HashMap` 时,性能就会非常低,因为 `HashMap `是通过 `HashCode` 定位到 Hash 槽,有冲突的时候,才会使用链表或者红黑树组织节点。固定地返回 0,相当于把 Hash 寻址功能给废除了。 + +## 6.`HashMap `等集合初始化的时候,尽量指定初始值大小 +通过指定初始值大小可减少扩容造成的性能损耗。 + +## 7.遍历`Map` 的时候,使用 `EntrySet` 方法 +使用 EntrySet 方法,可以直接返回 set 对象,直接拿来用即可;而使用 KeySet 方法,获得的是key 的集合,需要再进行一次 get 操作,多了一个操作步骤。所以更推荐使用 EntrySet 方式遍历 Map。 + +## 8.不要在多线程下使用同一个 Random +Random 类的 seed 会在并发访问的情况下发生竞争,造成性能降低,建议在多线程环境下使用 `ThreadLocalRandom` 类。 + +> 在 Linux 上,通过加入 JVM 配置 -Djava.security.egd=file:/dev/./urandom,使用 urandom 随机生成器,在进行随机数获取时,速度会更快。 + +## 9.自增推荐使用 LongAddr +自增运算可以通过 synchronized 和 volatile 的组合,或者也可以使用原子类(比如 AtomicLong)。 + +后者的速度比前者要高一些,AtomicLong 使用 CAS 进行比较替换,在线程多的情况下会造成过多无效自旋,所以可以使用 LongAdder 替换 AtomicLong 进行进一步的性能提升。 + +## 10.不要使用异常控制程序流程 +异常,是用来了解并解决程序中遇到的各种不正常的情况,它的实现方式比较昂贵,比平常的条件判断语句效率要低很多。 + +这是因为异常在字节码层面,需要生成一个如下所示的异常表(Exception table),多了很多判断步骤。 + +## 11.不要在循环中使用 try catch +道理与上面类似,很多文章介绍,不要把异常处理放在循环里,而应该把它放在最外层,但实际测试情况表明这两种方式性能相差并不大。 + +既然性能没什么差别,那么就推荐根据业务的需求进行编码。比如,循环遇到异常时,不允许中断,也就是允许在发生异常的时候能够继续运行下去,那么异常就只能在 for 循环里进行处理。 + +## 12.不要捕捉 RuntimeException +Java 异常分为两种,一种是可以通过预检查机制避免的 RuntimeException;另外一种就是普通异常。 + +其中,RuntimeException 不应该通过 catch 语句去捕捉,而应该使用编码手段进行规避。 + +## 13.合理使用 PreparedStatement +PreparedStatement 使用预编译对 SQL 的执行进行提速,大多数数据库都会努力对这些能够复用的查询语句进行预编译优化,并能够将这些编译结果缓存起来。 + +这样等到下次用到的时候,就可以很快进行执行,也就少了一步对 SQL 的解析动作。 + +PreparedStatement 还能提高程序的安全性,能够有效防止 SQL 注入。 + +但如果你的程序每次 SQL 都会变化,不得不手工拼接一些数据,那么 PreparedStatement 就失去了它的作用,反而使用普通的 Statement 速度会更快一些。 + +## 14.日志打印的注意事项 + debug 输出一些调试信息,然后在线上关掉它。 + +## 15.减少事务的作用范围 +如果的程序使用了事务,那一定要注意事务的作用范围,尽量以最快的速度完成事务操作。这是因为,事务的隔离性是使用锁实现的。 + +## 16.使用位移操作替代乘除法 +计算机是使用二进制表示的,位移操作会极大地提高性能。 + +- `<<` 左移相当于乘以 2; +- `<<` 右移相当于除以 2; +- `>>>`无符号右移相当于除以 2,但它会忽略符号位,空位都以 0 补齐。 + +## 17.不要打印大集合或者使用大集合的 toString 方法 +有的开发喜欢将集合作为字符串输出到日志文件中,这个习惯是非常不好的。 + +拿 ArrayList 来说,它需要遍历所有的元素来迭代生成字符串。在集合中元素非常多的情况下,这不仅会占用大量的内存空间,执行效率也非常慢 + +## 18.尽量少在程序中使用反射 +反射的功能很强大,但它是通过解析字节码实现的,性能就不是很理想。 + +现实中有很多对反射的优化方法,比如把反射执行的过程(比如 Method)缓存起来,使用复用来加快反射速度。 + +Java 7.0 之后,加入了新的包 java.lang.invoke,同时加入了新的 JVM 字节码指令 invokedynamic,用来支持从 JVM 层面,直接通过字符串对目标方法进行调用。 + +如果你对性能有非常苛刻的要求,则使用 invoke 包下的 MethodHandle 对代码进行着重优化,但它的编程不如反射方便,在平常的编码中,反射依然是首选。 + +## 19.正则表达式可以预先编译,加快速度 +Java 的正则表达式需要先编译再使用。 + diff --git "a/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/README.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/README.md" new file mode 100644 index 0000000..a816816 --- /dev/null +++ "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/README.md" @@ -0,0 +1 @@ +![Ga7vC.png](https://s.im5i.com/2021/04/14/Ga7vC.png) \ No newline at end of file diff --git "a/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/_sidebar.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/_sidebar.md" new file mode 100644 index 0000000..fae09b2 --- /dev/null +++ "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/_sidebar.md" @@ -0,0 +1,20 @@ +* **👉 Java核心基础** [↩](/README) + * [理解Java关键字](docs/Java核心基础/理解Java关键字.md) + * [理解String字符串](docs/Java核心基础/理解String字符串.md) + * [理解基本数据类型与包装类](docs/Java核心基础/理解基本数据类型与包装类.md) + * [理解各种内部类和枚举类](docs/Java核心基础/理解各种内部类和枚举类.md) + * [理解动态代理](docs/Java核心基础/理解动态代理.md) + * [理解克隆与序列化应用](docs/Java核心基础/理解克隆与序列化应用.md) + * [理解异常处理](docs/Java核心基础/理解异常处理.md) + * [理解抽象类与接口](docs/Java核心基础/理解抽象类与接口.md) + * [理解泛型与迭代器](docs/Java核心基础/理解泛型与迭代器.md) + * [理解浅克隆和深克隆](docs/Java核心基础/理解浅克隆和深克隆.md) + * [理解类与Object](docs/Java核心基础/理解类与Object.md) + * [理解集合Collection](docs/Java核心基础/理解集合Collection.md) + * [理解集合Map](docs/Java核心基础/理解集合Map.md) + * [理解Java中的各种锁](docs/Java核心基础/理解Java中的各种锁.md) + * [理解HashMap底层实现原理](docs/Java核心基础/理解HashMap底层实现原理.md) + * [理解HashMap为什么是线程不安全的](docs/Java核心基础/理解HashMap为什么是线程不安全的.md) + * [理解ConcurrentHashMap底层实现原理](docs/Java核心基础/理解ConcurrentHashMap底层实现原理.md) + * [理解数据结构队列](docs/Java核心基础/理解数据结构队列.md) + \ No newline at end of file diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243ConcurrentHashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243ConcurrentHashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243ConcurrentHashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243ConcurrentHashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243HashMap\344\270\272\344\273\200\344\271\210\346\230\257\347\272\277\347\250\213\344\270\215\345\256\211\345\205\250\347\232\204.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243HashMap\344\270\272\344\273\200\344\271\210\346\230\257\347\272\277\347\250\213\344\270\215\345\256\211\345\205\250\347\232\204.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243HashMap\344\270\272\344\273\200\344\271\210\346\230\257\347\272\277\347\250\213\344\270\215\345\256\211\345\205\250\347\232\204.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243HashMap\344\270\272\344\273\200\344\271\210\346\230\257\347\272\277\347\250\213\344\270\215\345\256\211\345\205\250\347\232\204.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243HashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243HashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243HashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243HashMap\345\272\225\345\261\202\345\256\236\347\216\260\345\216\237\347\220\206.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243Java\344\270\255\347\232\204\345\220\204\347\247\215\351\224\201.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243Java\345\205\263\351\224\256\345\255\227.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243Java\345\205\263\351\224\256\345\255\227.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243Java\345\205\263\351\224\256\345\255\227.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243Java\345\205\263\351\224\256\345\255\227.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243String\345\255\227\347\254\246\344\270\262.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243String\345\255\227\347\254\246\344\270\262.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243String\345\255\227\347\254\246\344\270\262.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243String\345\255\227\347\254\246\344\270\262.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\205\213\351\232\206\344\270\216\345\272\217\345\210\227\345\214\226\345\272\224\347\224\250.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\205\213\351\232\206\344\270\216\345\272\217\345\210\227\345\214\226\345\272\224\347\224\250.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\205\213\351\232\206\344\270\216\345\272\217\345\210\227\345\214\226\345\272\224\347\224\250.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\205\213\351\232\206\344\270\216\345\272\217\345\210\227\345\214\226\345\272\224\347\224\250.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\212\250\346\200\201\344\273\243\347\220\206.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\212\250\346\200\201\344\273\243\347\220\206.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\212\250\346\200\201\344\273\243\347\220\206.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\212\250\346\200\201\344\273\243\347\220\206.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\220\204\347\247\215\345\206\205\351\203\250\347\261\273\345\222\214\346\236\232\344\270\276\347\261\273.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\220\204\347\247\215\345\206\205\351\203\250\347\261\273\345\222\214\346\236\232\344\270\276\347\261\273.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\220\204\347\247\215\345\206\205\351\203\250\347\261\273\345\222\214\346\236\232\344\270\276\347\261\273.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\220\204\347\247\215\345\206\205\351\203\250\347\261\273\345\222\214\346\236\232\344\270\276\347\261\273.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\214\205\350\243\205\347\261\273.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\214\205\350\243\205\347\261\273.md" similarity index 91% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\214\205\350\243\205\347\261\273.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\214\205\350\243\205\347\261\273.md" index 659c6f0..6ca3096 100644 --- "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\214\205\350\243\205\347\261\273.md" +++ "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\214\205\350\243\205\347\261\273.md" @@ -1,6 +1,6 @@ -## 理解基本数据类型与包装类 +# 理解基本数据类型与包装类 -### 基本数据类型 +## 基本数据类型 Java 基本数据按类型可以分为四大类:布尔型、整数型、浮点型、字符型,这四大类包含 8 种基本数据类型。 @@ -35,7 +35,7 @@ public static void main(String[] args) { } ``` -### 包装类型 +## 包装类型 我们知道 8 种基本数据类型都有其对应的包装类,因为 Java 的设计思想是万物既对象,有很多时候我们需要以对象的形式操作某项功能,比如说获取哈希值(hashCode)或获取类(getClass)等。 @@ -121,7 +121,7 @@ public static Integer valueOf(int i) { - Long:缓存区 -128~127 - Integer:缓存区 -128~127 -### 包装类的注意事项 +## 包装类的注意事项 - int 的默认值是 0,而 Integer 的默认值是 null。 - 推荐所有包装类对象之间的值比较使用 `equals()` 方法,因为包装类的非高频区数据会在堆上产生,而高频区又会复用已有对象,这样会导致同样的代码,因为取值的不同,而产生两种截然不同的结果。代码示例: @@ -173,9 +173,9 @@ public static void main(String[] args) { 由此可见将 Integer 最大缓存修改为 666 之后,667 不会被缓存,而 -128~666 之间的数都被缓存了。 -### 相关面试题 +## 相关面试题 -#### 1. 以下 Integer 代码输出的结果是? +### 1. 以下 Integer 代码输出的结果是? ```java Integer age = 10; @@ -187,7 +187,7 @@ System.out.println((age == age2) + "," + (age3 == age4)); 答:`true,false` -#### 2. 以下 Double 代码输出的结果是? +### 2. 以下 Double 代码输出的结果是? ``` Double num = 10d; @@ -199,7 +199,7 @@ System.out.println((num == num2) + "," + (num3 == num4)); 答:`false,false` -#### 3. 以下程序输出结果是? +### 3. 以下程序输出结果是? ```java int i = 100; @@ -217,7 +217,7 @@ D:false,false 题目分析:有人认为这和 Integer 高速缓存有关系,但你发现把值改为 10000 结果也是 `true,true`,这是因为 Integer 和 int 比较时,会自动拆箱为 int 相当于两个 int 比较,值一定是 `true,true`。 -#### 4. 以下程序执行的结果是? +### 4. 以下程序执行的结果是? ```java final int iMax = Integer.MAX_VALUE; @@ -233,7 +233,7 @@ D:以上都不是 题目解析:这是因为整数在内存中使用的是补码的形式表示,最高位是符号位 0 表示正数,1 表示负数,当执行 +1 时,最高位就变成了 1,结果就成了 -2147483648。 -#### 5. 以下程序执行的结果是? +### 5. 以下程序执行的结果是? ```java Set set = new HashSet<>(); @@ -253,36 +253,36 @@ D:以上都不是 题目解析:Short 类型 -1 之后转换成了 Int 类型,remove() 的时候在集合中找不到 Int 类型的数据,所以就没有删除任何元素,执行的结果就是 5。 -#### 6. `short s=2;s=s+1;` 会报错吗?`short s=2;s+=1;` 会报错吗? +### 6. `short s=2;s=s+1;` 会报错吗?`short s=2;s+=1;` 会报错吗? 答:s=s+1 会报错,s+=1 不会报错,因为 s=s+1 会导致 short 类型升级为 int 类型,所以会报错,而 s+=1 还是原来的 short 类型,所以不会报错。 -#### 7. `float f=3.4;` 会报错吗?为什么? +### 7. `float f=3.4;` 会报错吗?为什么? 答:会报错,因为值 3.4 是 double 类型,float 类型级别小于 double 类型,所以会报错。如下图所示: ![报错示例图](https://img02.sogoucdn.com/app/a/100520146/2b8fd3d17b087b32d65ef30f31c7e11c) -#### 8. 为什么需要包装类? +### 8. 为什么需要包装类? 答:需要包装类的原因有两个。 ① Java 的设计思想是万物既对象,包装类体现了面向对象的设计理念; ② 包装类包含了很多属性和方法,比基本数据类型功能多,比如提供的获取哈希值(hashCode)或获取类(getClass)的方法等。 -#### 9. 基本类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗? +### 9. 基本类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗? 答:不正确,只有包装类高频区域数据才有缓存。 -#### 10. 包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗? +### 10. 包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗? 答:不正确,基本数据类型的包装类只有 Double 和 Float 没有高频区域的缓存。 -#### 11. 包装类的值比较要使用什么方法? +### 11. 包装类的值比较要使用什么方法? 答:包装类因为有高频区域数据缓存,所以推荐使用 equals() 方法进行值比较。 -#### 12. 包装类有哪些功能? +### 12. 包装类有哪些功能? 答:包装类提供的功能有以下几个。 @@ -294,11 +294,11 @@ D:以上都不是 详见正文“包装类型”部分内容。 -#### 13. 泛型可以为基本类型吗?为什么? +### 13. 泛型可以为基本类型吗?为什么? 答:泛型不能使用基本数据类型。泛型在 JVM(Java虚拟机)编译的时候会类型檫除,比如代码 `List list` 在 JVM 编译的时候会转换为 `List list` ,因为泛型是在 JDK 5 时提供的,而 JVM 的类型檫除是为了兼容以前代码的一个折中方案,类型檫除之后就变成了 Object,而 Object 不能存储基本数据类型,但可以使用基本数据类型对应的包装类,所以像 `List list` 这样的代码是不被允许的,编译器阶段会检查报错,而 `List list` 是被允许的。 -#### 14. 选择包装类还是基本类的原则有哪些? +### 14. 选择包装类还是基本类的原则有哪些? 答:我们知道正确的使用包装类,可以提供程序的执行效率,可以使用已有的缓存,一般情况下选择基本数据类型还是包装类原则有以下几个。 @@ -306,14 +306,14 @@ D:以上都不是 ② RPC 方法返回值和参数必须使用包装类; ③ 所有局部变量推荐使用基本数据类型。 -#### 15. 基本数据类型在 JVM 中一定存储在栈中吗?为什么? +### 15. 基本数据类型在 JVM 中一定存储在栈中吗?为什么? 答:基本数据类型不一定存储在栈中,因为基本类型的存储位置取决于声明的作用域,来看具体的解释。 - 当基本数据类型为局部变量的时候,比如在方法中声明的变量,则存放在方法栈中的,当方法结束系统会释放方法栈,在该方法中的变量也会随着栈的销毁而结束,这也是局部变量只能在方法中使用的原因; - 当基本数据类型为全局变量的时候,比如类中的声明的变量,则存储在堆上,因为全局变量不会随着某个方法的执行结束而销毁。 -#### 16. 以下程序执行的结果是? +### 16. 以下程序执行的结果是? ```java Integer i1 = new Integer(10); @@ -334,7 +334,7 @@ D:true,false,false 题目解析:new Integer(10) 每次都会创建一个新对象,Integer.valueOf(10) 则会使用缓存池中的对象。 -#### 17. 3*0.1==0.3 返回值是多少? +### 17. 3*0.1==0.3 返回值是多少? 答:返回值为:false。 diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\274\202\345\270\270\345\244\204\347\220\206.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\274\202\345\270\270\345\244\204\347\220\206.md" similarity index 90% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\274\202\345\270\270\345\244\204\347\220\206.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\274\202\345\270\270\345\244\204\347\220\206.md" index 67917a7..7a0e7ad 100644 --- "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\345\274\202\345\270\270\345\244\204\347\220\206.md" +++ "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\345\274\202\345\270\270\345\244\204\347\220\206.md" @@ -1,8 +1,8 @@ -## 理解异常处理 +# 理解异常处理 在程序开发中,异常处理也是我们经常使用到的模块,只是平常很少去深究异常模块的一些知识点。比如,try-catch 处理要遵循的原则是什么,finally 为什么总是能执行,try-catch 为什么比较消耗程序的执行性能等问题,我们本讲内容都会给出相应的答案,当然还有面试中经常被问到的异常模块的一些面试题,也是我们本篇要讲解的重点内容。 -### 异常处理基础介绍 +## 异常处理基础介绍 先来看看**异常处理的语法格式**: @@ -44,7 +44,7 @@ try { ![enter image description here](https://img03.sogoucdn.com/app/a/100520146/82758fb0ac32a583eaa81969a6f856dd) -### 异常处理的发展 +## 异常处理的发展 随着 Java 语言的发展,JDK 7 的时候引入了一些更加便利的特性,用来更方便的处理异常信息,如 try-with-resources 和 multiple catch,具体可以参考下面的代码段: @@ -57,7 +57,7 @@ try (FileReader fileReader = new FileReader(""); } ``` -### 异常处理的基本原则 +## 异常处理的基本原则 先来看下面这段代码,有没有发现一些问题? @@ -74,7 +74,7 @@ try { - 第一,尽量不要捕获通用异常,也就是像 Exception 这样的异常,而是应该捕获特定异常,这样更有助于你发现问题; - 第二,不要忽略异常,像上面的这段代码只是加了 catch,但没有进行如何的错误处理,信息就已经输出了,这样在程序出现问题的时候,根本找不到问题出现的原因,因此要切记不要直接忽略异常。 -### 异常处理对程序性能的影响 +## 异常处理对程序性能的影响 异常处理固然好用,但一定不要滥用,比如下面的代码片段: @@ -112,13 +112,13 @@ if (null != jsonStr && !jsonStr.equals("")) { System.out.println(array.size()); ``` -### 相关面试题 +## 相关面试题 -#### 1. try 可以单独使用吗? +### 1. try 可以单独使用吗? 答:try 不能单独使用,否则就失去了 try 的意义和价值。 -#### 2. 以下 try-catch 可以正常运行吗? +### 2. 以下 try-catch 可以正常运行吗? ``` try { @@ -130,7 +130,7 @@ try { 答:不能正常运行,catch 后必须包含异常信息,如 catch (Exception e)。 -#### 3. 以下 try-finally 可以正常运行吗? +### 3. 以下 try-finally 可以正常运行吗? ``` try { @@ -142,7 +142,7 @@ try { 答:可以正常运行。 -#### 4. 以下代码 catch 里也发生了异常,程序会怎么执行? +### 4. 以下代码 catch 里也发生了异常,程序会怎么执行? ```java try { @@ -159,7 +159,7 @@ System.out.println("main"); 答:程序会打印出 finally 之后抛出异常并终止运行。 -#### 5. 以下代码 finally 里也发生了异常,程序会怎么运行? +### 5. 以下代码 finally 里也发生了异常,程序会怎么运行? ``` try { @@ -175,7 +175,7 @@ System.out.println("main"); 答:程序在输出 try 之后抛出异常并终止运行,不会再执行 finally 异常之后的代码。 -#### 6. 常见的运行时异常都有哪些? +### 6. 常见的运行时异常都有哪些? 答:常见的运行时异常如下: @@ -191,21 +191,21 @@ System.out.println("main"); - java.lang.NoSuchMethodException 方法不存在异常; - java.lang.IllegalArgumentException 方法传递参数错误。 -#### 7. Exception 和 Error 有什么区别? +### 7. Exception 和 Error 有什么区别? 答:Exception 和 Error 都属于 Throwable 的子类,在 Java 中只有 Throwable 及其之类才能被捕获或抛出,它们的区别如下: - Exception(异常)是程序正常运行中,可以预期的意外情况,并且可以使用 try/catch 进行捕获处理的。Exception 又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception),运行时异常编译能通过,但如果运行过程中出现这类未处理的异常,程序会终止运行;而受检查的异常,要么用 try/catch 捕获,要么用 throws 字句声明抛出,否则编译不会通过。 - Error(错误)是指突发的非正常情况,通常是不可以恢复的,比如 Java 虚拟机内存溢出,诸如此类的问题叫做 Error。 -#### 8. throw 和 throws 的区别是什么? +### 8. throw 和 throws 的区别是什么? 答:它们的区别如下: - throw 语句用在方法体内,表示抛出异常由方法体内的语句处理,执行 throw 一定是抛出了某种异常; - throws 语句用在方法声明的后面,该方法的调用者要对异常进行处理,throws 代表可能会出现某种异常,并不一定会发生这种异常。 -#### 9. Integer.parseInt(null) 和 Double.parseDouble(null) 抛出的异常一样吗?为什么? +### 9. Integer.parseInt(null) 和 Double.parseDouble(null) 抛出的异常一样吗?为什么? 答:Integer.parseInt(null) 和 Double.parseDouble(null) 抛出的异常类型不一样,如下所示: @@ -214,17 +214,17 @@ System.out.println("main"); 至于为什么会产生不同的异常,其实没有特殊的原因,主要是由于这两个功能是不同人开发的,因而就产生了两种不同的异常信息。 -#### 10. NoClassDefFoundError 和 ClassNoFoundException 有什么区别? +### 10. NoClassDefFoundError 和 ClassNoFoundException 有什么区别? - NoClassDefFoundError 是 Error(错误)类型,而 ClassNoFoundExcept 是 Exception(异常)类型; - ClassNoFoundExcept 是 Java 使用 Class.forName 方法动态加载类,没有加载到,就会抛出 ClassNoFoundExcept 异常; - NoClassDefFoundError 是 Java 虚拟机或者 ClassLoader 尝试加载类的时候却找不到类订阅导致的,也就是说要查找的类在编译的时候是存在的,运行的时候却找不到,这个时候就会出现 NoClassDefFoundError 的错误。 -#### 11. 使用 try-catch 为什么比较耗费性能? +### 11. 使用 try-catch 为什么比较耗费性能? 答:这个问题要从 JVM(Java 虚拟机)层面找答案了。首先 Java 虚拟机在构造异常实例的时候需要生成该异常的栈轨迹,这个操作会逐一访问当前线程的栈帧,并且记录下各种调试信息,包括栈帧所指向方法的名字,方法所在的类名、文件名,以及在代码中的第几行触发该异常等信息,这就是使用异常捕获耗时的主要原因了。 -#### 12. 常见的 OOM 原因有哪些? +### 12. 常见的 OOM 原因有哪些? 答:常见的 OOM 原因有以下几个: @@ -232,7 +232,7 @@ System.out.println("main"); - 加载特别大的图片; - 递归次数过多,并一直操作未释放的变量。 -#### 13. 以下程序的返回结果是? +### 13. 以下程序的返回结果是? ```java public static int getNumber() { @@ -257,13 +257,13 @@ D:1 题目解析:程序最后一定会执行 finally 里的代码,会把之前的结果覆盖为 3。 -#### 14. finally、finalize 的区别是什么? +### 14. finally、finalize 的区别是什么? 答:finally、finalize 的区别如下: - finally 是异常处理语句的一部分,表示总是执行; - finalize 是 Object 类的一个方法,子类可以覆盖该方法以实现资源清理工作,垃圾回收之前会调用此方法。 -#### 15. 为什么 finally 总能被执行? +### 15. 为什么 finally 总能被执行? 答:finally 总会被执行,都是编译器的作用,因为编译器在编译 Java 代码时,会复制 finally 代码块的内容,然后分别放在 try-catch 代码块所有的正常执行路径及异常执行路径的出口中,这样 finally 才会不管发生什么情况都会执行。 \ No newline at end of file diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\225\260\346\215\256\347\273\223\346\236\204\351\230\237\345\210\227.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\225\260\346\215\256\347\273\223\346\236\204\351\230\237\345\210\227.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\225\260\346\215\256\347\273\223\346\236\204\351\230\237\345\210\227.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\225\260\346\215\256\347\273\223\346\236\204\351\230\237\345\210\227.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\263\233\345\236\213\344\270\216\350\277\255\344\273\243\345\231\250.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\263\233\345\236\213\344\270\216\350\277\255\344\273\243\345\231\250.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\263\233\345\236\213\344\270\216\350\277\255\344\273\243\345\231\250.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\263\233\345\236\213\344\270\216\350\277\255\344\273\243\345\231\250.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\265\205\345\205\213\351\232\206\345\222\214\346\267\261\345\205\213\351\232\206.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\265\205\345\205\213\351\232\206\345\222\214\346\267\261\345\205\213\351\232\206.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\346\265\205\345\205\213\351\232\206\345\222\214\346\267\261\345\205\213\351\232\206.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\346\265\205\345\205\213\351\232\206\345\222\214\346\267\261\345\205\213\351\232\206.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\347\261\273\344\270\216Object.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\347\261\273\344\270\216Object.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\347\261\273\344\270\216Object.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\347\261\273\344\270\216Object.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\351\233\206\345\220\210Collection.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\351\233\206\345\220\210Collection.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\351\233\206\345\220\210Collection.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\351\233\206\345\220\210Collection.md" diff --git "a/docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\351\233\206\345\220\210Map.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\351\233\206\345\220\210Map.md" similarity index 100% rename from "docs/Java\344\270\207\345\262\201/Java-\345\237\272\347\241\200\344\270\215\347\211\242\345\234\260\345\212\250\345\261\261\346\221\207/\347\220\206\350\247\243\351\233\206\345\220\210Map.md" rename to "docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\351\233\206\345\220\210Map.md" diff --git "a/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\351\235\242\345\220\221\345\257\271\350\261\241.md" "b/docs/Java\346\240\270\345\277\203\345\237\272\347\241\200/\347\220\206\350\247\243\351\235\242\345\220\221\345\257\271\350\261\241.md" new file mode 100644 index 0000000..e69de29 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" index 1926745..36851e0 100644 --- "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ArrayList\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,8 +1,4 @@ - - - - -# ArrayList源码分析 +# 👉 ArrayList源码分析 ## 1 底层结构 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ConcurrentHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ConcurrentHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" index e32c62d..0c646d3 100644 --- "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ConcurrentHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/ConcurrentHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -## ConcurrentHashMap源码分析 +# 👉 ConcurrentHashMap源码分析 当我们碰到线程不安全场景下,需要使用 Map 的时候,我们第一个想到的 API 估计就是 ConcurrentHashMap,ConcurrentHashMap 内部封装了锁和各种数据结构来保证访问 Map 是线程安全的,接下来我们一一来看下,和 HashMap 相比,多了哪些数据结构,又是如何保证线程安全的。 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" index f578794..a648254 100644 --- "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -## HashMap源码分析 +# 👉 HashMap源码分析 ## 1 整体架构 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashSet\344\270\216TreeSet\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashSet\344\270\216TreeSet\346\272\220\347\240\201\345\210\206\346\236\220.md" index c83671a..cc56b9d 100644 --- "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashSet\344\270\216TreeSet\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/HashSet\344\270\216TreeSet\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -## HashSet与TreeSet +# 👉 HashSet与TreeSet HashSet、TreeSet 两个类是在 Map 的基础上组装起来的类,我们学习的侧重点,主要在于 Set 是如何利用 Map 现有的功能,来达成自己的目标的,也就是说如何基于现有的功能进行创新,然后再看看一些改变的小细节是否值得我们学习。 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/LinkedHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/LinkedHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" index ecd3e53..897ddbb 100644 --- "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/LinkedHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/LinkedHashMap\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -# LinkedHashMap源码分析 +# 👉 LinkedHashMap源码分析 HashMap 是无序的,TreeMap 可以按照 key 进行排序,那有木有 Map 是可以维护插入的顺序的呢?接下来我们一起来看下 LinkedHashMap。 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/README.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/README.md" new file mode 100644 index 0000000..a788b3f --- /dev/null +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/README.md" @@ -0,0 +1,8 @@ +# Java并发编程 + +* [ArrayList源码分析](docs/Java源码分析/ArrayList源码分析.md) +* [HashMap源码分析](docs/Java源码分析/HashMap源码分析.md) +* [HashSet与TreeSet源码分析](docs/Java源码分析/HashSet与TreeSet源码分析.md) +* [LinkedHashMap源码分析](docs/Java源码分析/LinkedHashMap源码分析.md) +* [TreeMap源码分析](docs/Java源码分析/TreeMap源码分析.md) + diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/TreeMap\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/TreeMap\346\272\220\347\240\201\345\210\206\346\236\220.md" index 58715aa..5db0820 100644 --- "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/TreeMap\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/TreeMap\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -# TreeMap源码分析 +# 👉 TreeMap源码分析 ## 1 知识储备 diff --git "a/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/_sidebar.md" "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/_sidebar.md" new file mode 100644 index 0000000..bf4f932 --- /dev/null +++ "b/docs/Java\346\272\220\347\240\201\345\210\206\346\236\220/_sidebar.md" @@ -0,0 +1,6 @@ +* **👉 Java源码分析** [↩](/README) + * [ArrayList源码分析](docs/Java源码分析/ArrayList源码分析.md) + * [HashMap源码分析](docs/Java源码分析/HashMap源码分析.md) + * [HashSet与TreeSet源码分析](docs/Java源码分析/HashSet与TreeSet源码分析.md) + * [LinkedHashMap源码分析](docs/Java源码分析/LinkedHashMap源码分析.md) + * [TreeMap源码分析](docs/Java源码分析/TreeMap源码分析.md) \ No newline at end of file diff --git "a/docs/Java\350\231\232\346\213\237\346\234\272/JVM\347\241\256\350\256\244\345\217\257\345\233\236\346\224\266\345\257\271\350\261\241\347\232\204\346\226\271\345\274\217.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/JVM\347\241\256\350\256\244\345\217\257\345\233\236\346\224\266\345\257\271\350\261\241\347\232\204\346\226\271\345\274\217.md" new file mode 100644 index 0000000..596b465 --- /dev/null +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/JVM\347\241\256\350\256\244\345\217\257\345\233\236\346\224\266\345\257\271\350\261\241\347\232\204\346\226\271\345\274\217.md" @@ -0,0 +1,110 @@ +# 👉 JVM确认可回收对象的方式 + +## 前言 + +在开始之前,我们先回顾一下`堆`是个什么玩意,大家可能都知道,我们每天创建的Java对象几乎都存放在堆上面,所以说堆是一个巨大的对象池一点都不过分,在这个对象池里面管理者数据巨大的对象实例。 + +在对象池中对象的引用层次,有的是很深的。比如一个调用非常频繁的接口,生产对象的速度是非常可观的。对象之间的关系,可以形容成一张网。虽然Java总是给人一种有使不完的内存的感觉,但是对象也不能一直增加不减少啊,所以就必须有**垃圾回收**这个操作。 + +## JVM是怎么认识`垃圾`的呢? + +**"垃圾回收"本文中简称 GC** + +你还记得电视剧中的“诛九族""? + +img + +比如小憨批打了皇帝老儿一巴掌,把皇帝老儿打的鼻青脸肿滴,皇帝老儿非常生气,他要下令诛小憨批的九族,以平心头只恨。 + +哈哈哈嗝~ 小憨批完了~ + +img + +那么我们看看在古代这个诛九族是具体操作的呢?首先需要追溯到共同的祖先(也就是小憨批家族的大哥大),再往下逐一细数和小憨批有关系的(小憨批真坑啊)。 + +img + + + +其实发生在堆上的垃圾回收和这个“诛九族“的是相同思路,那么我们下面具体分析一下JVM是如何进行GC的呢? + +**关于JVM的GC是不受程序控制的,当满足一定条件的时候就会主动触发。** + +当发生GC的时候,对于一个对象来说,JVM总能够找到引用它的祖先,当找到最后的时候,JVM发现这家伙的有些祖先已经玩完了,那么它们就会被JVM给干掉。 + +为什么还有没有被干掉的祖先呢?因为这些躲过GC的祖先们,它们是GC Roots ,长得比较特殊嘛。 + +当从GC Roots 向下追溯、搜索,就会产生一个引用链。当碰到有对象没有任何一个GC Roots 产生关系的话,这个对象就会被无情的干掉。(一根绳上的蚂蚱嘛) + +来,我们画个图瞅瞅咋回事,如下图所示,Obj5、Obj6、Obj7,由于不能和 GC Root 产生关联,发生 GC 时,就会被摧毁。 + +img + + + +其实所谓的垃圾回收就是围绕着GC Roots 来的,但是同时,GC Roots 也存在着很多内存泄漏的根源,因为其他引用小弟压根没有这个权利。 + +那么什么样的对象才会是GC Roots 呢? 这个不在于它是什么样的对象,关键是它所处的位置(仔细品~)。 + +## GC Roots 是什么 + +首先,GC Roots必须是一组必须活跃的引用。简单的讲,就是程序接下来通过直接引用或间接引用,能够被访问到的潜在被使用的对象(咋感觉还是有点绕呢)。 + +**GC Roots:** + +1. Java线程中,当前所有正在被调用的方法的引用类型参数、局部变量、临时值等等。也就是与我们栈帧相关的各种引用。 +2. 所有当前被加载的Java类。 +3. Java类的引用类型静态变量。 +4. 运行时常量池里的引用类型常量。 +5. JVM内部数据结构的一些引用,比如sun.jvm.hotspot.memory.Univers类。 +6. 用于同步的监控对象。比如调用了对象的wait()方法。 +7. JNI handles,包括global handles 和 local handles。 + +以上GC Roots大致可以分为一下三大类。 + +1. 活动线程相关的各种引用。 +2. 类的静态变量的引用。 +3. JNI引用。 + +最后我们需要注意的是,我们这里说的是活跃的引用,而不是对象,对象是不能作为GC Roots的。 + +整个GC过程中是找到那些活对象,并把剩余的空间都认得为“无用”。而不是找到所有死掉的对象,并回收它们占用的空间。所有说,哪怕JVM的堆非常大,基于tracing的GC方式,回收速度也是跟快的。 + +## 总结 + + GC Roots 就是可达性分析法。还有一种叫作引用计数法的方式。下面我们简单介绍一下。 + +引用计数法:在Java中如果要操作对象,就必须先获取该对象的引用,因此可以通过引用计数法来判断一个对象是否可以被回收。在为一个对象添加一个引用时,引用计数器就加1;为对象删除一个引用时,引用计数器就减1;如果一个对象的引用计数为0,则说明该对象没有被引用,可以回收。**优点是垃圾回收比较及时,实时性比较高,只要对象计数器为 0,则可以直接进行回收操作;而缺点是无法解决循环引用的问题。** + +因为存在循环引用这个致命的硬伤,没有一个是采用引用计数法来实现 GC 的,所有你现在完全忘记引用计数这种方式了。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/docs/Java\350\231\232\346\213\237\346\234\272/Java\350\277\220\350\241\214\346\227\266\345\206\205\345\255\230\345\210\222\345\210\206.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/Java\350\277\220\350\241\214\346\227\266\345\206\205\345\255\230\345\210\222\345\210\206.md" new file mode 100644 index 0000000..d5931c9 --- /dev/null +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/Java\350\277\220\350\241\214\346\227\266\345\206\205\345\255\230\345\210\222\345\210\206.md" @@ -0,0 +1,36 @@ +# 👉 JVM的内存区域 + +​ **线程私有区域**的生命周期与线程相同,随线程的启动而创建,随线程的启动而创建,随线程的结束而销毁。在JVM内部,每个线程都与操作系统的本地线程直接映射,因此线程私有内存区域的存在与否和本地线程的启动和销毁对应。 + +​ **线程共享区域**随虚拟机的启动而创建,随虚拟机的关闭而销毁。 + +## 程序计数器 : 线程私有,无内存溢出问题 + +​ 程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指令,每个运行中的线程都有一个独立的程序计数器,在方法正在执行时,该方法的程序计数器记录的是实时虚拟机字节码指令的地址;如果该方法执行的是Native方法,则程序计数器的值为空。 + +​ 程序计数器是唯一没有内存溢出的区域。 + +## 虚拟机栈 : 线程私有,描述Java方法的执行过程 + +​ 虚拟机栈是描述Java方法的执行过程的内存模型,它在当前栈帧存储了局部变量表、操作数栈、动态链接、方法出口等信息。同时,栈帧用来存储部分运行时数据及其数据结构,处理动态链接方法的返回值和异常分派。 + +​ 栈帧用来记录方法的执行过程,在方法被执行时虚拟机会为其创建一个与之对应的栈帧,方法的执行和返回对应栈帧在虚拟机中的入栈和出栈。无法方法是正常运行完成还是异常完成,都可以视为方法运行结束。 + +## 本地方法区 : 线程私有 + +​ 本地方法区和虚拟机栈作用类似,区别就是本地方法栈是为Native方法服务,而虚拟机栈是为了Java方法服务。 + +## 堆内存 : 线程共享,运行时数据区 + +​ 在JVM运行过程中创建的对象和产生的数据都被存储在堆中,堆是被线程共享的内存区域,也是垃圾收集器进行垃圾回首的最主要的内存区域。 + +## 方法区 :线程共享 + +​ 方法区用于存储常量、静态变量、类信息、即时编译器编译后的机器码、运行时常量池等数据。 + +​ JVM把GC分代收集扩展至方法区,即使用Java堆的永久代来实现方法区,这样JVM的垃圾收集器就可以像管理Java堆一样管理这部分内存。永久带的内存回收主要针对常量池的回收和类的卸载,因此可回收的对象很少。 + +​ 常量被存储在运行时常量池中,是方法区的一部分。静态也属于方法区的一部分。在类信息中不但保存了类的版本/字段/方法/接口等描述信息,还保存了常量信息。 + +​ 在即使编译后,代码的内容将在执行阶段被保存在方法区的运行时常量池中。Java虚拟机堆Class文件每一部分的格式都明确的规定,只有符合规范的Class文件才能通过虚拟机的检查,然后被装载和执行。 + diff --git "a/docs/Java\350\231\232\346\213\237\346\234\272/README.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/README.md" new file mode 100644 index 0000000..bac0e28 --- /dev/null +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/README.md" @@ -0,0 +1,9 @@ +# JVM虚拟机 + + * [Java运行时内存划分](docs/Java虚拟机/Java运行时内存划分.md) + * [JVM确认可回收对象的方式](docs/Java虚拟机/JVM确认可回收对象的方式.md) + * [类加载机制](docs/Java虚拟机/类加载机制.md) + * [双亲委派机制](docs/Java虚拟机/双亲委派机制.md) + * [四种引用类型](docs/Java虚拟机/四种引用类型.md) + * [垃圾回收器](docs/Java虚拟机/垃圾回收器.md) + * [垃圾回收算法](docs/Java虚拟机/Jav垃圾回收算法a运行时内存划分.md) diff --git "a/docs/Java\350\231\232\346\213\237\346\234\272/_sidebar.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/_sidebar.md" new file mode 100644 index 0000000..890d76e --- /dev/null +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/_sidebar.md" @@ -0,0 +1,8 @@ +* **👉 Java虚拟机** [↩](/README) + * [Java运行时内存划分](docs/Java虚拟机/Java运行时内存划分.md) + * [JVM确认可回收对象的方式](docs/Java虚拟机/JVM确认可回收对象的方式.md) + * [类加载机制](docs/Java虚拟机/类加载机制.md) + * [双亲委派机制](docs/Java虚拟机/双亲委派机制.md) + * [四种引用类型](docs/Java虚拟机/四种引用类型.md) + * [垃圾回收器](docs/Java虚拟机/垃圾回收器.md) + * [垃圾回收算法](docs/Java虚拟机/Jav垃圾回收算法a运行时内存划分.md) diff --git "a/docs/Java\350\231\232\346\213\237\346\234\272/\345\217\214\344\272\262\345\247\224\346\264\276\346\234\272\345\210\266.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\217\214\344\272\262\345\247\224\346\264\276\346\234\272\345\210\266.md" new file mode 100644 index 0000000..82b9862 --- /dev/null +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\217\214\344\272\262\345\247\224\346\264\276\346\234\272\345\210\266.md" @@ -0,0 +1,17 @@ +# 👉 双亲委派机制 + +​ 双亲委派机制是指一个类在收到类加载请求之后不会尝试自己加载这个类,而是把该类加载请求向上委派给其父类,其父类在接受到该类的加载请求之后又会将其委派给自己的父类,以此类推,这样所有的类加载请求都被向上委派到启动类加载器中。 + +​ 但是若父类加载器在接收到类加载请求后发现自己也无法加载该类,则父类会将该信息反馈给子类并向下委派子类加载器,直到该类被成功加载,若找不到该类,则JVM会抛出ClassNotFind异常。 + +​ **双亲委派加载机制的类加载流程。** + +1. 将自定义加载器挂载到应用程序类加载器。 +2. 应用程序类加载器将类加载请求委托给扩展类加载器。 +3. 扩展器加载器将类加载请求委托给启动类加载器。 +4. 启动类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交给应用程序类加载器加载。 +5. 扩张类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由应用程序类加载器加载。 +6. 应用程序类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由自定义类加载器加载。 +7. 在自定义加载器下查找并加载用户指定目录下的Class文件,如果在自定义加载路径下为找到目标Class文件,则抛出ClassNotFind异常。 + +​ **双亲委派加载机制的核心就是保证类的唯一性和安全性。** \ No newline at end of file diff --git "a/docs/Java\350\231\232\346\213\237\346\234\272/\345\233\233\347\247\215\345\274\225\347\224\250\347\261\273\345\236\213.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\233\233\347\247\215\345\274\225\347\224\250\347\261\273\345\236\213.md" new file mode 100644 index 0000000..1bfca77 --- /dev/null +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\233\233\347\247\215\345\274\225\347\224\250\347\261\273\345\236\213.md" @@ -0,0 +1,114 @@ +# 👉 四种引用类型 +Java中一切皆为对象,Java中的引用类型有四种,分别为强引用/软引用/弱引用/虚引用等。 + +## 强引用—trong references + +当内存空间不足,系统撑不住了,JVM 就会抛出 OutOfMemoryError 错误。即使程序会异常终止,这种对象也不会被回收。这种引用属于最普通最强硬的一种存在,只有在和 GC Roots 断绝关系时,才会被消灭掉。 + +这种引用,你每天的编码都在用。例如:new 一个普通的对象。 + +```java +Object obj = new Object() +``` + +这种方式可能是有问题的。假如你的系统被大量用户(User)访问,你需要记录这个 User 访问的时间。可惜的是,User 对象里并没有这个字段,所以我们决定将这些信息额外开辟一个空间进行存放。 + +```java +static Map userVisitMap = new HashMap<>(); + +... + +userVisitMap.put(user, time); +``` + +当你用完了 User 对象,其实你是期望它被回收掉的。但是,由于它被 userVisitMap 引用,我们没有其他手段 remove 掉它。这个时候,就发生了内存泄漏(memory leak)。 + +这种情况还通常发生在一个没有设定上限的 Cache 系统,由于设置了不正确的引用方式,加上不正确的容量,很容易造成 OOM。 + +## 软引用—Soft references + +软引用用于维护一些可有可无的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。 + +可以看到,这种特性非常适合用在缓存技术上。比如网页缓存、图片缓存等。 + +Guava 的 CacheBuilder,就提供了软引用和弱引用的设置方式。在这种场景中,软引用比强引用安全的多。 + +软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java 虚拟机就会把这个软引用加入到与之关联的引用队列中。 + +我们可以看一下它的代码。软引用需要显式的声明,使用泛型来实现。 + +```java +// 伪代码 + +Object object = new Object(); + +SoftReference softRef = new SoftReference(object); +``` + +这里有一个相关的 JVM 参数。它的意思是:每 MB 堆空闲空间中 SoftReference 的存活时间。这个值的默认时间是1秒(1000)。 + +```java +-XX:SoftRefLRUPolicyMSPerMB= +``` + +这里要特别说明的是,网络上一些流传的优化方法,即把这个值设置成 0,其实是错误的,这样容易引发故障,感兴趣的话你可以自行搜索一下。 + +这种比较偏门的优化手段,除非在你对其原理相当了解的情况下,才能设置一些比较特殊的值。比如 0 值,无限大等,这种值在 JVM 的设置中,最好不要发生。 + +## 弱引用—Weak references + +弱引用对象相比较软引用,要更加无用一些,它拥有更短的生命周期。 + +当 JVM 进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。弱引用拥有更短的生命周期,在 Java 中,用 java.lang.ref.WeakReference 类来表示。 + +它的应用场景和软引用类似,可以在一些对内存更加敏感的系统里采用。它的使用方式类似于这段的代码: + +```java +// 伪代码 + +Object object = new Object(); + +WeakReference softRef = new WeakReference(object); +``` + +## 虚引用—Phantom References + +这是一种形同虚设的引用,在现实场景中用的不是很多。虚引用必须和引用队列(ReferenceQueue)联合使用。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。 + +实际上,虚引用的 get,总是返回 null。 + +```java +Object  object = new Object(); + +ReferenceQueue queue = new ReferenceQueue(); + +// 虚引用,必须与一个引用队列关联 + +PhantomReference pr = new PhantomReference(object, queue); +``` + +虚引用主要用来跟踪对象被垃圾回收的活动。 + +当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象之前,把这个虚引用加入到与之关联的引用队列中。 + +程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。 + +下面的方法,就是一个用于监控 GC 发生的例子。 + +```java +private static void startMonitoring(ReferenceQueue referenceQueue, Reference ref) { +     ExecutorService ex = Executors.newSingleThreadExecutor(); +     ex.execute(() -> { +         while (referenceQueue.poll()!=ref) { +             //don't hang forever +             if(finishFlag){ +                 break; +            } +        } +         System.out.println("-- ref gc'ed --"); +    }); +     ex.shutdown(); +} +``` + +基于虚引用,有一个更加优雅的实现方式,那就是 Java 9 以后新加入的 Cleaner,用来替代 Object 类的 finalizer 方法。 \ No newline at end of file diff --git "a/docs/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250.md" similarity index 95% rename from "docs/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250.md" rename to "docs/Java\350\231\232\346\213\237\346\234\272/\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250.md" index 876f8ce..5699fe4 100644 --- "a/docs/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250.md" +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250.md" @@ -1,4 +1,4 @@ -# 垃圾回收器 +# 👉 垃圾回收器 ![img](https://img1.sycdn.imooc.com/5e6afe7d0001656f16000566.jpg) diff --git "a/docs/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" similarity index 99% rename from "docs/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" rename to "docs/Java\350\231\232\346\213\237\346\234\272/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" index 77c49c4..b937626 100644 --- "a/docs/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" @@ -1,4 +1,4 @@ -# 垃圾回收算法 +# 👉 垃圾回收算法 ## 复制算法 diff --git "a/docs/JVM/\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" "b/docs/Java\350\231\232\346\213\237\346\234\272/\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" similarity index 82% rename from "docs/JVM/\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" rename to "docs/Java\350\231\232\346\213\237\346\234\272/\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" index ceb746d..05cc850 100644 --- "a/docs/JVM/\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" +++ "b/docs/Java\350\231\232\346\213\237\346\234\272/\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" @@ -1,14 +1,14 @@ -# 类加载机制 +# 👉 类加载机制 JVM 通过双亲委派模型进行类的加载,即当某个类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。 -img +![GN0Do.png](https://s.im5i.com/2021/04/16/GN0Do.png) **类加载器:** -1. **启动类加载器 (Bootstrap ClassLoader)**:负责加载 JAVA_HOME\lib 目录中的,或通过 - Xbootclasspath 参数指定路径中的,且被虚拟机认可(按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录也不会被加载)的类。启动类加载器无法被 Java 程序直接引用; -2. **扩展类加载器 (Extension ClassLoader)**:负责加载 JAVA_HOME\jre\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库; -3. **应用程序类加载器 (Application ClassLoader)**:负责加载用户路径(classpath)上的类库。 +1. **启动类加载器 (Bootstrap ClassLoader)** :负责加载 JAVA_HOME\lib 目录中的,或通过 - Xbootclasspath 参数指定路径中的,且被虚拟机认可(按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录也不会被加载)的类。启动类加载器无法被 Java 程序直接引用; +2. **扩展类加载器 (Extension ClassLoader)** :负责加载 JAVA_HOME\jre\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库; +3. **应用程序类加载器 (Application ClassLoader)** :负责加载用户路径(classpath)上的类库。 4. 通过继承 java.lang.ClassLoader 类实现**自定义类加载器**(主要是重写 findClass 方法)。 **总结:** 类加载器和字节码是Java平台无关性的基石,对于任意一个类,都需要由它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性。 @@ -23,7 +23,7 @@ JVM 通过双亲委派模型进行类的加载,即当某个类加载器在接 # 类加载流程 -img +![GNEkW.png](https://s.im5i.com/2021/04/16/GNEkW.png) 类的生命周期会经历以下 7 个阶段: diff --git "a/docs/MyBatis/\346\267\261\345\205\245\345\211\226\346\236\220 MyBatis \346\240\270\345\277\203\345\216\237\347\220\206/MyBatis \344\270\211\345\261\202\346\236\266\346\236\204\345\233\276.png" "b/docs/MyBatis/\346\267\261\345\205\245\345\211\226\346\236\220 MyBatis \346\240\270\345\277\203\345\216\237\347\220\206/MyBatis \344\270\211\345\261\202\346\236\266\346\236\204\345\233\276.png" new file mode 100644 index 0000000..da76a46 Binary files /dev/null and "b/docs/MyBatis/\346\267\261\345\205\245\345\211\226\346\236\220 MyBatis \346\240\270\345\277\203\345\216\237\347\220\206/MyBatis \344\270\211\345\261\202\346\236\266\346\236\204\345\233\276.png" differ diff --git "a/docs/MyBatis/\346\267\261\345\205\245\345\211\226\346\236\220 MyBatis \346\240\270\345\277\203\345\216\237\347\220\206/MyBatis \346\211\247\350\241\214\344\270\200\346\235\241 SQL \350\257\255\345\217\245\347\232\204\346\240\270\345\277\203\350\277\207\347\250\213.png" "b/docs/MyBatis/\346\267\261\345\205\245\345\211\226\346\236\220 MyBatis \346\240\270\345\277\203\345\216\237\347\220\206/MyBatis \346\211\247\350\241\214\344\270\200\346\235\241 SQL \350\257\255\345\217\245\347\232\204\346\240\270\345\277\203\350\277\207\347\250\213.png" new file mode 100644 index 0000000..f7472fb Binary files /dev/null and "b/docs/MyBatis/\346\267\261\345\205\245\345\211\226\346\236\220 MyBatis \346\240\270\345\277\203\345\216\237\347\220\206/MyBatis \346\211\247\350\241\214\344\270\200\346\235\241 SQL \350\257\255\345\217\245\347\232\204\346\240\270\345\277\203\350\277\207\347\250\213.png" differ diff --git "a/docs/MySQL/MySQL\345\256\236\346\210\230\345\256\235\345\205\270/08 \347\264\242\345\274\225\357\274\232\346\216\222\345\272\217\347\232\204\350\211\272\346\234\257.md" "b/docs/MySQL/MySQL\345\256\236\346\210\230\345\256\235\345\205\270/08 \347\264\242\345\274\225\357\274\232\346\216\222\345\272\217\347\232\204\350\211\272\346\234\257.md" new file mode 100644 index 0000000..966e24f --- /dev/null +++ "b/docs/MySQL/MySQL\345\256\236\346\210\230\345\256\235\345\205\270/08 \347\264\242\345\274\225\357\274\232\346\216\222\345\272\217\347\232\204\350\211\272\346\234\257.md" @@ -0,0 +1,25 @@ +# 08 | 索引:排序的艺术 + +## 前言 + +索引是关系型数据库中最核心的概念之一,只有正确设计索引,业务才能达到上线的初步标准。本文我们一起探索——索引,目的是认识索引、用好索引。 + +## 索引是什么? + +索引是提升查询速度的一种数据结构。 + +> 思考:索引为什么会提升查询速度呢? + +索引之所以能够提升查询速度,那是因为在插入时候对数据进行了排序操作,当然什么事情都要两面性,这个排序操作虽然提升了查询速度,但是会导致插入或者更新的效率下降。 + +所以说索引是一门排序的艺术,只有用好索引,才能提升整个数据库系统的性能。在MySQL 8.0版本中,InnoDB 存储引擎支持的索引有 B+ 树索引、全文索引、R 树索引。当然,使用最为广泛的是B+树索引了。 + +### B+树索引结构 + +B+ 树索引是数据库系统中最为常见的一种索引数据结构,几乎所有的关系型数据库都支持它。 + +> 思考:为什么呢?它有什么“魔力"? + +因为它是**目前为止**排序最有效率的数据结构。像二叉树,哈希索引、红黑树、SkipList,在海量数据基于磁盘存储效率方面远不如 B+ 树索引高效。 + +所以,上述的数据结构一般仅用于内存对象,基于磁盘的数据排序与存储,最有效的依然是 B+ 树索引了。 \ No newline at end of file diff --git a/docs/MySQL/README.md b/docs/MySQL/README.md new file mode 100644 index 0000000..a9faa85 --- /dev/null +++ b/docs/MySQL/README.md @@ -0,0 +1,13 @@ +# MySQL + +* [MySQL基础概念](docs/MySQL/MySQL基础概念.md) +* [常见SQL优化方式](docs/MySQL/常见SQL优化方式.md) +* [浅谈MySQL的优化方案](docs/MySQL/浅谈MySQL的优化方案.md) +* [如何使用索引](docs/MySQL/如何使用索引.md) +* [如何使用EXPLAIN查看执行计划](docs/MySQL/如何使用EXPLAIN查看执行计划.md) +* [什么时候不需要创建索引](docs/MySQL/什么时候不需要创建索引.md) +* [什么情况下索引失效](docs/MySQL/什么情况下索引失效.md) +* [Hash索引与B+树索引的区别](docs/MySQL/Hash索引与B+树索引的区别.md) +* [B树与B+树详谈](docs/MySQL/树详谈.md) +* [SQL经典笔试题目](docs/MySQL/SQL经典笔试题目.md) +* [SQL进阶](docs/MySQL/SQL进阶.md) diff --git a/docs/MySQL/_sidebar.md b/docs/MySQL/_sidebar.md new file mode 100644 index 0000000..6e1c640 --- /dev/null +++ b/docs/MySQL/_sidebar.md @@ -0,0 +1,12 @@ +* **👉 MySQL** [↩](/README) + * [MySQL基础概念](docs/MySQL/MySQL基础概念.md) + * [常见SQL优化方式](docs/MySQL/常见SQL优化方式.md) + * [浅谈MySQL的优化方案](docs/MySQL/浅谈MySQL的优化方案.md) + * [如何使用索引](docs/MySQL/如何使用索引.md) + * [如何使用EXPLAIN查看执行计划](docs/MySQL/如何使用EXPLAIN查看执行计划.md) + * [什么时候不需要创建索引](docs/MySQL/什么时候不需要创建索引.md) + * [什么情况下索引失效](docs/MySQL/什么情况下索引失效.md) + * [Hash索引与B+树索引的区别](docs/MySQL/Hash索引与B+树索引的区别.md) + * [B树与B+树详谈](docs/MySQL/B树与B+树详谈.md) + * [SQL经典笔试题目](docs/MySQL/SQL经典笔试题目.md) + * [SQL进阶](docs/MySQL/SQL进阶.md) diff --git "a/docs/MySQL/\343\200\212MySQL\345\277\205\347\237\245\345\277\205\344\274\232\343\200\213.md" "b/docs/MySQL/\343\200\212MySQL\345\277\205\347\237\245\345\277\205\344\274\232\343\200\213.md" new file mode 100644 index 0000000..dc0948b --- /dev/null +++ "b/docs/MySQL/\343\200\212MySQL\345\277\205\347\237\245\345\277\205\344\274\232\343\200\213.md" @@ -0,0 +1,377 @@ +# 《MySQL必知必会》 + +## 1. 基础概念 + +### 1.1 什么是数据库 + + 数据库(DataBase,DB)是一个长期存储在计算机内的、有组织的、有共享的、统一管理的数据集合。它是一个按数据结构来存储和管理数据的计算机软件系统。 + +### 1.2 表 + + 在关系数据库中,表是一系列二维数组的集合,用于存储数据和操作数据的逻辑结构。表是右纵向的列和横向的行组成。行叫做记录,是组织数据的单位。列叫做字段,是记录的一个属性,所用表都是由一个或多个列组成的。 + +> 从技术上来说,行才是正确的术语。但是记录也不错~ + +我们举个例子解释,如表1-1所示: + +| 编号 | 姓名 | 性别 | 年龄 | 专业 | +| :--: | :----: | :--: | :--: | :----------: | +| 1 | 张无忌 | 男 | 18 | 软件工程 | +| 2 | 赵敏 | 女 | 16 | 车辆工程 | +| 3 | 张三丰 | 男 | 99 | 文化产业管理 | + +上表中,我们可以看到编码、姓名、性别、年龄、专业等就是这个表的字段(熟悉、列),编号1、2、3等从左到右一行就是这个表的记录(行)。 + +### 1.3 主键 + +主键(Primary Key),用于唯一地标识表中的每一条记录。主键列上既不能有两行相同的值,也不能为空值。 + +> 简单的说,主键的作用就是唯一性区分表中的每一行。 + +主键通常是定义在表的一列上,但是也不一定,也可以一起使用多个列最为主键,但是这多个列的组合必须满足唯一性。 + +### 1.4 了解SQL + +SQL是对数据库进行查询和修改操作的语言,其含义是结构化查询语言(Structured Query Language)。SQL语言包含以下4部分。 + +1. 数据定义语言(DDL):DROP、CREATE、ALTER等语句。 +2. 数据操作语言(DML):INSERT(插入)、UPDATE(修改)、DELETE(删除)语句。 +3. 数据查询语言(DQL):SELECT语句。 +4. 数据控制语言(DCL):GRANT、REVOKE、COMMIT、ROLLBACK等语句。 + +### 1.5 了解MySQL + +MySQL是一个小型关系数据库管理系统。与其他大型数据库管理系统(例如Oracle、DB2、SQL Server等)相比,MySQL规模小、功能有限,但是它体积小、速度快、成本低,并且提供的功能对稍微复杂的应用来说已经够用,这些特性使得MySQL成为世界上最受欢迎的开放源代码数据库。 + +MySQL的优点: + +1. 性能:MySQL执行很快(非常快)。 +2. 成本:MySQL是开发源代码的,社区版本是免费的,企业版本是收费的。 +3. 简单:MySQL安装非常简单且容易上手。 +4. 移植性高:能够工作在众多不同的系统平台上,例如Windows、Linux、UNIX、Mac OS等。 + +MySQL常用图形管理工具推荐: + +1. Navicat 下载地址:http://www.navicat.com/ +2. SQLyog 下载地址:http://www.webyog.com/ +3. MySQL Workbench 下载地址:http://dev.MySQL.com/downloads/workbench/ + +## 2. 表的基本操作 + +实际开发中,大多都是直接使用第三方管理软件进行数据库操作了,很少会使用命令直接操作表。但是这些基础知识也是应该了解一下的。 + +### 2.1 创建数据表 + +创建数据表的语句为`CREATE TABLE`,语法规则如下: + +```sql +CREATE TABLE 表名 ( + 字段名1,数据类型[列级别约束条件] [默认值] , + 字段名2数据类型[列级别约束条件] [默认值] , + 字段名3数据类型[列级别约束条件] [默认值] , + ··· + + [表级别约束条件] +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` + +具体创建表的SQL如下列: + +```sql +CREATE TABLE `t_student` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) DEFAULT NULL COMMENT '姓名', + `sex` char(8) DEFAULT NULL COMMENT '性别', + `age` int(11) DEFAULT NULL COMMENT '年龄', + `major` varchar(64) DEFAULT NULL COMMENT '专业', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` + +注意事项: + ++ 要创建的表的名称,不区分大小写,不能使用SQL语言中的关键字,如DROP、ALTER、INSERT等。 ++ 数据表中每一列(字段)的名称和数据类型,如果创建多列,就要用逗号隔开。 + +### 2.2 查看数据表结构 + +查看表的结构语句,SQL命令是:SHOW COLUMNS FROM 表名 或者 DESCRIBE 表名 或者 DESC 表名。具体操作如下: + +```sql +mysql> SHOW COLUMNS FROM t_student; ++-------+-------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-------+-------------+------+-----+---------+----------------+ +| id | int(11) | NO | PRI | NULL | auto_increment | +| name | varchar(32) | YES | | NULL | | +| sex | char(8) | YES | | NULL | | +| age | int(11) | YES | | NULL | | +| major | varchar(64) | YES | | NULL | | ++-------+-------------+------+-----+---------+----------------+ +5 rows in set (0.00 sec) + +mysql> DESCRIBE t_student; ++-------+-------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-------+-------------+------+-----+---------+----------------+ +| id | int(11) | NO | PRI | NULL | auto_increment | +| name | varchar(32) | YES | | NULL | | +| sex | char(8) | YES | | NULL | | +| age | int(11) | YES | | NULL | | +| major | varchar(64) | YES | | NULL | | ++-------+-------------+------+-----+---------+----------------+ +5 rows in set (0.00 sec) + + +mysql> DESC t_student; ++-------+-------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-------+-------------+------+-----+---------+----------------+ +| id | int(11) | NO | PRI | NULL | auto_increment | +| name | varchar(32) | YES | | NULL | | +| sex | char(8) | YES | | NULL | | +| age | int(11) | YES | | NULL | | +| major | varchar(64) | YES | | NULL | | ++-------+-------------+------+-----+---------+----------------+ +5 rows in set (0.00 sec) + +``` + +其中,表结构中的各个字段的含义分别解释如下: + ++ NULL:表示该列是否可以存储NULL值。 ++ Key:表示该列是否已编制索引。PRI表示该列是表主键的一部分; ++ UNI表示该列是UNIQUE索引的一部分; ++ MUL表示在列中某个给定值允许出现多次。 ++ Default:表示该列是否有默认值,有的话指定值是多少。 ++ Extra:表示可以获取的与给定列有关的附加信息,例如AUTO_INCREMENT等。 + +查看表创建时候的CREATE TABLE 语句,SQL命令是:`SHOW CREATE TABLE 表名`,具体操作如下: + +```sql +mysql> SHOW CREATE TABLE t_student; ++-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Table | Create Table | ++-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| t_student | CREATE TABLE `t_student` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) DEFAULT NULL COMMENT '姓名', + `sex` char(8) DEFAULT NULL COMMENT '性别', + `age` int(11) DEFAULT NULL COMMENT '年龄', + `major` varchar(64) DEFAULT NULL COMMENT '专业', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 | ++-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +1 row in set (0.00 sec) + +``` + +> 使用SHOW CREATE TABLE语句,不仅可以查看表创建时候的详细语句,还可以查看存储引擎和字符编码。 + +如果不加‘\G’参数,显示的结果可能非常混乱,加上参数‘\G’之后,可使显示结果更加直观,易于查看。 + +使用参数‘\G’之后的结果如下: + +```sql +mysql> SHOW CREATE TABLE t_student\G; +*************************** 1. row *************************** + Table: t_student +Create Table: CREATE TABLE `t_student` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) DEFAULT NULL COMMENT '姓名', + `sex` char(8) DEFAULT NULL COMMENT '性别', + `age` int(11) DEFAULT NULL COMMENT '年龄', + `major` varchar(64) DEFAULT NULL COMMENT '专业', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +1 row in set (0.00 sec) +``` + +是不是变得整洁了许多呢~ + +### 2.3 修改数据表 + +修改表指的是修改数据库中已经存在的数据表的结构。MySQL使用`ALTER TABLE`语句修改表。常用的修改表的操作有修改表名、修改字段数据类型或字段名、增加和删除字段、修改字段的排列位置、更改表的存储引擎、删除表的外键约束等。 + +修改数据表名,MySQL是通过`ALTER TABLE`语句来实现表名的修改的,具体的语法规则如下: + +```sql +ALTER TABLE <旧表名称> RENAME [TO] <新表名称>; +``` + +其中,TO为可选参数,使用与否均不影响结果。 + +我们这里将上面创建的`t_student`表改为`t_students`,加个s。具体操作如下: + +```sql +mysql> ALTER TABLE t_student RENAME t_students; +Query OK, 0 rows affected (0.01 sec) +``` + +使用`SHOW TABLES`命令,查看当前库中的所有表。 + +```sql +mysql> SHOW TABLES; ++-----------------+ +| Tables_in_study | ++-----------------+ +| t_students | ++-----------------+ +1 row in set (0.00 sec) +``` + +现在表名已经修改为了`t_students`。 + +### 2.4 删除数据库表 + +删除数据表是一个危险的操作,最好在删除之前对表有个备份的心里准备。当然了,在开发中,大多数开发者不会有权限直接操作生产库中的表,所谓的“删库跑路”听听得了,真是删了库,你也跑不掉。 + +删除一张表的SQL命令是这样写的:`DROP TABLE [IF EXISTS] 表名`。 + +```sql +mysql> DROP TABLE IF EXISTS t_students; +Query OK, 0 rows affected (0.00 sec) +``` + +可选参数“`IF EXISTS`”用于在删除前判断删除的表是否存在,加上该参数后,再删除表的时候,如果表不存在,SQL语句可以顺利执行,但是会发出警告(warning)。 + +```sql +mysql> DROP TABLE IF EXISTS t_students; +Query OK, 0 rows affected, 1 warning (0.00 sec) +``` + +## 3. 数据类型与运算符 + +一张数据库表是由多个列字段组成的,每一个字段都会指定一个数据类型,数据类型也就决定了字段存储的数据内容。不同的数据类型也决定了MySQL在存储它们的时候使用的方式,以及在使用它们的时候选择什么运算符号进行运算。 + +MySQL数据类型: + +- 数值类型:包括整数类型`TINYINT`、`SMALLINT`、`MEDIUMINT`、`INT`、`BIGINT`、浮点小数数据类型`FLOAT`和`DOUBLE`,定点小数类型`DECIMAL`。 +- 日期、时间类型:包括`YEAR`、`TIME`、`DATE`、`DATETIME`和`TIMESTAMP`。 +- 字符串类型:包括`CHAR`、`VARCHAR`、`BINARY`、`VARBINARY`、`BLOB`、`TEXT`、`ENUM`和`SET`等。字符串类型又分为文本字符串和二进制字符串。 + +### 3.1 整数类型 + +数值型数据类型主要用来存储数字,MySQL提供了多种数值数据类型,不同的数据类型提供不同的取值范围,可以存储的值范围越大,其所需要的存储空间也会越大。 + +MySQL主要提供的整数类型有`TINYINT`、`SMALLINT`、`MEDIUMINT`、`INT(INTEGER)`、`BIGINT`。整数类型的属性字段可以添加`AUTO_INCREMENT`自增约束条件。如下表MySQL中的数值类型及取值范围: + +| 类型名称 | 用途 | 大小(单位:字节) | 有符号 | 无符号 | +| :----------: | :--------: | :----------------: | :-----------------------------------------------------: | :----------------------------: | +| TINYINT | 小整数值 | 1 | (-128,127) | (0,255) | +| SMALLINT | 大整数值 | 2 | (-32 768,32 767) | (0,65 535) | +| MEDIUMINT | 大整数值 | 3 | (-8 388 608,8 388 607) | (0,16 777 215) | +| INT(INTEGER) | 大整数值 | 4 | -2 147 483 648,2 147 483 647) | (0,4 294 967 295) | +| BIGINT | 极大整数值 | 8 | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | 0,18 446 744 073 709 551 615) | + +我们还以上文中创建的`t_student`表为例: + +```sql +CREATE TABLE `t_student` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) DEFAULT NULL COMMENT '姓名', + `sex` char(8) DEFAULT NULL COMMENT '性别', + `age` int(11) DEFAULT NULL COMMENT '年龄', + `major` varchar(64) DEFAULT NULL COMMENT '专业', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` + +id 字段的数据类型为INT(11),注意后面的数字11,它表示的是该数据类型指定的显示宽度,即能够显示的数值中数字的个数。 + +显示宽度和数据类型的取值范围是无关的。显示宽度只是指明MySQL最大可能显示的数字个数,数值的位数小于指定的宽度时会由空格填充; + +如果插入了大于显示宽度的值,只要该值不超过该类型整数的取值范围,数值依然可以插入,而且能够显示出来。 + +> 注意:显示宽度只用于显示,并不能限制取值范围和占用空间。例如:INT(3)会占用4字节的存储空间,并且允许的最大值不会是999,而是INT整型所允许的最大值。 + +### 3.2浮点数类型和定点数类型 + +| 类型名称 | 大小(单位:字节) | 有符号 | 无符号 | +| -------- | ---------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| FLOAT | 4 bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | +| DOUBLE | 8 bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | +| DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | + +### 3.3 日期与时间类型 + +MySQL中有多种表示日期的数据类型,主要有DATETIME、DATE、TIMESTAMP、TIME和YEAR。 + +| 类名称 | 大小(单位:字节) | 范围 | 格式 | 用途 | +| :-------: | :----------------: | :----------------------------------------------------------: | :------------------ | :----------------------: | +| DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 | +| TIME | 3 | '-838:59:59'/'838:59:59' | HH:MM:SS | 时间值或持续时间 | +| YEAR | 1 | 1901/2155 | YYYY | 年份值 | +| DATETIME | 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 | +| TIMESTAMP | 4 | 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 | + +### 3.4 如何选择数据类型 + +MySQL中提供了很多的数据类型供选择,选择最合适的数据类型,有利于优化存储、提供数据库性能。在上文中我们对MySQL中的数据类型逐一做了介绍,在此基础上我们进一步分析,在实际使用过程中,我们该如何选择数据类型才能尽可能最优、最合适。 + +#### 3.4.1 整数和浮点数 + +整数类型使用非常频繁,如果你确定你不需要小数部分的话,可以选择整数类型来保存数据。如果你需要小数部分,可以选择浮点数类型,浮点数类型存入的数据会对该列定义的小数位进行四舍五入。 + +浮点类型包括`FLOAT`和`DOUBLE`类型。`DOUBLE`类型精度比`FLOAT`类型高,因此要求存储精度较高时应选择`DOUBLE`类型。 + +还有一点,如果你定义货币等这类对精确度要求较高的数据时候,可以选择`DECIMAL`。 + +#### 3.4.2 日期与时间类型 + +MySQL中有不同种类的日期和时间的数据类型,比如`YEAR`和`TIME`。如果仅需要记录年份,则使用`YEAR`类型即可;如果仅记录时间,则使用`TIME`类型。 + +如果同时需要记录日期和时间的话,则可以使用`TIMESTAMP`或者`DATETIME`类型。由于`TIMESTAMP`列的取值范围小于`DATETIME`的取值范围,因此存储范围较大的日期最好使用`DATETIME`。 + +`TIMESTAMP`也有一个`DATETIME`不具备的属性。默认的情况下,当插入一条记录但并没有指定`TIMESTAMP`这个列值时,MySQL会把`TIMESTAMP`列设为当前的时间,这一点非常方便。 + +因此当需要插入记录的同时插入当前时间时,使用`IMESTAMP`是方便的。另外,`TIMESTAMP`在空间上比`DATETIME`更有效。 + +#### 3.4.3 CHAR与VARCHAR之间的特点与选择 + +我们先看看`CHAR`与`VARCHAR`的区别: + +- `CHAR`是固定长度字符,`VARCHAR`是可变长度字符; +- `CHAR`会自动删除插入数据的尾部空格,`VARCHAR`不会删除尾部空格; + +因为`CHAR`是固定长度,所以它的处理速度会比`VARCHAR`的速度快,但是缺点也很明显,那就是造成一定程度上的存储空间浪费,对于那些存储不大但是速度有要求的可以选择使用`CHAR`类型,反之可以使用`VARCHAR`类型。 + +我们来看看存储引擎对于选择`CHAR`和`VARCHAR`会产生什么影响: + ++ `MyISAM`:最好使用固定长度的数据列代替可变长度的数据列。这样可以使整个表静态化,从而使数据检索更快,用空间换时间。 ++ `InnoDB`:使用可变长度的数据列,因为`InnoDB`数据表的存储格式不分固定长度和可变长度,因此使用`CHAR`不一定比使用`VARCHAR`更好,但由于`VARCHAR`是按照实际的长度存储的,比较节省空间,所以对磁盘I/O和数据存储总量比较好。 + +#### 3.4.4 ENUM和SET + +`ENUM`只能取单值,它的数据列表是一个枚举集合。它的合法取值列表最多允许有65535个成员。因此,在需要从多个值中选取一个时,可以使用`ENUM`。比如:性别字段适合定义为`ENUM`类型,每次只能从‘男’或‘女’中取一个值。 + +`SET`可取多值。它的合法取值列表最多允许有64个成员。空字符串也是一个合法的`SET`值。在需要取多个值的时候,适合使用`SET`类型,比如要存储一个人的兴趣爱好,最好使用SET类型。 + +`ENUM`和`SET`的值是以字符串形式出现的,但在内部,MySQL是以数值的形式存储它们的。 + +#### 3.4.5 BLOB和TEXT + +`BLOB`是二进制字符串,`TEXT`是非二进制字符串,两者均可存放大容量的信息。`BLOB`主要存储图片、音频信息等,而`TEXT`只能存储纯文本文件。 + +## 4. 查询数据 + +### 4.1 单表查询 + +#### 4.1.1 查询所有字段 + + + + + + + + + + + + + + + + + diff --git a/docs/Redis/README.md b/docs/Redis/README.md new file mode 100644 index 0000000..8f51c35 --- /dev/null +++ b/docs/Redis/README.md @@ -0,0 +1,2 @@ +# Redis TODO + diff --git a/docs/Redis/_sidebar.md b/docs/Redis/_sidebar.md new file mode 100644 index 0000000..d2a93c0 --- /dev/null +++ b/docs/Redis/_sidebar.md @@ -0,0 +1,2 @@ +* **👉 Redis** [↩](/README) + * [**Reids**]() diff --git a/docs/SpringBoot/README.md b/docs/SpringBoot/README.md new file mode 100644 index 0000000..20c3c4e --- /dev/null +++ b/docs/SpringBoot/README.md @@ -0,0 +1,5 @@ +# SpringBoot + +* [SpringBoot的常用注解](docs/SpringBoot/SpringBoot的常用注解.md) +* [基于SpringBoot集成Mybatis-Plus实现代码生成器](docs/SpringBoot/基于SpringBoot集成Mybatis-Plus实现代码生成器.md) + \ No newline at end of file diff --git "a/docs/SpringBoot/SpringBoot\347\232\204\345\270\270\347\224\250\346\263\250\350\247\243.md" "b/docs/SpringBoot/SpringBoot\347\232\204\345\270\270\347\224\250\346\263\250\350\247\243.md" index e0f23a8..204a8bd 100644 --- "a/docs/SpringBoot/SpringBoot\347\232\204\345\270\270\347\224\250\346\263\250\350\247\243.md" +++ "b/docs/SpringBoot/SpringBoot\347\232\204\345\270\270\347\224\250\346\263\250\350\247\243.md" @@ -1,4 +1,4 @@ -# SpringBoot的常用注解 +# 👉 SpringBoot的常用注解 >**注解用来定义一个类、属性或方法,方便程序能够被编译处理。它也相当于一个说明文件。告诉程序被某个注解标注的类或属性是什么,要怎么处理。注解可以用在标注包、类、方法和变量。** diff --git a/docs/SpringBoot/_sidebar.md b/docs/SpringBoot/_sidebar.md new file mode 100644 index 0000000..f5a1b95 --- /dev/null +++ b/docs/SpringBoot/_sidebar.md @@ -0,0 +1,4 @@ +* **👉 SpringBoot** [↩](/README) + * [SpringBoot的常用注解](docs/SpringBoot/SpringBoot的常用注解.md) + * [基于SpringBoot集成Mybatis-Plus实现代码生成器](docs/SpringBoot/基于SpringBoot集成Mybatis-Plus实现代码生成器.md) + \ No newline at end of file diff --git "a/docs/SpringBoot/\345\237\272\344\272\216SpringBoot\351\233\206\346\210\220Mybatis-Plus\345\256\236\347\216\260\344\273\243\347\240\201\347\224\237\346\210\220\345\231\250.md" "b/docs/SpringBoot/\345\237\272\344\272\216SpringBoot\351\233\206\346\210\220Mybatis-Plus\345\256\236\347\216\260\344\273\243\347\240\201\347\224\237\346\210\220\345\231\250.md" index 390d509..4c0f8d9 100644 --- "a/docs/SpringBoot/\345\237\272\344\272\216SpringBoot\351\233\206\346\210\220Mybatis-Plus\345\256\236\347\216\260\344\273\243\347\240\201\347\224\237\346\210\220\345\231\250.md" +++ "b/docs/SpringBoot/\345\237\272\344\272\216SpringBoot\351\233\206\346\210\220Mybatis-Plus\345\256\236\347\216\260\344\273\243\347\240\201\347\224\237\346\210\220\345\231\250.md" @@ -1,4 +1,4 @@ -# 基于`SpringBoot`集成`Mybatis-Plus`实现代码生成器 +# 👉 基于`SpringBoot`集成`Mybatis-Plus`实现代码生成器 ## 1. 引入所需依赖 diff --git "a/docs/\345\267\245\345\205\267/Emoji\347\254\246\345\217\267\345\244\247\345\205\250.md" "b/docs/\345\267\245\345\205\267/Emoji\347\254\246\345\217\267\345\244\247\345\205\250.md" index 3bf294d..10a8f33 100644 --- "a/docs/\345\267\245\345\205\267/Emoji\347\254\246\345\217\267\345\244\247\345\205\250.md" +++ "b/docs/\345\267\245\345\205\267/Emoji\347\254\246\345\217\267\345\244\247\345\205\250.md" @@ -1,4 +1,4 @@ -## Emoji符号大全 +# 👉 Emoji符号大全 > 如有符号显示不正常,请更换浏览器或操作系统浏览 @@ -7,7 +7,7 @@ | 常见 | 🌹🍀🍎💰📱🌙🍁🍂🍃🌷💎🔪🔫🏀⚽⚡👄👍🔥 | | 表情 | 😀😁😂😃😄😅😆😉😊😋😎😍😘😗😙😚☺😇😐😑😶😏😣😥😮😯😪😫😴😌😛😜😝😒😓😔😕😲😷😖😞😟😤😢😭😦😧😨😬😰😱😳😵😡😠 | | 人物 | 👦👧👨👩👴👵👶👱👮👲👳👷👸💂🎅👰👼💆💇🙍🙎🙅🙆💁🙋🙇🙌🙏👤👥🚶🏃👯💃👫👬👭💏💑👪 | -| 手势 | 💪👈👉☝👆👇✌✋👌👍👎✊👊👋👏👐✍ | +| 手势 | ☕️💪👈👉☝👆👇✌✋👌👍👎✊👊👋👏👐✍ | | 日常 | 👣👀👂👃👅👄💋👓👔👕👖👗👘👙👚👛👜👝🎒💼👞👟👠👡👢👑👒🎩🎓💄💅💍🌂 | | 手机 | 📱📲📶📳📴☎📞📟📠 | | 公共 | ♻🏧🚮🚰♿🚹🚺🚻🚼🚾⚠🚸⛔🚫🚳🚭🚯🚱🚷🔞💈 | diff --git "a/docs/\347\256\227\346\263\225/\345\270\270\347\224\250\347\256\227\346\263\225.md" "b/docs/\347\256\227\346\263\225/\345\270\270\347\224\250\347\256\227\346\263\225.md" deleted file mode 100644 index b062217..0000000 --- "a/docs/\347\256\227\346\263\225/\345\270\270\347\224\250\347\256\227\346\263\225.md" +++ /dev/null @@ -1,112 +0,0 @@ -## 常用算法 - -来看算法部分的知识点汇总,如下图所示。 - -img - -算法题的常用解题方法。 - -1. 复杂度是衡量算法好坏的标准之一,我们需要掌握计算算法时间复杂度和空间复杂度的方法。计算时间复杂度的方法一般是找到执行次数最多的语句,然后计算语句执行次数的数量级,最后用大写 O 来表示结果。 - -2. 常用的字符串匹配算法,了解不同算法的匹配思路。 - -3. 排序也是经常考察的知识点,排序算法分为插入、交换、选择、归并、基数五类,其中快速排序和堆排序考察的频率最高,要重点掌握,需要能够手写算法实现。 - -4. 常用的查找算法,包括二分查找、二叉排序树、B 树、Hash、BloomFilter 等,需要了解它们的适用场景,例如二分查找适合小数量集内存查找,B 树适合文件索引,Hash 常数级的时间复杂度更适合对查找效率要求较高的场合,BloomFilter 适合对大数据集进行数据存在性过滤。 - -算法的知识点比较多,提高算法解题能力需要适当刷题,但不能单纯依靠刷题来解决问题。需要掌握几种常用解题思路与方法,才能以不变应万变。这里讲一下:分治、动态规划、贪心、回溯和分支界定这五种常用的算法题解题方法,来看看它们分别适用于什么场景,如何应用。 - -## 分治法 - -分治法的思想是将一个难以直接解决的复杂问题或者大问题,分割成一些规模较小的相同问题,分而治之。比如快速排序、归并排序等都是应用了分治法。 - -适合使用分治法的场景需要满足三点要求: - -1. 可以分解为子问题; - -2. 子问题的解可以合并为原问题的解; - -3. 子问题之间没有关联。 - - -使用分治法解决问题的一般步骤如下图表格所示。 - -![img](http://s0.lgstatic.com/i/image2/M01/8A/C2/CgoB5l14oT-AOl2vAABkMCakhSg069.png) - -1. 第一步,要找到最小子问题的求解方法; - -2. 第二步,要找到合并子问题解的方法; - -3. 第三步,要找到递归终止条件。 - -## 动态规划法 - -动态规划法,与分治法类似,也是将问题分解为多个子问题。与分治法不同的是,子问题的解之间是有关联的。前一子问题的解,为后一子问题的求解提供了有用的信息。动态规划法依次解决各子问题,在求解每一个子问题时,列出所有局部解,通过决策保留那些有可能达到全局最优的局部解。最后一个子问题的解就是初始问题的解。 - -使用动态规划的场景需要也满足三点条件: - -1. 子问题的求解必须是按顺序进行的; - -2. 相邻的子问题之间有关联关系; - -3. 最后一个子问题的解就是初始问题的解。 - - -使用动态规划解决问题时,如上图表格第二行。 - -1. 第一步,先要分析最优解的性质; - -2. 第二步,递归的定义最优解; - -3. 第三步,记录不同阶段的最优值; - -4. 第四步,根据阶段最优解选择全局最优解 - -## 贪心算法 - -第三个贪心算法,因为它考虑的是局部的最优解,所以贪心算法不是对所有问题都能得到整体最优解。贪心算法的关键是贪心策略的选择。贪心策略必须具备无后效性,就是说某个状态以后的过程不会影响以前的状态,只与当前状态有关。 - -贪心算法使用的场景必须满足两点: - -1. 局部最优解能产生全局最优解; - -2. 就是刚才说的必须具备无后效性。 - - -如下图所示,使用贪心算法解题的一般步骤为: - -![img](http://s0.lgstatic.com/i/image2/M01/8A/E1/CgotOV14oT-AP4CcAABsEmtOf8k652.png) - -1. 第一步,先分解为子问题; - -2. 第二步、按贪心策略计算每个子问题的局部最优解; - -3. 第三步,合并局部最优解。 - -## 回溯算法 - -回溯算法实际上是一种深度优先的搜索算法,按选优的条件向前搜索,当探索到某一步时,发现原先选择并不优或达不到目标,就退回上一步重新选择,这种走不通就退回再走的方法就是回溯法。 - -回溯法适用于能够深度优先搜索,并且需要获取解空间的所有解的场合,例如迷宫问题等。 - -如上图所示,回溯法一般的解题步骤为: - -1. 第一步先针对所给问题,确定问题的解空间; - -2. 第二步、确定结点的扩展搜索规则; - -3. 第三步,以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。 - -## 分支界定法 - -最后是分支界定法,与回溯法的求解目标不同。回溯法的求解目标是找出满足约束条件的所有解,而分支界定法的求解目标则是找出满足约束条件的一个解。 - -分支界定法适用于广度优先搜索,并且获取解空间的任意解就可以的场合,例如求解整数规划问题。 - -如上图所示,分支界定法一般的解题步骤: - -1. 第一步先确定解的特征; - -2. 第二步在确定子节点搜索策略,例如是先入先出,还是先入后出; - -3. 第三步通过广度优先遍历寻找解。 \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/README.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/README.md" new file mode 100644 index 0000000..eac34dc --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/README.md" @@ -0,0 +1 @@ +![GRHeq.png](https://s.im5i.com/2021/04/15/GRHeq.png) \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/_sidebar.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/_sidebar.md" new file mode 100644 index 0000000..948a9e9 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/_sidebar.md" @@ -0,0 +1,14 @@ +* **👉 算法与数据结构** [↩](/README) + * [算法概述](docs/算法与数据结构/算法概述.md) + * [数组](docs/算法与数据结构/数组.md) + * [链表](docs/算法与数据结构/链表.md) + * [队列](docs/算法与数据结构/队列.md) + * [栈](docs/算法与数据结构/栈.md) + * [散列表](docs/算法与数据结构/散列表.md) + * [树](docs/算法与数据结构/树.md) + * [图](docs/算法与数据结构/图.md) + * [排序算法](docs/算法与数据结构/排序算法.md) + * [动态规划](docs/算法与数据结构/动态规划.md) + * [递归算法](docs/算法与数据结构/递归算法.md) + * [贪心算法](docs/算法与数据结构/贪心算法.md) + * [剑指offer](docs/算法与数据结构/剑指offer题解.md) diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\211\221\346\214\207offer\351\242\230\350\247\243.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\211\221\346\214\207offer\351\242\230\350\247\243.md" new file mode 100644 index 0000000..10ab10a --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\211\221\346\214\207offer\351\242\230\350\247\243.md" @@ -0,0 +1,9 @@ +# 👉 剑指offer题解 + +- [数组中重复的数字](http://mp.weixin.qq.com/s?__biz=MzUzMzM2NTQ0Ng==&mid=100000753&idx=1&sn=cccd8da3a96253839533b7cf41f21edc&chksm=7aa454584dd3dd4ed4644ab3a69372121f1fd8ca42fdb3bd5ee92e6285794e10f786a8c5694e#rd) +- [二维数组中的查找](http://mp.weixin.qq.com/s?__biz=MzUzMzM2NTQ0Ng==&mid=100000773&idx=1&sn=8dc1150518955041da93dd76571f2837&chksm=7aa453ac4dd3daba8b8ff766e54368906cb7028df912fb51833b99d4ad1572129c73cbc9d416#rd) +- [替换空格](http://mp.weixin.qq.com/s?__biz=MzUzMzM2NTQ0Ng==&mid=100000801&idx=1&sn=dcbca06ed25ca77b76de426d3c7910b3&chksm=7aa453884dd3da9e80d22652af33afb411e526fa1fc47538b41e10fa8b7b85a9a048ebe45726#rd) +- [用两个栈实现队列](http://mp.weixin.qq.com/s?__biz=MzUzMzM2NTQ0Ng==&mid=100000846&idx=1&sn=a1e9f3c2ccc75717018b6797b44b19b7&chksm=7aa453e74dd3daf10f930f28065cb62c30b5fa2dffbd38761ae7683690305d801ec00da5ddd1#rd) +- [删除链表节点](http://mp.weixin.qq.com/s?__biz=MzUzMzM2NTQ0Ng==&mid=100000881&idx=1&sn=30ff81c0cec276e8b9fd2c55e6a05468&chksm=7aa453d84dd3dace71e61de78c4404646f7877da39718568396677e25d34778a41044142b300#rd) +- [调整数组顺序使奇数位于偶数前面](http://mp.weixin.qq.com/s?__biz=MzUzMzM2NTQ0Ng==&mid=100000881&idx=1&sn=30ff81c0cec276e8b9fd2c55e6a05468&chksm=7aa453d84dd3dace71e61de78c4404646f7877da39718568396677e25d34778a41044142b300#rd) +- ··· diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\212\250\346\200\201\350\247\204\345\210\222.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\212\250\346\200\201\350\247\204\345\210\222.md" new file mode 100644 index 0000000..9789e18 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\212\250\346\200\201\350\247\204\345\210\222.md" @@ -0,0 +1,3 @@ +# 👉 动态规划: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\233\276.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\233\276.md" new file mode 100644 index 0000000..ab27f35 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\345\233\276.md" @@ -0,0 +1,3 @@ +# 👉 图: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\216\222\345\272\217\347\256\227\346\263\225.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\216\222\345\272\217\347\256\227\346\263\225.md" new file mode 100644 index 0000000..9ad34a1 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\216\222\345\272\217\347\256\227\346\263\225.md" @@ -0,0 +1,3 @@ +# 👉 排序算法: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\243\345\210\227\350\241\250.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\243\345\210\227\350\241\250.md" new file mode 100644 index 0000000..c259b8c --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\243\345\210\227\350\241\250.md" @@ -0,0 +1,3 @@ +# 👉 哈希表: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/01 \344\270\272\344\273\200\344\271\210\350\246\201\345\255\246\344\271\240\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\357\274\237.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/01 \344\270\272\344\273\200\344\271\210\350\246\201\345\255\246\344\271\240\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\357\274\237.md" new file mode 100644 index 0000000..54c5c4f --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/01 \344\270\272\344\273\200\344\271\210\350\246\201\345\255\246\344\271\240\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\357\274\237.md" @@ -0,0 +1,52 @@ +# 01 | 为什么要学习数据结构和算法? + +img + +## 前言 + +很多人认为数据结构和算法、计算机网络、操作系统以及计算机组成原理,实际工作中用的非常少,是脱离实际工作的,也就面试的时候会有被问到的机会吧~ + +这样的声音很多很多,就像我们上学的时候,总会人经常说买菜也不需要勾股定理啊,来抵制应试教育~ + +其实这样的说法很真实,但是看的还是不够本质吧~ 买菜的时候是不需要勾股定理来计算一下,但是会决定你在哪里买菜~ 仔细品! + +同样的道理,为什么大厂面试的时候总会被问到数据结构和算法、计算机网络、操作系统等等基础知识呢? + +有人会说,我在实际工作中很少或者几乎都用不到这数据结构那算法的,不照样把代码写的很“好”?但是事实真的是这样? + + + +问题来了:到底为什么建议要去学习数据结构与算法呢? + + + +## 大厂面试必备 + +目前很多的大厂面试,算法与数据结构的考察几乎是必备的。为什么这些大厂都偏向于这方面的考察呢? + ++ 如果你是参加校招,从公司考察角度来看,你没有什么实际的项目经验,只能从基础知识考察,比如计算机网络、操作系统、数据库原理、算法与数据结构等等。 + ++ 如果你是参加社招,公司考察算法与数据结构,其其目的更看重你的长期潜力,而非短期能力。 + +## 提升个人竞争力 + +作为业务开发,我们会用到各种框架、中间件和底层系统,比如 Spring、RPC 框架、消息中间件、Redis 等等。在这些基础框架中,一般都揉和了很多基础数据结构和算法的设计思想。 + +比如,我们常用的 Key-Value 数据库 Redis 中,里面的有序集合是用什么数据结构来实现的呢?为什么要用跳表来实现呢?为什么不用二叉树呢? + +如果你能弄明白这些底层原理,你就能更好地使用它们。即便出现问题,也很容易就能定位。因此,掌握数据结构和算法,不管对于阅读框架源码,还是理解其背后的设计思想,都是非常有用的。 + +在平时的工作中,数据结构和算法的应用到处可见。我来举一个你非常熟悉的例子:如何实时地统计业务接口的 99% 响应时间? + +你可能最先想到,每次查询时,从小到大排序所有的响应时间,如果总共有 1200 个数据,那第 1188 个数据就是 99% 的响应时间。很显然,每次用这个方法查询的话都要排序,效率是非常低的。但是,如果你知道“堆”这个数据结构,用两个堆可以非常高效地解决这个问题。 + + + +## 总结 + +最重要的是掌握了数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样 + +因为这样的你,就像是站在巨人的肩膀上,拿着生存利器行走世界。数据结构与算法,会为你的编程之路,甚至人生之路打开一扇通往新世界的大门。 + + + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/02 \345\246\202\344\275\225\346\212\223\344\275\217\351\207\215\347\202\271\357\274\214\347\263\273\347\273\237\351\253\230\346\225\210\345\234\260\345\255\246\344\271\240\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\357\274\237.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/02 \345\246\202\344\275\225\346\212\223\344\275\217\351\207\215\347\202\271\357\274\214\347\263\273\347\273\237\351\253\230\346\225\210\345\234\260\345\255\246\344\271\240\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\357\274\237.md" new file mode 100644 index 0000000..a88af0f --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/02 \345\246\202\344\275\225\346\212\223\344\275\217\351\207\215\347\202\271\357\274\214\347\263\273\347\273\237\351\253\230\346\225\210\345\234\260\345\255\246\344\271\240\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\357\274\237.md" @@ -0,0 +1,84 @@ +# 02 | 如何抓住重点,系统高效地学习数据结构与算法? + +img + +## 理解数据结构与算法 + +1. 数据结构就是指一组数据的存储结构。算法就是操作数据的一组方法。 +2. 数据结构和算法是相辅相成的,数据结构是为算法服务的,算法要作用在特定的数据结构之上。 +3. 数据结构是静态的吗,它只是组织数据的一种方式。如果不在它的基础上操作、构建算法、孤立存在的数据结构就是没用的。 + +img + +## 学习重点 + +### 复杂度分析 + +数据结构和算法解决的是如何更省、更快地存储和处理数据的问题,因此,我们就需要一个考量效率和资源消耗的方法,这就是复杂度分析方法。 + +> 思考:在实际开发中,如何选取合适的算法与数据结构,都取决于复杂度分析。 + +### 20个最常用的、最基础的数据结构与算法 + +#### 数据结构 + +1. 数组 +2. 链表 +3. 栈 +4. 队列 +5. 散列表 +6. 二叉树 +7. 堆 +8. 跳表 +9. 图 +10. Trie树 + +#### 算法 + +1. 递归 +2. 排序 +3. 二分查找 +4. 搜索 +5. 哈希算法 +6. 贪心算法 +7. 分治算法 +8. 回溯算法 +9. 动态规划 +10. 字符串匹配算法 + +> 思考:在学习数据结构和算法的过程中,你也要注意,不要只是死记硬背,不要为了学习而学习,而是要学习它的“来历”“自身的特点”“适合解决的问题”以及“实际的应用场景”。对于每一种数据结构或算法,我都会从这几个方面进行详细讲解。只要你掌握了我每节课里讲的内容,就能在开发中灵活应用。 + +## 如何学习才能事半功倍 + +### 1. 边学边练,适度刷题 + +“边学边练”这一招非常有用。建议你每周花 1~2 个小时的时间,集中把这周的三节内容涉及的数据结构和算法,全都自己写出来,用代码实现一遍。这样一定会比单纯地看或者听的效果要好很多! + +### 2. 多问、多思考、多互动 + +学习最好的方法是,找到几个人一起学习,一块儿讨论切磋,有问题及时寻求老师答疑。 + +> 思考:比如:创建一个交流群,多交流,多思考。 + +### 3. 打怪升级学习法 + +学习的过程中,我们碰到最大的问题就是,坚持不下来。 + +> 思考:每次学习一个知识点之后,要学会总结与思考,记下自己的学习心得,针对性的设立阶段目标 。 + +### 4. 知识需要沉淀,不要想试图一下子掌握所有 + +在学习的过程中,一定会碰到“拦路虎”。如果哪个知识点没有怎么学懂,不要着急,这是正常的。因为,想听一遍、看一遍就把所有知识掌握,这肯定是不可能的。 + +学习知识的过程是反复迭代、不断沉淀的过程。如果碰到“拦路虎”,你可以尽情地在留言区问我,也可以先沉淀一下,过几天再重新学一遍。所谓,书读百遍其义自见,我觉得是很有道理的! + +> 思考:说的非常对,学习就是一个反反复复的过程。 + + + + + + + + + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/03 \345\244\215\346\235\202\345\272\246\345\210\206\346\236\220\357\274\210\344\270\212\357\274\211\357\274\232\345\246\202\344\275\225\345\210\206\346\236\220\343\200\201\347\273\237\350\256\241\347\256\227\346\263\225\347\232\204\346\211\247\350\241\214\346\225\210\347\216\207\345\222\214\350\265\204\346\272\220\346\266\210\350\200\227\357\274\237.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/03 \345\244\215\346\235\202\345\272\246\345\210\206\346\236\220\357\274\210\344\270\212\357\274\211\357\274\232\345\246\202\344\275\225\345\210\206\346\236\220\343\200\201\347\273\237\350\256\241\347\256\227\346\263\225\347\232\204\346\211\247\350\241\214\346\225\210\347\216\207\345\222\214\350\265\204\346\272\220\346\266\210\350\200\227\357\274\237.md" new file mode 100644 index 0000000..165ee55 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/03 \345\244\215\346\235\202\345\272\246\345\210\206\346\236\220\357\274\210\344\270\212\357\274\211\357\274\232\345\246\202\344\275\225\345\210\206\346\236\220\343\200\201\347\273\237\350\256\241\347\256\227\346\263\225\347\232\204\346\211\247\350\241\214\346\225\210\347\216\207\345\222\214\350\265\204\346\272\220\346\266\210\350\200\227\357\274\237.md" @@ -0,0 +1,2 @@ +# 03 | 复杂度分析(上):如何分析、统计算法的执行效率和资源消耗? + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/04 \345\244\215\346\235\202\345\272\246\345\210\206\346\236\220\357\274\210\344\270\213\357\274\211\357\274\232\346\265\205\346\236\220\346\234\200\345\245\275\343\200\201\346\234\200\345\235\217\343\200\201\345\271\263\345\235\207\343\200\201\345\235\207\346\221\212\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/04 \345\244\215\346\235\202\345\272\246\345\210\206\346\236\220\357\274\210\344\270\213\357\274\211\357\274\232\346\265\205\346\236\220\346\234\200\345\245\275\343\200\201\346\234\200\345\235\217\343\200\201\345\271\263\345\235\207\343\200\201\345\235\207\346\221\212\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" new file mode 100644 index 0000000..fe2817e --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/04 \345\244\215\346\235\202\345\272\246\345\210\206\346\236\220\357\274\210\344\270\213\357\274\211\357\274\232\346\265\205\346\236\220\346\234\200\345\245\275\343\200\201\346\234\200\345\235\217\343\200\201\345\271\263\345\235\207\343\200\201\345\235\207\346\221\212\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" @@ -0,0 +1,2 @@ +# 04 | 复杂度分析(下):浅析最好、最坏、平均、均摊时间复杂度 + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/05 \346\225\260\347\273\204\357\274\232\344\270\272\344\273\200\344\271\210\345\276\210\345\244\232\347\274\226\347\250\213\350\257\255\350\250\200\344\270\255\346\225\260\347\273\204\351\203\275\344\273\2160\345\274\200\345\247\213\347\274\226\345\217\267\357\274\237.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/05 \346\225\260\347\273\204\357\274\232\344\270\272\344\273\200\344\271\210\345\276\210\345\244\232\347\274\226\347\250\213\350\257\255\350\250\200\344\270\255\346\225\260\347\273\204\351\203\275\344\273\2160\345\274\200\345\247\213\347\274\226\345\217\267\357\274\237.md" new file mode 100644 index 0000000..de46008 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/05 \346\225\260\347\273\204\357\274\232\344\270\272\344\273\200\344\271\210\345\276\210\345\244\232\347\274\226\347\250\213\350\257\255\350\250\200\344\270\255\346\225\260\347\273\204\351\203\275\344\273\2160\345\274\200\345\247\213\347\274\226\345\217\267\357\274\237.md" @@ -0,0 +1,30 @@ +# 05 | 数组:为什么很多编程语言中数组都从0开始编号? + +## 数组的定义 + +> 数组是一种线性表数据结构,它是一种线性表数据结构。数组使用一组连续的内存空间,存储一组具有**相同类型**的数据。 + +## 什么是线性表? + +线性表是数据按照线性排列的结构,每一个线性表上的数据最多只有前后两个方向。像数组、链表、队列、栈等都是线性表结构。 + +如下图所示: + +img + +## 什么是非线性表? + +非线性表的概念与线性表相对立,像图、二叉树、堆等。不像线性表一样,在非线性表中的数据并不是简单的前后关系。 + +如下图所示: + +img + +## 数组的特征:连续的内存空间、相同的数据类型 + +连续的内存空间,使得数据的**随机访问**非常高效。但是也使得在数组中删除、插入一个数据变得非常低效。 + +这是因为数据的连续性带来的限制,在删除或插入一个数据之后,数组需要保持其连续性就必须会涉及到大量的数据搬移操作。 + +## 数组是如何实现随机访问? + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/06 \351\223\276\350\241\250\357\274\210\344\270\212\357\274\211\357\274\232\345\246\202\344\275\225\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/06 \351\223\276\350\241\250\357\274\210\344\270\212\357\274\211\357\274\232\345\246\202\344\275\225\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225.md" new file mode 100644 index 0000000..1e51137 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/06 \351\223\276\350\241\250\357\274\210\344\270\212\357\274\211\357\274\232\345\246\202\344\275\225\345\256\236\347\216\260LRU\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225.md" @@ -0,0 +1,2 @@ +# 06 | 链表(上):如何实现LRU缓存淘汰算法? + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/README.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/README.md" new file mode 100644 index 0000000..eac34dc --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/README.md" @@ -0,0 +1 @@ +![GRHeq.png](https://s.im5i.com/2021/04/15/GRHeq.png) \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/_sidebar.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/_sidebar.md" new file mode 100644 index 0000000..0d20f5a --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217/_sidebar.md" @@ -0,0 +1,6 @@ +* **👉 数据结构与算法专栏** [↩](/README) + * **01.为什么要学习数据结构和算法?.md** + * **02.如何抓住重点,系统高效地学习数据结构与算法?.md** + * **03.复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?.md** + * **04.复杂度分析(下):浅析最好、最坏、平均、均摊时间复杂度.md** + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/01 \346\240\210\357\274\232\344\273\216\347\256\200\345\215\225\346\240\210\345\210\260\345\215\225\350\260\203\346\240\210\357\274\214\350\247\243\345\206\263\347\273\217\345\205\270\346\240\210\351\227\256\351\242\230.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/01 \346\240\210\357\274\232\344\273\216\347\256\200\345\215\225\346\240\210\345\210\260\345\215\225\350\260\203\346\240\210\357\274\214\350\247\243\345\206\263\347\273\217\345\205\270\346\240\210\351\227\256\351\242\230.md" new file mode 100644 index 0000000..d5d3484 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/01 \346\240\210\357\274\232\344\273\216\347\256\200\345\215\225\346\240\210\345\210\260\345\215\225\350\260\203\346\240\210\357\274\214\350\247\243\345\206\263\347\273\217\345\205\270\346\240\210\351\227\256\351\242\230.md" @@ -0,0 +1,256 @@ +# 01 | 栈:从简单栈到单调栈,解决经典栈问题 + +## 前言 + +栈这种数据结构,使用是非常广泛的,比如我们Java中函数的调用、浏览器中的前进与后退功能、操作系统中从用户态到内核态寄存器的保存、网络消息的处理等都会用到栈。 + +## 如何理解栈? + +如何去理解栈呢? + + + +子弹上膛的这个过程,后进的子弹最先射出,最上面的子弹就相当于栈顶。一句话可以概况栈的特性:**先进后出**,俗称“**出多了吐**”。 + +![img](https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20171206%2F36518da2f8f341a2b6db088a7e156f5f.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1627127265&t=c1701cb993dd287a2bedda0feeed0207) + +在Java中如何使用栈,代码如下: + +```java +// 创建一个栈 +Stack stack = new Stack(); +// 想栈中放入4个元素 +stack.push(1); +stack.push(2); +stack.push(3); +stack.push(4); + +// 查看此时栈顶的元素 +System.out.println(stack.peek()); // 输出结果:4 +// 将栈顶元素出站 +System.out.println(stack.pop()); // 输出结果:4 +// 再次查看此时栈顶元素 +System.out.println(stack.peek()); // 输出结果:3 +// 再次将栈顶元素出站 +System.out.println(stack.pop()); // 输出结果:3 +``` + +## 如何实现栈? + +实现栈的方式既可以选择数组,也可以链表。那么选择数组来实现的栈就叫做顺序栈,选择链表来实现的栈就叫做链式栈。 + +接下来,我们用Java代码分别实现**顺序栈**、**链式栈**。 + +### 顺序栈 + +```java +/** + * @author 微信公众号:码上Java + * @Description: 用数组实现站结构 + */ + +public class MyArratStack { + + private Object[] data = null; // 泛型数组 + private int maxSize = 0; //栈容量 + private int top = -1; //栈顶指针 + + /** + * 初始化构造方法 + * @param initialSize 初始栈的容量 + */ + MyArratStack(int initialSize) { + if (initialSize >= 0) { + this.maxSize = initialSize; + data = new Object[initialSize]; + top = -1; + } else { + throw new RuntimeException("初始化大小不能小于0: " + initialSize); + } + } + + /** + * 初始化构造方法 默认栈容量为10 + */ + public MyArratStack() { + this(10); + } + + /** + * 入栈操作 + * @param e + * @return + */ + public boolean push(E e) { + //首先判断一下栈是否已经满了 + if (top == maxSize - 1) { + //可优化 TODO 扩容操作 + throw new RuntimeException("栈已满,元素无法入栈"); + } else { + data[top] = e; + top++; + return true; + } + } + + /** + * 出栈操作 + * @return + */ + public E pop() { + //首先查看一下栈是否为空 + if (top == -1) { + throw new RuntimeException("栈为空 "); + } else { + //将栈顶元素返回后维护一下栈顶指针 + return (E) data[top--]; + } + } + + /** + * 查看栈顶元素 + * @return + */ + public E peek() { + if (top == -1) { + throw new RuntimeException("栈为空"); + } else { + // 查看栈顶元素并不移除所以说不需要维护栈顶指针 + return (E) data[top]; + } + } + + /** + * 判断栈是否为空 + * @return + */ + public boolean isEmpty() { + return maxSize == 0; + } + +} +``` + +### 链式栈 + +```java +public class StackBasedOnLinkedList { + private Node top = null; + + public void push(int value) { + Node newNode = new Node(value, null); + // 判断是否栈空 + if (top == null) { + top = newNode; + } else { + newNode.next = top; + top = newNode; + } + } + + /** + * 我用-1表示栈中没有数据。 + */ + public int pop() { + if (top == null) return -1; + int value = top.data; + top = top.next; + return value; + } + + public void printAll() { + Node p = top; + while (p != null) { + System.out.print(p.data + " "); + p = p.next; + } + System.out.println(); + } + + private static class Node { + private int data; + private Node next; + + public Node(int data, Node next) { + this.data = data; + this.next = next; + } + + public int getData() { + return data; + } + } +} +``` + +### 小结 + +不管是顺序栈还是链式栈,因为栈本身的局限性,也就是一个口子,只能涉及到个别元素的操作,所以说时间复杂度都是O(1)。 + +还有一点你发现没有,顺序栈是存在一个扩容的问题,因为数组不像链表,链表只要你内存够大,是可以支持无限扩展的。但是数组就不一样了,因为数组本身大小是已经初始化好了的,如果数组满了的话,你是无法继续往栈中添加元素的。如果想要添加元素,就必须解决这个扩容的问题。 + +那么如何解决呢?无非就是创建一个更大点的新数组,将就旧数组的元素通过遍历放到新数组里面。此时的时间复杂度会变成O(n)了。 + +那么我们可以总结下,最好的情况是栈不满,时间复杂度是O(1)。最坏的情况是栈满了,时间复杂度是O(1)。 + +## 实践演练 + +### 判断字符串括号是否合法 + +题目描述:给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 + +有效字符串需满足: + ++ 左括号必须用相同类型的右括号闭合。 ++ 左括号必须以正确的顺序闭合。 + +**解题思路:** + +1. 从左到右遍历字符串,当遇到左括号的时候,将其压入栈中,当遇到有括号的时候,将栈顶的元素与其匹配,如果能够匹配说明合法字符,继续以上操作。如果遇到不能匹配或者栈为空,则说明非法字符。 +2. 如果遍历结束,栈为空,则说明字符串为合法字符。否则,说明有未能匹配的左括号,则为非法字符。 + +**代码实现:** + +```java + /** + * 有效括号校验 + * + * @param str + * @return + */ + public static boolean isValid(String str) { + // 如果字符串为空,直接返回false + if (str.length() == 0 || str == null) { + return false; + } + // 如果字符串的长度为奇数,直接返回false + if (str.length() % 2 != 0) { + return false; + } + // 创建一个栈 + Stack stack = new Stack(); + + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '(') { + stack.push(')'); + } else if (c == '{') { + stack.push('}'); + } else if (c == '[') { + stack.push(']'); + } else if (stack.isEmpty() || c != stack.pop()) { + return false; + } + } + return stack.isEmpty(); + } +``` + + + + + + + + + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/_sidebar.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/_sidebar.md" new file mode 100644 index 0000000..89a9d32 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/_sidebar.md" @@ -0,0 +1,12 @@ +* **👉 数据结构与算法面试宝典专栏** [↩](/README) + * **01.栈:从简单栈到单调栈,解决经典栈问题.md** + * **链表** + * **队列** + * **栈** + * **散列表** + * **树** + * **图** + * **排序算法** + * **动态规划** + * **递归算法** + * **贪心算法** diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/\346\240\221.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/\346\240\221.md" new file mode 100644 index 0000000..3253d16 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\351\235\242\350\257\225\345\256\235\345\205\270\344\270\223\346\240\217/\346\240\221.md" @@ -0,0 +1 @@ +~ todo \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\347\273\204.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\347\273\204.md" new file mode 100644 index 0000000..3d77a40 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\225\260\347\273\204.md" @@ -0,0 +1,169 @@ +# 👉 数组: 一种非常基础且重要的数据结构 + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/数组.png) + +## 前言 + +数组是一种非常基础且重要的数据结构,很多复杂的数据结构都是基于数组实现的。深入理解数据的存储原理和特点,有利于我们在实际开发工作中,充分发挥数据的优势。 + +## 数据是什么 + + 数组的定义:数组(Array)是一种**线性表**数据结构。它用一组**连续的内存空间**,存储一组具有**相同类型的数据**。 + +在上面的定义中加黑的描述,我们可以发现数组的几个特点,分别是:线性表、连续的内存空间、相同类型的数据。如下图所示: + +![数组1](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/数组1.png) + +数组因具有连续的内存空间的特点,让数据拥有非常高效率的“随机访问”,但也是因为要保持这个连续的内存空间,导致数组在删除或插入操作的时非常低效。因为数组为了保持连续性,必然会涉及大量数据的搬移,这个是非常消耗时间的。 + +> 思考:这里你可能会有疑问:什么是连续的内存空间? + +首先,我们来说说内存,内存是由一个个连续的内存单元组成的,每一个内存单元都有自己的地址。在这些内存单元中,有些被其他数据占用了,有些是空闲的。 + +然而数据中的每个元素,都存储在小小的内存单元中,并且元素之间紧密排列,既不能打乱元素的存储顺序,也不能跳过某个存储单元进行存储。 + +## 数组的随机访问 + +数组的随机访问是有个寻址公式的,上问中我们提到过数组是用一组**连续的内存空间**存储数据元素的,然而每个内存单元都有自己的地址(在计算机里面就是通过这个地址访问数据的),又加上每个内存单元的大小都是一样的,这样就很容易得到一个公式了,如下所示: + +``` +a[i]_address=base_address+i*data_type_size +``` + +我们来简单解释一下上述公式,其中data_type_size表示数组中每个元素的大小、base_address表示内存块的首地址、i 表示数组下标。 + +## 数组的基本操作 + +在开始之前我们先创建一个数组类,来模拟数组操作时候的相关操作。代码如下: + +```java +public class MyArray { + + private int[] array; + // 数组大小 + private int size; + + public MyArray(int capacity) { + this.size = 0; + this.array = new int[capacity]; + } + +} +``` + +### 1. 读取元素 + +我们知道数组在内存中是连续存储的,所以根据上文的寻址公式可以知道,我们可以根据数组下标 i 快速定位到对应的元素。 + +简单举例,代码如下: + +```java +int[] array={1,2,3,4,5,6}; +System.out.println(array[1]); // 输出的是2 因为数组的下标是从0开始的。 +``` + +### 2. 更新元素 + +我们可以根据数组下标快速查找到对应元素。那么同样道理,我们可以根据数组下标 i 快速更新元素,这中间涉及两个过程,首先就是找到数组下标 i 对应的数据元素A,然后将新的数据元素B赋值给A即完成更新。 + +简单举例,代码如下: + +```java +int[] array={1,2,3,4,5,6}; +System.out.println(array[1]); // 输出的是2 + +//更新数组下标为 1 的数组元素 +array[1]=22; +System.out.println(array[1]); // 输出的是22 +``` + +### 3. 插入元素 + +相比读取、更新操作,插入元素稍微复杂一些,分为以下两种情况: + +尾部插入:首先,我们看看尾部插入,这种情况很简单,在数组的最后新增一个新的元素,此时对于原数组来说没有任何影响,时间复杂度为0(1)。如下图所示: + + + +中间插入:如果在数组的中间位置插入元素的话,此时会对插入元素位置之后的元素产生影响,也就是这些数据需要向后依次挪动一个位置。如下图所示: + + + +中间插入的代码如下: + +```java +/** + * 插入元素 + * @param index 待插入的位置 + * @param element 待插入的元素 +*/ +public void insert(int index,int element){ + if(index<0 || index>size){ + throw new IndexOutOfBoundsException("超过数组容量 ! 插入失败!"); + } + // 从左到右,将元素向右移动一位 + for (int i=size-1 ; i>index ; i--){ + array[i+1]=array[i]; + } + // 此时index这个位置已经腾空了,可以放进入element + array[index]=element; + //数组中元素个数+1 + size++; +} +``` + +#### 3.1 数组扩容 + +因为数组的长度在创建的时候已经确定了,当插入元素的时候如果数组已经满了,是没办法插入成功的。这个时候就要考虑数组扩容的问题了,那么该如何实现扩容呢? + +其实我们可以这样,比如此时的数组是A, A已经满了,我们再创建一个数组B且数组长度是A的2倍,然后我们将数组A的元素全部放到数组B中,这样就完成了数组扩容了。 + +数组扩容的代码如下: + +```java +/** + * 数组扩容为原数组的二倍 + */ +public void resize(){ + int[] newArray=new int[array.length*2]; + System.arraycopy(array,0,newArray,0,array.length); + array=newArray; +} +``` + +### 4. 删除元素 + +删除元素和插入元素类似,如果我们删除第k个位置的数据,为了内存的连续性,同样会涉及数据的挪动。如下图所示: + + + +删除元素的代码如下: + +```java + /** + * 根据数组下标删除元素 + * + * @param index 数组下标 + * @return + */ + public int delete(int index) { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("已经超过数组容量 ! 插入失败!"); + } + int deleteElement = array[index]; + // 从左到右,将元素向左移动一位 + for (int i = index; i < size - 1; i++) { + array[i] = array[i + 1]; + } + size--; + return deleteElement; + } +``` + +## 总结 + +数组是使用一块连续的内存空间,存储相同类型的一组数据,其最大的优点是数组支持随机访问,是因为数组可以通过数组下标(寻址公式)快速访问对应元素,时间复杂度为O(1)。 + +数组在删除元素和插入元素这两个操作比较低效,是因为数组为了保持数据的连续性,会涉及到数据的挪动,平均时间复杂度为O(N)。 + +故数组适合“读多写少” 的场景。 \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210.md" new file mode 100644 index 0000000..7e4a3ab --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210.md" @@ -0,0 +1,173 @@ +# 栈:一吃多就会吐的家伙~ + +## 前言 + +前两篇文章中我们学习了线性表中的数组和链表,数组和链表是最基础的数据结构,很多数据结构的实现都是基于数据或链表的。那么今天我们一起学习一个非常简单的数据结构—**栈**。栈使用是非常广泛的,比如我们Java中函数的调用、浏览器中的前进与后退功能等都会用到栈。 + +## 什么是栈 + +先画张图,看看栈长什么样。如下图所示: + +![// 配图](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/顺序栈与链式栈.png) + +从图中看到栈是有些特殊,对于栈的操作被限制只能在栈的一端(栈顶)进行,也就是不允许在栈的中间进行数据操作,只能在栈顶进行数据操作(也就是插入和删除数据)。 + +> 思考:“受限制”的栈有什么用呢? + +特定的数据结构肯定有其特定的使用场景,相比于数组或者链表而言,栈虽然没有怎么灵活(只能在栈的一端进行数据操作),但是对于新增或者删除数据的时候,因为栈只涉及到一端,效率肯定不低。 + +如何去理解栈呢?其实也非常简单,一句话可以概况栈的特性:**先进后出**,俗称“**吃多了吐**”。哈哈~ + +## 栈的基本操作 + +栈有不同的实现方式,基于数组实现的栈,被叫做**顺序栈**。基于链表实现的栈,被叫做**链式栈**。不管用什么方式实现的栈,其原理都是一样的,不用担心! + +栈的操作主要就两个:入栈(push)和出栈(pop)。 + +- 顺序栈 + +下面我们先基于数组来实现一个顺序栈,代码如下: + +```java +public class MyStack { + private Object[] data = null; // 数组 + private int maxSize = 0; //栈容量 + private int top = -1; //栈顶指针 + + // 初始化构造方法 + MyStack(int initialSize) { + if (initialSize >= 0) { + this.maxSize = initialSize; + data = new Object[initialSize]; + top = -1; + } else { + throw new RuntimeException("初始化大小不能小于0: " + initialSize); + } + } + + // 初始化构造方法 默认栈容量为10 + public MyStack() { + this(10); + } + + //入栈操作 + public boolean push(E e) { + //首先判断一下栈是否已经满了 + if (top == maxSize - 1) { + // 扩容 + resize(); + } + data[top] = e; + top++; + return true; + } + + //出栈操作 + public E pop() { + //首先查看一下栈是否为空 + if (top == -1) { + throw new RuntimeException("栈为空"); + } else { + //将栈顶元素返回后维护一下栈顶指针 + return (E) data[top--]; + } + } + + //查看栈顶元素 + public E peek() { + if (top == -1) { + throw new RuntimeException("栈为空"); + } else { + // 查看栈顶元素并不移除所以说不需要维护栈顶指针 + return (E) data[top]; + } + } + + // 查看栈是否为空 + public boolean isEmpty() { + return maxSize == 0; + } + + // 扩容操作 + public void resize() { + // 创建一个新数组 + Object[] newArray = new Object[data.length * 2]; + System.arraycopy(data, 0, newArray, 0, data.length); + data = newArray; + } + + +} + +``` + +在顺序栈中,数组的第一个元素最为栈底,最后一个元素最为栈顶。当top=-1的时候,此时栈为空。 + +每当新增数据入栈push的时候,maxSize加一,同理删除元素出栈pop的时候,maxSize减一。因为是基础数组的实现,所以顺序栈会涉及一个扩容的情况。 + +- 链式栈 + +我们再来看看基于链表来实现一个链式栈,代码如下: + +```java +public class MyStack { + StackNode top = null; //栈顶 + + private class StackNode{ + E data; + StackNode next; + StackNode(E data) { + this.data=data; + } + } + + /** + * 入栈 + * 首先将要push的数据的next赋值为栈顶top + * 然后将栈顶指针指向新push进来的节点 + * @param data + */ + public void push(E data) { + StackNode newNode = new StackNode(data); + newNode.next = top; + top = newNode; + } + + /** + * 出栈 + * @return + */ + public E pop() { + if(this.isEmpty()) { + throw new RuntimeException("栈为空"); + } + E data = top.data; + top = top.next; + return data; + } + + /** + * 查看栈顶元素 + * @return + */ + public E peek() { + if(isEmpty()) { + throw new RuntimeException("栈为空"); + } + return top.data; + } + + // 判断栈是否为空 + public boolean isEmpty() { + return top == null; + } +} +``` + +在链式栈中,单链表的头部最为栈顶,因为栈的特性是先进后出,所以不需要头节点的。每当新增数据入栈push的时候,需要让新的结点指向原栈顶,然后再让top指向新增的这个结点。同理删除元素出栈pop的时候,只需要栈顶的 top 指向栈顶元素的 next 指针即可完成删除。 + +## 总结 + +栈作为一个受限制的线性表,只允许对栈顶的数据进行操作,也就是所谓的:先进后出,后进先出。不管是顺序栈还是链式栈,新增或者删除数据时都只能在栈顶进行,故时间复杂度都是O(1),查找数据的时候都需要进行全局遍历,故时间复杂度都是O(n)。顺序栈基于数组实现,初始化时大小便已经固定,后续需要考虑扩容的情况,而链式栈基于链表实现,不需要考虑扩容。 + +~ todo \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221.md" new file mode 100644 index 0000000..3a5f8ce --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221.md" @@ -0,0 +1,3 @@ +# 👉 树: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\347\256\227\346\263\225\346\246\202\350\277\260.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\347\256\227\346\263\225\346\246\202\350\277\260.md" new file mode 100644 index 0000000..5c708ff --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\347\256\227\346\263\225\346\246\202\350\277\260.md" @@ -0,0 +1,3 @@ +# 👉 算法概述: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\350\264\252\345\277\203\347\256\227\346\263\225.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\350\264\252\345\277\203\347\256\227\346\263\225.md" new file mode 100644 index 0000000..d2a13de --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\350\264\252\345\277\203\347\256\227\346\263\225.md" @@ -0,0 +1,3 @@ +# 👉 贪心算法: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\200\222\345\275\222\347\256\227\346\263\225.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\200\222\345\275\222\347\256\227\346\263\225.md" new file mode 100644 index 0000000..1ca7f82 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\200\222\345\275\222\347\256\227\346\263\225.md" @@ -0,0 +1,3 @@ +# 👉 递归算法: + +todo~ \ No newline at end of file diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\223\276\350\241\250.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\223\276\350\241\250.md" new file mode 100644 index 0000000..9126d23 --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\223\276\350\241\250.md" @@ -0,0 +1,232 @@ +# 👉 链表:想写好链表代码可真要下点功夫 + + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/链表.png) + +## 前言 + +上一篇文章我们探讨了数组这个非常基础的数据结构。对于数组,我们知道了数组在内存中是按照顺序存储并线性排列,所以具有“随机访问"的能力,但是对于删除和插入等操作却十分低效。 + +今天我们一起探讨一个新的数据结构—**链表**,看看链表是什么?学习链表有什么用? + +## 链表是什么 + +链表是一种非常重要的数据结构,应用的非常广泛,在写链表代码非常容易出错,所以面试中链表经常会被用来考察面试者的逻辑是否严谨。 + +链表它不像数组,数组需要的是一块连续的内存空间来存储,而链表并不需要一块连续的内存你空间(也就是可连续也可不连续),它可以利用“**指针**”(`next`域)将一组零散的内存块串联起来,所有链表的存储方式是随机存储。我们看看链表中的单个节点长什么样,如下如所示: + +![链表单个节点](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/链表单个节点.png) + +图中你可以看到,`data`和`next`。 解释一下: + +1. **data**: 存放结点值的数据域 ; +2. **next**: 记录下个结点地址的指针,也叫做后继指针域; + +链表之所以能够将零散的内存块串联起来,主要就是依靠这个`next`指针。 + +那么接下来,今天我们一起了解三种最常见的链表结构,分别是**单链表**、**双向链表**、**循环链表**等。 + +### 1. 单链表 + +我们先来看看单链表的结构,如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表.png) + +图中我们可以发现,在单链表中每个单节点都包含两部分,也就是上面我们说的`data`和`next`。这里就不再解释了。除此之外,还有一个`head`,这个是什么呢? 这个其实是**头结点**,也就是链表的第一个节点。同样道理,链表最后一个结点我们称为**尾结点**,尾结点比较特殊,它的next指针是指向null的,也就是表示链表的最后一个结点。 + +### 2. 双向链表 + +我们先再来看看双向链表的结构,如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/双向链表.png) + +图中我们可以发现,双向链表是比单链表稍微复杂一些的,在单链表中只有一个方向,每个结点只有一个后继指针`next` , 而双向链表支持两个方向,每个结点中不仅有一个后继指针`next`,还有一个前继指针`pre`,而且第一个结点的前继指针`pre`是指向`null`的。 + +> 思考:双向链表每个结点使用两个指针有什么优缺点呢? + +由图可知,单链表只支持一个方向的遍历,而双向链表是支持两个方向的遍历的。优点就是双向链表要比单链表灵活的多,但是这种灵活是要付出代价的。缺点就是如果存储相同数量的元素,相比单链表而言,双向链表的两个指针是比较浪费空间的。 + +### 3. 循环链表 + +提到循环链表,可分为单向循环链表和双向循环链表,其实都是由上述的两种链表演化而来。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单向循环链表.png) + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/双向循环链表.png) + +单链表的尾结点后继指针是指向`null`,而循环链表的尾结点后继指针是指向链表的头结点的,图中我们可以发现,循环链表就像一个环一样首尾连接。 + +## 链表的基本操作 + +上文中我们一起简单聊了几种常见的链表结构,下面我们以单链表为例,用图解的方式看看链表是怎么进行增删改查的,在开始之前我们先创建一个类。代码如下: + +```java +public class MyLinked { + + private Node head; + + private Node last; + + private int size; + + private static class Node{ + + public int data; + + public Node next; + + public Node(int data){ + this.data=data; + } + } + +} +``` + +### 1. 查找结点 + +当数组在查找元素的时候,可以通过下标快速定位到对应元素。但是链表可没这个能力,在链表中查找某个元素,只能从头结点开始一个个向后查找,直到找到要查找的元素或者找不到。由于从头开始遍历,故时间复杂度为O(N)。链表查找结点过程如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表查找元素.png) + + 查找指定结点的代码如下: + +```java +/** + * 获取指定位置的元素 + * + * @param index 指定位置 + * @return + * @throws Exception + */ +public Node find(int index) throws Exception { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("超出链表实际节点范围!"); + } + Node temp = head; + for (int i = 0; i < index; i++) { + temp = temp.next; + } + return temp; +} +``` + +### 2. 更新结点 + +链表中更新结点如查找过程类似,也是从头开始遍历,找到要更新的结点那个位置,然后直接赋值就可以了。链表更新结点过程如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表更新元素.png) + +### 3. 新增结点 + +链表中新增结点需要考虑三种情况,分别是:头部新增、中间新增、尾部新增。 + +我们先来看看最简单的尾部新增的情况,只需要遍历链表,如果当前结点的`next`指向`null `的话,就直接该结点的`next`指针指向新增的这个结点就可以了。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表尾部新增元素.png)接下来我们在看看头部插入情况,因为在链表头部插入,所有我们不需要遍历链表。我们先将新增的这个结点的`next`指针指向原链表的头结点`head`,然后修改一下头结点的位置为新增的这个结点即可。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表头部新增元素.png) + +最后我们再看看中间新增结点的情况,此时我们需要遍历链表,第一步:将新增的结点的`next`指针指向新增的位置的结点,第二步:将新增的这个位置的前置结点的`next`指针指向新结点即可。这个过程一点要注意,一点不能颠倒顺序,否则容易链表的断开。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表中间新增元素.png) + +指定位置新增结点的代码如下: + +```java + /** + * 指定位置新增元素 + * + * @param data + * @param index + * @throws Exception + */ +public void insert(int data, int index) throws Exception { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("超出链表实际节点范围!"); + } + Node insertNode = new Node(data); + if (size == 0) { + // 空链表 新增 + head = insertNode; + last = insertNode; + } else if (index == 0) { + // 头部新增 + insertNode.next = head; + head = insertNode; + } else if (size == index) { + // 尾部新增 + last.next = insertNode; + last = insertNode; + } else { + // 获得 新增的位置前面一个元素 + Node preNode = find(index - 1); + insertNode.next = preNode.next; + preNode.next = insertNode; + } + // 链表实际长度+1 + size++; +} +``` + + + +### 4. 删除结点 + +链表中删除结点同样需要考虑三种情况,分别是:头部删除、中间删除、尾部删除。 + +我们先来看看最简单的尾部删除的情况,当遍历到链表倒数第二个结点的结点,直接将该结点的`next`结点指向`null`即可。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表尾部删除元素.png) + +接下来我们在看看头部删除情况,当删除链表头部结点的时候,只需要将头结点变更为原头结点的下一个结点为新的头结点即可。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表头部删除元素.png) + +最后我们再看看中间删除结点的情况,这个情况的关键是找到待删除结点的前置结点。修改这个前置结点的下一个结点为待删除结点的下一个结点接口。如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/单链表中间删除元素.png) + +指定位置新增结点的代码如下: + +```java +/** + * 删除指定位置的链表元素 + * + * @param index 指定位置 + * @return 删除的元素 + * @throws Exception +*/ +public Node delete(int index) throws Exception { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("超出链表实际节点范围!"); + } + Node removeNode = null; + if (size == 0) { + // 头部删除 + removeNode = head; + head = head.next; + } else if (size - 1 == index) { + // 尾部删除 + // 获得 删除的位置前面一个元素 + Node preNode = find(index - 1); + removeNode = preNode.next; + preNode.next = null; + last = preNode; + } else { + // 中间删除 + // 获得 删除的位置前面一个元素 + Node preNode = find(index - 1); + removeNode = preNode.next; + preNode.next = preNode.next.next; + } + // 链表实际长度-1 + size--; + return removeNode; +} +``` + +## 总结 + +本文简单介绍了链表这个数据结构,我们知道了链表的优点是大小可变,插入和删除的效率很都非常高。缺点就是如果查找一个元素,你只能从头开始遍历,所以说查询的效率很低。 + diff --git "a/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\230\237\345\210\227.md" "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\230\237\345\210\227.md" new file mode 100644 index 0000000..cd80a2f --- /dev/null +++ "b/docs/\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204/\351\230\237\345\210\227.md" @@ -0,0 +1,123 @@ +# 👉 队列: 排队买包子,还不允许插队的那种 + +## 前言 + +上一篇文章我们简单阐述了**栈**这个基本数据结构,我们知道了,栈最大的特点就是`后进先出`,以及**入栈**和**出栈**这两个基本的操作。今天我们再来学习与**栈**非常相似的另一个数据结构—**队列**,那么接下来我们看看队列到底是什么吧。 + +## 队列是什么 + +首先,当你看到**队列**这两个字的时候,你脑袋里面会不会联想到每天在早餐店排队买包子的场景呢?(什么?你不吃早餐),这个时候不考虑插队情况(拒绝插队,从你我做起)的话,那就是站在队列前面的人先买到包子,后来的人只能站在队尾等待,故先来的先买包子,也就是队列的**先进先出**。 + +上面我们提到`不能插队`,这个其实就是队列的限制,只能按照`先进先出`的规则,所以说队列同栈一样,也是一个操作受限的数据结构。画张图看看队列,如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/顺序队列与链式队列.1y4xfbj2zun4.png) + +## 队列的基本操作 + +队列与栈相似,数组和链表均可以实现队列。其中基于数组实现的队列被称为顺序队列,基于链表实现的队列被称为链式队列。队列支持两种基本操作,分别是**入队**和**出队**,数据入队操作是在队列的队尾,数据的出队是在队列的队头。下面我们以基于数组实现的顺序队列为例,看看队列是如何进行入队和出队操作的。 + +我们先创建一个属于我们的队列,代码就不做解释了,该注释的都注释了,如下代码所示: + +```java +/** + * msJava + * + * @Description 基于数组实现顺序队列 + * @Date 2021-08-01 + */ +public class MyArrayQueue { + + private Object[] array; + //队列容量 + private int n=0; + // 队头 + private int head=0; + // 队尾 + private int tail=0; + + /** + * 队列构造 + * @param capacity 队列容量 + */ + public MyArrayQueue(int capacity){ + array=new Object[capacity]; + n=capacity; + } + + /** + * 查看当前队列是否为空 + * @return + */ + public boolean isEmpty() { + return n == 0; + } + + /** + * 遍历当前队列 + */ + public void ergodic(){ + for (int i = head; i < tail; i++) { + System.out.print(array[i]+" "); + } + System.out.println(); + } + +} +``` + +### 入队 + +我们先来画张图,再唠两毛钱的入队操作,如下图所示: + +**![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/顺序队列—入队.5zboyf0cmqc0.png)** + +如上图中,当6、3、2、1、7、8依次入队之后,此时队头第一个红色块6,队尾是图中黄色块。当有新的数据9入队的时候是直接放到黄色块中的,当数据入队的后,队尾需要向后移动一个位置。 + +我们已经学习过数组了,知道了数组在创建的时候容量已经确定,那么我们基于数组实现其他的数据结构,比如栈和队列,都必然会涉及到数组已满的情况,那么当实现队列的时候,队列已满的情况,你该怎么办呢?类比我们前面文章谈到了,这个你可以好好想想哦。 + +队列入队的代码如下: + +```java + /** + * 入队 + * @param e + * @return + */ + public boolean enqueue(E e){ + if(n==tail){ + throw new RuntimeException("队列已满~" ); + } + array[tail]=e; + tail++; + return true; + } +``` + +### 出队 + +然后再画张图,我们看看出队操作,如下图所示: + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/顺序队列—出队.5kqhi5ajn0w0.png) + +如上图中,当6、3、2等依次出队,每次出队一个数据之后,队头都要向后移动一个位置。队列出队的代码如下: + +```java + /** + * 出队 + * @return + */ + public E dequeue(){ + if(head==tail){ + throw new RuntimeException("队列为空~" ); + } + E ref=(E)array[head]; + ++head; + return ref; + } +``` + +图中可以看到,已经出队的块变成了灰色,随着不断的出队,队列的容量逐渐减少,但是队头左侧的数组空间已经无法利用了(因为队列的只能队头出、队尾进),这样不是造成了空间浪费嘛。的确是这样,其实这样的问题可以采用**循环队列**,我们下一篇文章再来唠唠其他类型的队列。 + +## 总结 + +队列是一种操作受限的数据结构,只能先进先出,队列支持两种基本操作:入队和出队。基于数组实现的队列被称为顺序队列,基于链表实现的队列被称为链式队列。 \ No newline at end of file diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/OSI\344\270\203\345\261\202\346\250\241\345\236\213.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/OSI\344\270\203\345\261\202\346\250\241\345\236\213.md" new file mode 100644 index 0000000..fd1409f --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/OSI\344\270\203\345\261\202\346\250\241\345\236\213.md" @@ -0,0 +1,33 @@ +# 👉 OSI 七层模型 + + image.png + +OSI 模型全称为开放式通信系统互连参考模型,是国际标准化组织 ( ISO ) 提出的一个试图使各种计算机在世界范围内互连为网络的标准框架。 OSI 将计算机网络体系结构划分为七层,每一层实现各自的功能和协议,并完成与相邻层的接口通信。OSI 的服务定义详细说明了各层所提供的服务。某一层的服务就是该层及其下各层的一种能力,它通过接口提供给更高一层。各层所提供的服务与这些服务是怎么实现的无关 + +## ① 应用层 + +应用层位于 OSI 参考模型的第七层,其作用是通过应用程序间的交互来完成特定的网络应用。该层协议定义了应用进程之间的交互规则,通过不同的应用层协议为不同的网络应用提供服务。例如域名系统 DNS,支持万维网应用的 HTTP 协议,电子邮件系统采用的 SMTP 协议等。在应用层交互的数据单元我们称之为报文。 + +## ② 表示层 + +表示层的作用是使通信的应用程序能够解释交换数据的含义,其位于 OSI 参考模型的第六层,向上为应用层提供服务,向下接收来自会话层的服务。该层提供的服务主要包括数据压缩,数据加密以及数据描述。这使得应用程序不必担心在各台计算机中表示和存储的内部格式差异。 + +## ③ 会话层 + +会话层就是负责建立、管理和终止表示层实体之间的通信会话。该层提供了数据交换的定界和同步功能,包括了建立检查点和恢复方案的方法。 + +## ④ 传输层 + +传输层的主要任务是为两台主机进程之间的通信提供服务。应用程序利用该服务传送应用层报文。该服务并不针对某一特定的应用,多种应用可以使用同一个运输层服务。由于一台主机可同时运行多个线程,因此运输层有复用和分用的功能。所谓复用就是指多个应用层进程可同时使用下面运输层的服务,分用和复用相反,是运输层把收到的信息分别交付上面应用层中的相应进程。 + +## ⑤ 网络层 + +两台计算机之间传送数据时其通信链路往往不止一条,所传输的信息甚至可能经过很多通信子网。网络层的主要任务就是选择合适的网间路由和交换节点,确保数据按时成功传送。在发送数据时,网络层把运输层产生的报文或用户数据报封装成分组和包向下传输到数据链路层。在网络层使用的协议是无连接的网际协议(Internet Protocol)和许多路由协议,因此我们通常把该层简单地成为 IP 层。 + +## ⑥ 数据链路层 + +数据链路层通常也叫做链路层,在物理层和网络层之间。两台主机之间的数据传输,总是在一段一段的链路上传送的,这就需要使用专门的链路层协议。在两个相邻节点之间传送数据时,数据链路层将网络层交下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。每一帧包括数据和必要的控制信息。通过控制信息我们可以知道一个帧的起止比特位置,此外,也能使接收端检测出所收到的帧有无差错,如果发现差错,数据链路层能够简单的丢弃掉这个帧,以避免继续占用网络资源。 + +## ⑦ 物理层 + +作为 OSI 参考模型中最低的一层,物理层的作用是实现计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。使其上面的数据链路层不必考虑网络的具体传输介质是什么。该层的主要任务是确定与传输媒体的接口的一些特性(机械特性、电气特性、功能特性,过程特性)。 diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/OSI\344\270\203\345\261\202\347\275\221\347\273\234\346\250\241\345\236\213.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/OSI\344\270\203\345\261\202\347\275\221\347\273\234\346\250\241\345\236\213.md" deleted file mode 100644 index b1bc885..0000000 --- "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/OSI\344\270\203\345\261\202\347\275\221\347\273\234\346\250\241\345\236\213.md" +++ /dev/null @@ -1,17 +0,0 @@ -# OSI 七层网络模型 - -+ 应用层 -> 基于网络构建具体应用。如ftp文件上传下载服务、http服务、dns服务、snmp邮件服务、telnet服务等; -+ 表示层 -> 主要是对接受的数据进行解释、加密、解密、压缩、解压缩等,转化为人能识别的内容(图片、声音、文字)等; -+ 会话层 -> 建立连接并访问验证和会话管理,如登录验证、断点续传、数据沾包分包等; -+ 传输层 -> 定义了传输数据的协议和端口号,如tcp、udp等; -+ 网络层 -> ip地址的封装和解析,如路由器、交换机、防火墙等; -+ 数据链路层 -> mac地址解析和封装,如数据帧、网卡、网桥、交换机等; -+ 物理层 -> 定义物理设备标准,如比特流; - diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/README.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/README.md" new file mode 100644 index 0000000..4bc39e8 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/README.md" @@ -0,0 +1 @@ +![GJ14d.png](https://s.im5i.com/2021/04/14/GJ14d.png) \ No newline at end of file diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/_sidebar.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/_sidebar.md" new file mode 100644 index 0000000..17b58c0 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/_sidebar.md" @@ -0,0 +1,5 @@ +* **👉 计算机网络** [↩](/README) + * [**OSI七层模型**](docs/计算机网络/OSI七层模型.md) + * [**网络协议分层**](docs/计算机网络/网络协议分层.md) + * [**TCP和UDP**](docs/计算机网络/理解TCP和UDP.md) + * [**HTTP与HTTPS**](docs/计算机网络/理解HTTP与HTTPS.md) diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243HTTP\344\270\216HTTPS.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243HTTP\344\270\216HTTPS.md" index ae65a6a..ce77ce2 100644 --- "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243HTTP\344\270\216HTTPS.md" +++ "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243HTTP\344\270\216HTTPS.md" @@ -1,4 +1,4 @@ -# 理解HTTP与HTTPS +# 👉 理解HTTP与HTTPS ## HTTP 概况 diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243TCP\345\222\214UDP.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243TCP\345\222\214UDP.md" index 6e0070e..a86583a 100644 --- "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243TCP\345\222\214UDP.md" +++ "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\220\206\350\247\243TCP\345\222\214UDP.md" @@ -1,4 +1,4 @@ -# 理解TCP和UDP +# 👉 理解TCP和UDP ## 1. TCP是什么 diff --git "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\275\221\347\273\234\345\215\217\350\256\256\345\210\206\345\261\202.md" "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\275\221\347\273\234\345\215\217\350\256\256\345\210\206\345\261\202.md" index ef41df1..a27a568 100644 --- "a/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\275\221\347\273\234\345\215\217\350\256\256\345\210\206\345\261\202.md" +++ "b/docs/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\347\275\221\347\273\234\345\215\217\350\256\256\345\210\206\345\261\202.md" @@ -1,4 +1,4 @@ -# 网络协议分层 +# 👉 网络协议分层 > 国际标准化组织 ISO 提出了 OSI 开放互连的七层计算机网络模型,从上到下分别是应用层、表示层、会 > 话层、运输层、网络层、链路层和物理层。OSI 模型的概念清楚,理论也比较完善,但是既复杂又不实 diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/README.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/README.md" new file mode 100644 index 0000000..2aab32c --- /dev/null +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/README.md" @@ -0,0 +1,2 @@ + +![](https://cdn.jsdelivr.net/gh/msJavaCoder/msJava@master/image/设计模式思维导图.png) diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/_sidebar.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/_sidebar.md" new file mode 100644 index 0000000..3ebaf78 --- /dev/null +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/_sidebar.md" @@ -0,0 +1,4 @@ +* **👉 设计模式** [↩](/README) + * [单例模式](docs/设计模式/单例模式.md) + * [原型模式](docs/设计模式/原型模式.md) + \ No newline at end of file diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" new file mode 100644 index 0000000..b36e4b3 --- /dev/null +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" @@ -0,0 +1,249 @@ +# 👉 单例模式 + +## 1. 单例模式的定义 + +​ **单例模式指的是一个类中在任何情况下都绝对只有一个实例,并且提供一个全局访问点。** + +## 2. 单例模式的应用场景 + +> 单例模式的应用非常广泛,如数据库中的连接池、J2EE中的ServletContext和ServletContextConfig、Spring框架中的ApplicationContext等等。然而在Java中,单例模式还可以保证一个JVM中只存在一个唯一的实例。 + +单例模式的应用场景主要有以下几个方面: + +- 当需要频繁创建一些类的时候,使用单例可以降低系统的内存压力,减少GC(垃圾回收) ; +- 当某些类创建实例时候需要占用的资源较多,或者实例化过程耗时比较长,且经常使用的情况; +- 当存在频繁访问数据库或者文件的对象; +- 当对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,是不允许存在多个实例的,否则玩完; + +## 3. 单例模式的优缺点 + +### 3.1 单例模式的优点 + +- **单例模式可以保证内存中只有一个实例对象,从而会减少内存的开销;** +- **单例模式可以避免对资源的多重占用;** +- **单例模式设置全局访问点,可以起到优化和共享资源的访问的作用;** + +### 3.2 单例模式的缺点 + +- **扩展难**, 因为单例模式通常是没有接口的啊,如果想要扩展,那么你唯一途径就是修改之前的代码,所以说单例模式违背了开闭原则; +- **调试难**,因为在并发测试中,单例模式是不利于代码的调试的,单例中的代码没有执行完,也不能模拟生成一个新对象; +- **违背单一职责原则**,因为单例模式的业务代码通常写在一个类中,如果功能设计不合理,就很容易违背单一职责原则; + +## 4. 单例模式的实现方式及其优缺点 + +### 4.1 单例模式的饿汉式实现 + +#### 4.1.1 饿汉式标准写法 + +Singleton类称为单例类,通过内部初始化一次 , 隐藏构造方法, 并提供一个全局访问点的方式实现。** + +```java +/** + * msJava + * + * @Description 单例模式的通用写法 + * @Date 2021-01-23 + */ +public class Singleton { + /** + * 内部初始化一次 + */ + private static final Singleton instance = new Singleton(); + + /** + * 隐藏构造方法 + */ + private Singleton() { + } + + /** + * 提供一个全局访问点 + * + * @return Singleton + */ + public static Singleton getInstance() { + return instance; + } + +} + +``` + +​ **以上饿汉式单例写法在类的初始化的时候就会进行初始化操作,并且创建对象,绝对的线程安全,因为此时线程还没有出现就已经实例化了,故不会存在访问安全的问题。** + +#### 4.1.2 饿汉式静态块机制写法 + +​ **饿汉式还有一种实现,那就是静态块机制,如下代码所示:** + +```java +/** + * msJava + * + * @Description 单例模式 饿汉式静态机制 实现 + * @Date 2021-01-23 + */ +public class HungryStaticSingleton { + + private static final HungryStaticSingleton hungrySingleton; + //静态代码块 类加载的时候就初始化 + static { + hungrySingleton=new HungryStaticSingleton(); + } + /** + * 私有化构造函数 + */ + private HungryStaticSingleton(){} + + /** + * 提供一个全局访问点 + * @return + */ + public static HungryStaticSingleton getInstance() { + return hungrySingleton; + } +} +``` + +​ **我们分析一下这种是写法 ,可以明显的看到所以对象是类在加载的时候就进行实例化了,那么这样一来,会导致单例对象的数量不确定,从而会导致系统初始化的时候就造成大量内存浪费,况且你用不用还不一定,还一直占着空间,俗称“占着茅坑不拉屎”。** + +### 4.2 单例模式的懒汉式实现 + +​ **为了解决饿汉式单例写法可能带来的内存浪费问题,这里分析一下懒汉式单例的写法。如下代码所示:** + +```java +/** + * msJava + * + * @Description 单例模式 懒汉式单例实现 + * @Date 2021-01-23 + */ +public class LazySimpleSingleton { + + private static LazySimpleSingleton lazySingleton = null; + + /** + * 私有化构造函数 + */ + private LazySimpleSingleton() { + + } + /** + * 提供一个全局访问点 + * + * @return + */ + public static LazySimpleSingleton getInstance() { + if (lazySingleton == null) { + lazySingleton = new LazySimpleSingleton(); + } + return lazySingleton; + } +} + +``` + +​ **这样实现的好处就是只有对象被使用的时候才会进行初始化,不会存在内存浪费的问题,但是它会在多线程环境下,存在线程安全问题。我们可以利用synchronized关键字将全局访问点方法变成一个同步方法,这样就可以解决线程安全的问题,代码如下所示:** + +```java +/** + * msJava + * + * @Description 单例模式 懒汉式单例实现 synchronized修饰 + * @Date 2021-01-23 + */ +public class LazySimpleSingleton { + private static LazySimpleSingleton lazySingleton = null; + /** + * 私有化构造函数 + */ + private LazySimpleSingleton() {} + /** + * 提供一个全局访问点 + * + * @return + */ + public synchronized static LazySimpleSingleton getInstance() { + if (lazySingleton == null) { + lazySingleton = new LazySimpleSingleton(); + } + return lazySingleton; + } +} +``` + +​ **但是,这样虽然解决了线程安全的问题,可是如果在线程数量剧增的情况下,用synchronized加锁,则会导致大批线程阻塞,从而骤减系统性能。** + +### 4.3 单例模式的双重检测实现 + + 在上述代码上进一步优化,代码如下所示: + +```java + +/** + * msJava + * + * @Description 单例模式 懒汉式-双重检测单例实现 + * @Date 2021-01-23 + */ +public class LazyDoubleCheckSingleton { + // volatile 关键字修饰 + private volatile static LazyDoubleCheckSingleton lazySingleton ; + /** + * 私有化构造函数 + */ + private LazyDoubleCheckSingleton() {} + /** + * 提供一个全局访问点 + * + * @return + */ + public static LazyDoubleCheckSingleton getInstance() { + // 这里先判断一下是否阻塞 + if (lazySingleton == null) { + synchronized (LazyDoubleCheckSingleton.class){ + // 判断是否需要重新创建实例 + if (lazySingleton == null) { + lazySingleton = new LazyDoubleCheckSingleton(); + } + } + } + return lazySingleton; + } +} +``` + +​ **当第一个线程调用getInstance()方法时,第二个线程也可以调用,但是第一个线程执行synchronized时候,第二个线程就会发现阻塞,但是此时的阻塞是getInstance()内部的阻塞。** + +#### 4.4 单例模式的静态内部类实现 + +​ **虽然双重检测锁的单例模式解决了线程安全和性能问题,但是毕竟涉及加锁的操作,多多少少就会到了性能的影响,下面我们分享一下更加优雅的单例模式实现,如下代码所示:** + +```java +/** + * msJava + * + * @Description 单例模式 静态内部类单例实现 + * @Date 2021-01-23 + */ +public class LazyStaticInnerClassSingleton { + // 在构造方法里面抛出异常真的合适? + private LazyStaticInnerClassSingleton(){ + if(LazyHolder.INSTANCE != null){ + throw new RuntimeException("不允许创建多个实例"); + } + } + // static 保证这个方法不会被重写 覆盖 + private static LazyStaticInnerClassSingleton getInstance(){ + return LazyHolder.INSTANCE; + } + // Java 默认不会加载内部类 + private static class LazyHolder{ + private static final LazyStaticInnerClassSingleton INSTANCE=new LazyStaticInnerClassSingleton(); + } +} + +``` + +## 5. 总结 + +​ 单例模式面试几乎必备! \ No newline at end of file diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\216\237\345\236\213\346\250\241\345\274\217.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\216\237\345\236\213\346\250\241\345\274\217.md" new file mode 100644 index 0000000..2502767 --- /dev/null +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\216\237\345\236\213\346\250\241\345\274\217.md" @@ -0,0 +1,3 @@ +# 👉 原型模式 + +todo~ \ No newline at end of file diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\267\245\345\216\202\346\250\241\345\274\217.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\267\245\345\216\202\346\250\241\345\274\217.md" new file mode 100644 index 0000000..b2c4c8f --- /dev/null +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\345\267\245\345\216\202\346\250\241\345\274\217.md" @@ -0,0 +1 @@ +todo~ \ No newline at end of file diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217.md" new file mode 100644 index 0000000..b2c4c8f --- /dev/null +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217.md" @@ -0,0 +1 @@ +todo~ \ No newline at end of file diff --git "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\346\235\245\357\274\214\344\270\200\350\265\267\345\244\215\344\271\240\344\270\200\344\270\213\350\256\276\350\256\241\346\250\241\345\274\217\347\232\204\345\205\255\345\244\247\350\256\276\350\256\241\345\216\237\345\210\231\357\274\201.md" "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\350\256\276\350\256\241\346\250\241\345\274\217\345\205\255\345\244\247\350\256\276\350\256\241\345\216\237\345\210\231.md" similarity index 99% rename from "docs/\350\256\276\350\256\241\346\250\241\345\274\217/\346\235\245\357\274\214\344\270\200\350\265\267\345\244\215\344\271\240\344\270\200\344\270\213\350\256\276\350\256\241\346\250\241\345\274\217\347\232\204\345\205\255\345\244\247\350\256\276\350\256\241\345\216\237\345\210\231\357\274\201.md" rename to "docs/\350\256\276\350\256\241\346\250\241\345\274\217/\350\256\276\350\256\241\346\250\241\345\274\217\345\205\255\345\244\247\350\256\276\350\256\241\345\216\237\345\210\231.md" index 0cc07ea..97ef7f4 100644 --- "a/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\346\235\245\357\274\214\344\270\200\350\265\267\345\244\215\344\271\240\344\270\200\344\270\213\350\256\276\350\256\241\346\250\241\345\274\217\347\232\204\345\205\255\345\244\247\350\256\276\350\256\241\345\216\237\345\210\231\357\274\201.md" +++ "b/docs/\350\256\276\350\256\241\346\250\241\345\274\217/\350\256\276\350\256\241\346\250\241\345\274\217\345\205\255\345\244\247\350\256\276\350\256\241\345\216\237\345\210\231.md" @@ -1,3 +1,4 @@ +# 👉 六大设计原则 > 本文我们一起学习设计模式中的六大设计原则 六大设计原则包括:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则,接下来我们一一来看看它们分别是什么。 diff --git "a/docs/\350\265\204\346\272\220\345\210\206\344\272\253/\347\274\226\347\250\213\344\272\272\347\224\237.md" "b/docs/\350\265\204\346\272\220\345\210\206\344\272\253/\347\274\226\347\250\213\344\272\272\347\224\237.md" new file mode 100644 index 0000000..52b79d7 --- /dev/null +++ "b/docs/\350\265\204\346\272\220\345\210\206\344\272\253/\347\274\226\347\250\213\344\272\272\347\224\237.md" @@ -0,0 +1,56 @@ +# 计算机基础 ++ 《图解HTTP》 ++ 《图解TCP/IP》 + +# 数据结构与算法 ++ 《算法 》 ++ 《图解算法》 ++ 《大话数据结构》 ++ 《剑指offer 第二版》 ++ 《程序员代码面试指南 第二版》 ++ 《程序员面试金典 第六版》 + +# Java ++ 《Java编程的逻辑》 ++ 《Effective Java 第三版》 ++ 《深入理解Java虚拟机 第三版》 ++ 《Java并发编程实战》 ++ 《Java并发编程的艺术》 ++ 《Java并发编程之美》 + +# 数据库 ++ 《SQL必知必会》 ++ 《MySQL必知必会》 ++ 《高性能 MySQL》 ++ 《Redis设计与实现》 + + +# 主流开源框架 ++ 《SpringBoot实战派》 ++ 《SpringBoot编程思想》 ++ 《SpringCloud微服务架构实战派》 ++ 《通用源码阅读指导书 MyBatis源码详解》 ++ 《Spring5 核心原理与30个类手写实战》 + + +# 阅读人生 ++ 《认识世界,认识自己》 ++ 《中国通史》 ++ 《毛泽东传》 ++ 《如何学习》 ++ 《围城》 ++ 《平凡的世界》 ++ 《人生》 ++ 《人生海海》 ++ 《理解人性》 ++ 《乌合之众》 ++ 《思考,快与慢》 ++ 《金钱不能买什么》 ++ 《人类简史:从动物到上帝》 ++ 《未来简史:从智人到智神》 ++ 《思维简史:从丛林到宇宙》 ++ 《今日简史:人类命运大议题》 + + + + diff --git "a/docs/\350\270\251\345\235\221\350\256\260\345\275\225/IDEAMaven\344\276\235\350\265\226\346\210\220\345\212\237\345\257\274\345\205\245\344\275\206\344\273\215\347\204\266\346\212\245\351\224\231\346\211\276\344\270\215\345\210\260\345\214\205\350\247\243\345\206\263\346\226\271\346\241\210.md" "b/docs/\350\270\251\345\235\221\350\256\260\345\275\225/IDEAMaven\344\276\235\350\265\226\346\210\220\345\212\237\345\257\274\345\205\245\344\275\206\344\273\215\347\204\266\346\212\245\351\224\231\346\211\276\344\270\215\345\210\260\345\214\205\350\247\243\345\206\263\346\226\271\346\241\210.md" index 8a9c485..2e70972 100644 --- "a/docs/\350\270\251\345\235\221\350\256\260\345\275\225/IDEAMaven\344\276\235\350\265\226\346\210\220\345\212\237\345\257\274\345\205\245\344\275\206\344\273\215\347\204\266\346\212\245\351\224\231\346\211\276\344\270\215\345\210\260\345\214\205\350\247\243\345\206\263\346\226\271\346\241\210.md" +++ "b/docs/\350\270\251\345\235\221\350\256\260\345\275\225/IDEAMaven\344\276\235\350\265\226\346\210\220\345\212\237\345\257\274\345\205\245\344\275\206\344\273\215\347\204\266\346\212\245\351\224\231\346\211\276\344\270\215\345\210\260\345\214\205\350\247\243\345\206\263\346\226\271\346\241\210.md" @@ -1,4 +1,4 @@ -## IDEA 2020 Maven依赖成功导入但仍然报错找不到包解决方案 +# IDEA 2020 Maven依赖成功导入但仍然报错找不到包解决方案 ## 问题描述 diff --git "a/docs/\350\270\251\345\235\221\350\256\260\345\275\225/README.md" "b/docs/\350\270\251\345\235\221\350\256\260\345\275\225/README.md" new file mode 100644 index 0000000..6b6e941 --- /dev/null +++ "b/docs/\350\270\251\345\235\221\350\256\260\345\275\225/README.md" @@ -0,0 +1,3 @@ +# 踩坑记录 + * [IDEAMaven依赖成功导入但仍然报错找不到包解决方案](docs/踩坑记录/IDEAMaven依赖成功导入但仍然报错找不到包解决方案.md) + \ No newline at end of file diff --git "a/docs/\350\270\251\345\235\221\350\256\260\345\275\225/_sidebar.md" "b/docs/\350\270\251\345\235\221\350\256\260\345\275\225/_sidebar.md" new file mode 100644 index 0000000..2bf76a6 --- /dev/null +++ "b/docs/\350\270\251\345\235\221\350\256\260\345\275\225/_sidebar.md" @@ -0,0 +1,3 @@ +* **踩坑记录** + * [IDEAMaven依赖成功导入但仍然报错找不到包解决方案](docs/踩坑记录/IDEAMaven依赖成功导入但仍然报错找不到包解决方案.md) + \ No newline at end of file diff --git "a/docs/\351\235\242\350\257\225\351\242\230/Java\346\240\270\345\277\203\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/Java\346\240\270\345\277\203\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index 81029a2..de9737d 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/Java\346\240\270\345\277\203\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/Java\346\240\270\345\277\203\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -# Java后端开发核心面试题 +# 👉 Java后端开发核心面试题 ## Java 基础部分 diff --git "a/docs/\351\235\242\350\257\225\351\242\230/JVM\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/Java\350\231\232\346\213\237\346\234\272\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" similarity index 99% rename from "docs/\351\235\242\350\257\225\351\242\230/JVM\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" rename to "docs/\351\235\242\350\257\225\351\242\230/Java\350\231\232\346\213\237\346\234\272\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index 9fab676..43a63c4 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/JVM\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/Java\350\231\232\346\213\237\346\234\272\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## JVM 面试题汇总 +# 👉 JVM 面试题汇总 #### 1.什么是 JVM?它有什么作用? diff --git "a/docs/\351\235\242\350\257\225\351\242\230/MyBatis\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/MyBatis\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index aa7cbb4..247beb9 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/MyBatis\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/MyBatis\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,28 +1,7 @@ -## MyBatis - -### MyBatis 介绍 - -MyBatis 是一款优秀的 ORM(Object Relational Mapping,对象关系映射)框架,它可以通过对象和数据库之间的映射,将程序中的对象自动存储到数据库中。它是 Apache 提供的一个开源项目,之前的名字叫做 iBatis,2010 年迁移到了 Google Code,并且将名字改为我们现在所熟知的 MyBatis,又于 2013 年 11 月迁移到了 Github。 - -MyBatis 提供了普通 SQL 查询、事务、存储过程等功能,它的优缺点如下。 - -**优点**: - -- 相比于 JDBC 需要编写的代码更少 -- 使用灵活,支持动态 SQL -- 提供映射标签,支持对象与数据库的字段关系映射 - -**缺点**: - -- SQL 语句依赖于数据库,数据库移植性差 -- SQL 语句编写工作量大,尤其在表、字段比较多的情况下 - -总体来说,MyBatis 是一个非常优秀和灵活的数据持久化框架,适用于需求多变的互联网项目,也是当前主流的 ORM 框架。 +# 👉 MyBatis #### MyBatis 重要组件 -MyBatis 中的重要组件如下: - - Mapper 配置:用于组织具体的查询业务和映射数据库的字段关系,可以使用 XML 格式或 Java 注解格式来实现; - Mapper 接口:数据操作接口也就是通常说的 DAO 接口,要和 Mapper 配置文件中的方法一一对应; - Executor:MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 执行的; @@ -44,244 +23,3 @@ MyBatis 执行流程说明: 5. 封装 SQL 对象,在这一步,执行器将待处理的 SQL 信息封装到一个对象中(MappedStatement),该对象包括 SQL 语句、输入参数映射信息(Java 简单类型、HashMap 或 POJO)和输出结果映射信息(Java 简单类型、HashMap 或 POJO)。 6. 操作数据库,拥有了执行器和 SQL 信息封装对象就使用它们访问数据库了,最后再返回操作结果,结束流程。 -### MyBatis XML 版 - -MyBatis 使用分为两个版本:XML 版和 Java 注解版。接下来我们使用 Spring Boot 结合 MyBatis 的 XML 版,来实现对数据库的基本操作,步骤如下。 - -#### 1)创建数据表 - -```sql -drop table if exists `t_user`; -create table `t_user` ( - `id` bigint(20) not null auto_increment comment '主键id', - `username` varchar(32) default null comment '用户名', - `password` varchar(32) default null comment '密码', - `nick_name` varchar(32) default null, - primary key (`id`) -) engine=innodb auto_increment=1 default charset=utf8; -``` - -#### 2)添加依赖 - -在项目添加对 MyBatis 和 MySQL 支持的依赖包,在 pom.xml 文件中添加如下代码: - -```xml - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - 2.1.0 - - - - mysql - mysql-connector-java - 8.0.16 - -``` - -mybatis-spring-boot-starter 是 MyBatis 官方帮助我们快速集成 Spring Boot 提供的一个组件包,mybatis-spring-boot-starter 2.1.0 对应 MyBatis 的版本是 3.5.2。 - -#### 3)增加配置文件 - -在 application.yml 文件中添加以下内容: - -```xml -spring: - datasource: - url: jdbc:mysql://localhost:3306/learndb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver -mybatis: - config-location: classpath:mybatis/mybatis-config.xml - mapper-locations: classpath:mybatis/mapper/*.xml - type-aliases-package: com.interview.mybatislearning.model -``` - -其中: - -- mybatis.config-location:配置 MyBatis 基础属性; -- mybatis.mapper-locations:配置 Mapper 对应的 XML 文件路径; -- mybatis.type-aliases-package:配置项目中实体类包路径。 - -注:如果配置文件使用的是 application.properties,配置内容是相同的,只是内容格式不同。 - -#### 4)创建实体类 - -```java -public class UserEntity implements Serializable { - private static final long serialVersionUID = -5980266333958177104L; - private Integer id; - private String userName; - private String passWord; - private String nickName; - public UserEntity(String userName, String passWord, String nickName) { - this.userName = userName; - this.passWord = passWord; - this.nickName = nickName; - } - public Integer getId() { - return id; - } - public void setId(Integer id) { - this.id = id; - } - public String getUserName() { - return userName; - } - public void setUserName(String userName) { - this.userName = userName; - } - public String getPassWord() { - return passWord; - } - public void setPassWord(String passWord) { - this.passWord = passWord; - } - public String getNickName() { - return nickName; - } - public void setNickName(String nickName) { - this.nickName = nickName; - } -} -``` - -#### 5)创建 XML 文件 - -**mybatis-config.xml**(基础配置文件): - -```xml - - - - - - - - - - - - -``` - -mybatis-config.xml 主要是为常用的数据类型设置别名,用于减少类完全限定名的长度,比如:`resultType="Integer"` 完整示例代码如下: - -```xml - -``` - -**UserMapper.xml**(业务配置文件): - -```xml - - - - - - - - - - - id, username, password, nick_name - - - - and userName = #{userName} - - - - - - INSERT INTO - t_user - (username,password,nick_name) - VALUES - (#{userName}, #{passWord}, #{nickName}) - - - UPDATE - t_user - SET - username = #{userName}, - password = #{passWord}, - nick_name = #{nickName} - WHERE - id = #{id} - - - DELETE FROM - t_user - WHERE - id =#{id} - - -``` - -以上配置我们增加了增删改查等基础方法。 - -#### 6)增加 Mapper 文件 - -此步骤我们需要创建一个与 XML 对应的业务 Mapper 接口,代码如下: - -```java -public interface UserMapper { - List getAll(); - UserEntity getOne(Long id); - void insert(UserEntity user); - void update(UserEntity user); - void delete(Long id); -} -``` - -#### 7)添加 Mapper 包扫描 - -在启动类中添加 @MapperScan,设置 Spring Boot 启动的时候会自动加载包路径下的 Mapper。 - -```java -@SpringBootApplication -@MapperScan("com.interview.mybatislearning.mapper") -public class MyBatisLearningApplication { - public static void main(String[] args) { - SpringApplication.run(MyBatisLearningApplication.class, args); - } -} -``` - -#### 8)编写测试代码 - -经过以上步骤之后,整个 MyBatis 的集成就算完成了。接下来我们写一个单元测试,验证一下。 - -```java -@RunWith(SpringRunner.class) -@SpringBootTest -public class MybatislearningApplicationTests { - @Resource - private UserMapper userMapper; - @Test - public void testInsert() { - userMapper.insert(new UserEntity("laowang", "123456", "老王")); - Assert.assertEquals(1, userMapper.getAll().size()); - } -} -``` - -### 总结 - -通过本文我们知道 MyBatis 是一个优秀和灵活的数据持久化框架,MyBatis 包含 Mapper 配置、Mapper 接口、Executor、SqlSession、SqlSessionFactory 等几个重要的组件,知道了 MyBatis 基本流程:MyBatis 首先加载 Mapper 配置和 SQL 映射文件,通过创建会话工厂得到 SqlSession 对象,再执行 SQL 语句并返回操作信息。我们也使用 XML 的方式,实现了 MyBatis 对数据库的基础操作。 \ No newline at end of file diff --git "a/docs/\351\235\242\350\257\225\351\242\230/MySQL\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/MySQL\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index 1839010..501ec60 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/MySQL\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/MySQL\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## MySQL 面试题汇总 +# 👉 MySQL 面试题汇总 #### 1.说一下 MySQL 执行一条查询语句的内部执行过程? @@ -60,7 +60,7 @@ D:truncate table t 答:D -题目解析:truncate 清除表数据不会写日志,delete 要写日志,因此 truncate 的效率要高于 delete。 +> 题目解析:truncate 清除表数据不会写日志,delete 要写日志,因此 truncate 的效率要高于 delete。 #### 10.唯一索引和普通索引哪个性能更好? diff --git "a/docs/\351\235\242\350\257\225\351\242\230/README.md" "b/docs/\351\235\242\350\257\225\351\242\230/README.md" new file mode 100644 index 0000000..3c53c50 --- /dev/null +++ "b/docs/\351\235\242\350\257\225\351\242\230/README.md" @@ -0,0 +1,14 @@ +# 面试题 + +* [Java核心面试题汇总](docs/面试题/Java核心面试题汇总.md) +* [算法常用面试题汇总](docs/面试题/算法常用面试题汇总.md) +* [设计模式常见面试题汇总](docs/面试题/设计模式常见面试题汇总.md) +* [MySQL面试题汇总](docs/面试题/MySQL面试题汇总.md) +* [Java虚拟机面试题汇总](docs/面试题/Java虚拟机面试题汇总.md) +* [Spring面试题汇总](docs/面试题/Spring面试题汇总.md) +* [SpringMVC面试题汇总](docs/面试题/SpringMVC面试题汇总.md) +* [MyBatis面试题汇总](docs/面试题/MyBatis面试题汇总.md) +* [SpringBoot面试题汇总](docs/面试题/SpringBoot面试题汇总.md) +* [分布式框架面试题汇总](docs/面试题/分布式框架面试题汇总.md) +* [消息队列面试题汇总](docs/面试题/消息队列面试题汇总.md) + diff --git "a/docs/\351\235\242\350\257\225\351\242\230/SpringBoot\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/SpringBoot\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index b15a07c..d216e4d 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/SpringBoot\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/SpringBoot\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,513 +1,3 @@ -## SpringBoot +# 👉 SpringBoot -### 为什么要用 Spring Boot? - -Spring Boot 来自于 Spring 大家族,是 Spring 官方团队(Pivotal 团队)提供的全新框架,它的诞生解决了 Spring 框架使用较为繁琐的问题。Spring Boot 的核心思想是约定优于配置,让开发人员不需要配置任何 XML 文件,就可以像 Maven 整合 Jar 包一样,整合并使用所有框架。 - -**Spring Boot 特性** - -- 秒级构建一个项目; -- 便捷的对外输出格式,如 REST API、WebSocket、Web 等; -- 简洁的安全集成策略; -- 内嵌容器运行,如 Tomcat、Jetty; -- 强大的开发包,支持热启动; -- 自动管理依赖; -- 自带应用监控。 - -**Spring Boot 2 对系统环境的要求** - -- Java 8+ -- Gradle 4+ or Maven 3.2+ -- Tomcat 8+ - -### Spring Boot 使用 - -在开始之前,我们先来创建一个Spring Boot 项目。 - -Spring Boot 有两种快速创建的方式:Spring 官网在线网站创建和 IntelliJ IDEA 的 Spring Initializr 创建,下面分别来看。 - -#### 创建 Spring Boot 项目 - -##### 1)在线网站创建 - -在浏览器输入 [https://start.spring.io](https://start.spring.io/),页面打开如下图所示: - -![1](https://images.gitbook.cn/edd49590-d9de-11e9-970d-b51140896651) - -填写相应的项目信息,选择对应的 Spring Boot 和 Java 版本点击 “Generate the project”按钮下载项目压缩文件,解压后用 IDEA 打开即可。 - -其中 Group 和 Artifact 是 Maven 项目用来确认依赖项目的标识,比如: - -```xml - - org.springframework - spring-core - 4.1.6.RELEASE - -``` - -Group 对应的是配置文件的 groupId,相当于项目的包名;而 Artifact 对应的是配置文件的 artifactId,相当于项目名。 - -##### 2)使用 IntelliJ IDEA 创建 - -① 新建项目 → 选择 Spring Initialzr,如下图所示: - -![2](https://images.gitbook.cn/66e35660-d9df-11e9-970d-b51140896651) - -② 点击 Next 按钮,填写对应的项目信息(和在线网站创建的字段基本相同),如下图所示: - -![3](https://images.gitbook.cn/93a3c9f0-d9df-11e9-a4a6-41549f4e358a) - -③ 点击 Next 按钮,选择相应的依赖信息,如下图所示: - -![4](https://images.gitbook.cn/c2e4a6d0-d9df-11e9-b9ea-ef21e98d4482) - -④ 点击 Next 按钮,选择项目保存的路径,点击 Finish 创建项目完成,如下图所示: - -![5](https://images.gitbook.cn/db4ad640-d9df-11e9-a4a6-41549f4e358a) - -#### 创建一个 Web 应用 - -1)pom.xml 中添加 Web 模块的依赖,如下所示: - -```xml - - org.springframework.boot - spring-boot-starter-web - -``` - -2)创建后台代码 - -```java -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class HelloController { - @RequestMapping("/index") - public String index(String name) { - return "Hello, " + name; - } -} -``` - -3)启动并访问项目 - -项目的启动类是标识了 @Spring BootApplication 的类,代码如下所示: - -```java -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -@SpringBootApplication -public class SpringbootlearningApplication { - public static void main(String[] args) { - SpringApplication.run(SpringbootlearningApplication.class, args); - } -} -``` - -启动并访问 http://localhost:8080/index?name=laowang 效果如下: - -![6](https://images.gitbook.cn/f54c1810-d9df-11e9-b9ea-ef21e98d4482) - -到目前为止 Spring Boot 的项目就创建并正常运行了。 - -#### 设置配置文件 - -Spring Boot 的配置文件,是 resources 目录下 application.properties 文件,如下图所示: - -![7](https://images.gitbook.cn/070f0f80-d9e0-11e9-a4a6-41549f4e358a) - -可以在配置文件中设置很多关于 Spring 框架的配置,格式如下配置所示: - -```xml -# 项目运行端口 -server.port=8086 -# 请求编码格式 -server.tomcat.uri-encoding=UTF-8 -``` - -Spring Boot 的其他功能开发和 Spring 相同(Spring Boot 2 是基于 Spring Framework 5 构建的),本文就不过多的介绍了,[感兴趣的朋友可以点击这里查看](https://docs.spring.io/spring-boot/docs/current/reference/html/) - -### Spring Boot 发布 - -Spring Boot 项目的发布方式有两种: - -- 内置容器运行 -- 外置容器(Tomcat)运行 - -#### 内置容器运行 - -##### 1)打包应用 - -使用窗口命令,在 pom.xml 同级目录下: - -> mvn clean package -Dmaven.test.skip=true - -Dmaven.test.skip=true 表示不执行测试用例,也不编译测试用例类。 - -##### 2)启动应用 - -后台启动 Java 程序, 命令如下: - -> nohup java -jar springbootlearning-0.0.1-SNAPSHOT.jar & - -**停止程序** - -首先查询 Java 程序的 pid - -> ps -ef|grep java - -再停止程序 - -> kill -9 pid - -操作如下图所示: - -![8](https://images.gitbook.cn/2fe74c60-d9e0-11e9-bef2-d97388d98f3f) - -**扩展内容** - -指定程序运行日志文件 - -> nohup java -jar springbootlearning-0.0.1-SNAPSHOT.jar 1>>logs 2>>errlog & - -其中: - -- 1:表示普通日志 -- 2:表示错误日志 - -#### 外置容器(Tomcat)运行 - -##### 1)排除内置 Tomcat - -```xml - - org.springframework.boot - spring-boot-starter-tomcat - provided - -``` - -将 scope 属性设置为 provided,表示打包不会包含此依赖。 - -##### 2)配置启动类 - -在项目的启动类中继承 Spring BootServletInitializer 并重写 configure() 方法: - -```java -@SpringBootApplication -public class PackageApplication extends SpringBootServletInitializer { - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(PackageApplication.class); - } - public static void main(String[] args) { - SpringApplication.run(PackageApplication.class, args); - } -} -``` - -##### 3)打包应用 - -使用窗口命令,在 pom.xml 同级目录下: - -> mvn clean package -Dmaven.test.skip=true - -##### 4)部署应用 - -打包完成会在 target 目录下生成:项目名 + 版本号.war 文件,复制到 Tomcat 的 webapps 目录下,运行 Tomcat 即可。 - -### 相关面试题 - -#### 1.Spring Boot 2.0 支持最低的 JDK 版本是? - -A:JDK 6 -B:JDK 7 -C:JDK 8 -D:JDK 9 - -答:C - -#### 2.Spring、Spring Boot、Spring Cloud 是什么关系? - -答:它们都是来自于 Spring 大家庭,Spring Boot 是在 Spring 框架的基础上开发而来,让更加方便使用 Spring;Spring Cloud 是依赖于 Spring Boot 而构建的一套微服务治理框架。 - -#### 3.Spring Boot 项目有哪些优势? - -答:Spring Boot 项目优势如下: - -- 开发变得简单,提供了丰富的解决方案,快速集成各种解决方案提升开发效率; -- 配置变得简单,提供了丰富的 Starters,集成主流开源产品往往只需要简单的配置即可; -- 部署变得简单,其本身内嵌启动容器,仅仅需要一个命令即可启动项目,结合 Jenkins、Docker 自动化运维非常容易实现; -- 监控变得简单,自带监控组件,使用 Actuator 轻松监控服务各项状态。 - -#### 4.如何将 Spring Boot 项目打包成 war 包? - -答:在 pom.xml 里设置 `war` 。 - -#### 5.在 Maven 项目中如何修改打包名称? - -答:在 pom.xml 文件的 build 节点中,添加 finalName 节点并设置为要的名称即可,配置如下: - -```xml - - warName - -``` - -#### 6.Ant、Maven、Gradle 有什么区别? - -答:Ant、Maven、Gradle 是 Java 领域中主要有三大构建工具,它们的区别如下: - -- Ant(AnotherNeatTool)诞生于 2000 年,是由 Java 编写,采用 XML 作为构建脚本,这样就允许你在任何环境下运行构建。Ant 是 Java 领域最早的构建工具,不过因为操作复杂,慢慢的已经被淘汰了; -- Maven 诞生于 2004 年,目的是解决程序员使用 Ant 所带来的一些问题,它的好处在于可以将项目过程规范化、自动化、高效化以及强大的可扩展性; -- Gradle 诞生于 2009 年,是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化建构工具。它使用一种基于 Groovy 的特定领域语言来声明项目设置,而不是传统的 XML。结合了前两者的优点,在此基础之上做了很多改进,它具有 Ant 的强大和灵活,又有 Maven 的生命周期管理且易于使用。 - -Spring Boot 官方支持 Maven 和 Gradle 作为项目构建工具。Gradle 虽然有更好的理念,但是相比 Maven 来讲其行业使用率偏低,并且 Spring Boot 官方默认使用 Maven。 - -#### 9.Spring Boot 热部署有几种方式? - -答:Spring Boot 热部署主要有两种方式:Spring Loaded、Spring-boot-devtools。 - -方式 1:Spring Loaded - -在 pom.xml 文件中添加如下依赖: - -```xml - - org.springframework.boot - spring-boot-maven-plugin - - - org.springframework - springloaded - 1.2.6.RELEASE - - - - 此处为入口类 - - -``` - -方式 2:Spring-boot-devtools - -在 pom.xml 文件中添加如下依赖: - -```xml - - org.springframework.boot - spring-boot-devtools - provided - true - -``` - -#### 10.Spring Boot 2.0 可以在 Tomcat 7 运行吗?为什么? - -答:Spring Boot 2.0 无法在 Tomcat 7 上运行。因为 Spring Boot 2.0 使用的是 Spring Framework 5,Spring Framework 5 使用的是 Servlet 3.1,而 Tomcat 7 最高支持到 Servlet 3.0,所以 Spring Boot 2.0 无法在 Tomcat 7 上运行。 - -#### 11.如何使用 Jetty 代替 Tomcat? - -答:在 spring-boot-starter-web 移除现有的依赖项,添加 Jetty 依赖,配置如下: - -```xml - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - - - org.springframework.boot - spring-boot-starter-jetty - -``` - -#### 12.Spring Boot 不支持以下哪个内嵌容器? - -A:Tomcat -B:Jetty -C:Undertow -D:Nginx - -答:D - -题目解析:Jetty 容器支持如下: - -```xml - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - - - org.springframework.boot - spring-boot-starter-jetty - -``` - -Undertow 容器支持如下: - -```xml - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - - - org.springframework.boot - spring-boot-starter-undertow - -``` - -#### 13.Spring Boot 中配置文件有几种格式? - -答:Spring Boot 中有 .properties 和 .yml 两种配置文件格式,它们主要的区别是书写格式不同。 - -.properties 配置文件格式如下: - -```xml -app.user.name = hellojava -``` - -.yml 配置文件格式如下: - -```xml -app: - user: - name: hellojava -``` - -#### 14.项目中有两个配置 application.properties 和 application.yml,以下说法正确的是? - -A:application.properties 的内容会被忽略,只会识别 application.yml 的内容。 -B:两个配置文件同时有效,有相同配置时,以 application.properties 文件为主。 -C:application.yml 的内容会被忽略,只会识别 application.properties 的内容。 -D:两个配置文件同时有效,有相同配置时,以 application.yml 文件为主。 - -答:B - -#### 15.RequestMapping 和 GetMapping 有什么不同? - -答:RequestMapping 和 GetMapping 区别如下: - -- RequestMapping 可以支持 GET、POST、PUT 请求; -- GetMapping 是一个组合注解,相当于 @RequestMapping(method = RequestMethod.GET)。 - -#### 16.以下关于 @RestController 和 @Controller 说法正确的? - -A:@Controller 返回 JSON 数据 -B:@RestController 返回 JSON 数据 -C:@APIController 返回 JSON 数据 -D:以上都对 - -答:B - -#### 17.Spring Cache 常用的缓存注解有哪些? - -答:Spring Cache 常用注解如下: - -- @Cacheable:用来声明方法是可缓存,将结果存储到缓存中以便后续使用相同参数调用时不需执行实际的方法,直接从缓存中取值; -- @CachePut:使用它标注的方法在执行前,不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中; -- CacheEvict:是用来标注在需要清除缓存元素的方法或类上的,当标记在一个类上时表示其中所有方法的执行都会触发缓存的清除操作。 - -#### 18.Spring Boot Admin 和 Spring Boot Actuator 的关系是什么? - -答:Spring Boot Admin 使用了 Spring Boot Actuator 接口进行 UI 美化封装的监控工具,它以图形化的方式查询单个应用的详细状态,也可以使用 Spring Boot Admin 来监控整个集群的状态。 - -#### 19.如何理解 Spring Boot 中的 Stater? - -答:Stater 可以理解为启动器,它是方便开发者快速集成其他框架到 Spring 中的一种技术。比如,spring-boot-starter-data-jpa 就是把 JPA 快速集成到 Spring 中。 - -#### 20.常见的 starter 有哪些? - -答:常见的 starter 如下: - -- spring-boot-starter-web:Web 开发支持 -- spring-boot-starter-data-jpa:JPA 操作数据库支持 -- spring-boot-starter-data-redis:Redis 操作支持 -- spring-boot-starter-data-solr:Solr 权限支持 -- mybatis-spring-boot-starter:MyBatis 框架支持 - -#### 21.Spring Boot Starter JDBC 和 Spring JDBC 有什么关系? - -答:spring-boot-starter-jdbc 是 Spring Boot 针对 JDBC 的使用提供了对应的 Starter 包,在 Spring JDBC 上做了进一步的封装,方便在 Spring Boot 生态中更好的使用 JDBC。 - -#### 22.Spring Boot 有哪几种读取配置的方式? - -答:Spring Boot 可以通过 @Value、@Environment、@ConfigurationProperties 这三种方式来读取。 - -例如,配置文件内容如下: - -```xml -app.name=中文 -``` - -**① Value 方式** - -```java -@Value("${app.name}") -private String appName; -``` - -**② Environment 方式** - -```java -public class HelloController { - @Autowired - private Environment environment; - @RequestMapping("/index") - public String index(String hiName) { - // 读取配置文件 - String appName = environment.getProperty("app.name"); - return "Hello, " + hiName + " |@" + appName; - } -} -``` - -**③ ConfigurationProperties 方式** - -```java -@ConfigurationProperties(prefix = "app") -public class HelloController { - // 读取配置文件,必须有 setter 方法 - private String name; - public void setName(String name) { - this.name = name; - } - @RequestMapping("/index") - public String index(String hiName) { - System.out.println("appname:" + name); - return "Hello, " + hiName + " |@" + appName; - } -} -``` - -#### 23.使用 @Value 读取中文乱码是什么原因?如何处理? - -答:这是因为配置文件的编码格式导致的,需要把编码格式设置为 UTF-8,如下图所示: - -![9](https://images.gitbook.cn/a286b670-d9e0-11e9-a4a6-41549f4e358a) - -设置完成之后,重新启动 IDEA 就可以正常显示中文了。 - -### 总结 - -通过本文我们学习了 Spring Boot 的两种创建方式:在线网站创建和 IntelliJ IDEA 方式创建。知道了 Spring Boot 发布的两种方式:内置容器和外置 Tomcat,知道了 Spring Boot 项目特性,以及配置文件 .properties 和 .yml 的差异,掌握了读取配置文件的三种方式:@Value、@Environment、@ConfigurationProperties。 \ No newline at end of file + ···· 高质量的面试题 整理中 \ No newline at end of file diff --git "a/docs/\351\235\242\350\257\225\351\242\230/SpringMVC\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/SpringMVC\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index c11fe9e..eee0232 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/SpringMVC\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/SpringMVC\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,12 +1,6 @@ -## SpringMVC +# 👉 SpringMVC -### Spring MVC 介绍 - -Spring MVC(Spring Web MVC)是 Spring Framework 提供的 Web 组件,它的实现基于 MVC 的设计模式:Controller(控制层)、Model(模型层)、View(视图层),提供了前端路由映射、视图解析等功能,让 Java Web 开发变得更加简单,也属于 Java 开发中必须要掌握的热门框架。 - -### 执行流程 - -Spring MVC 的执行流程如下: +### Spring MVC 的执行流程 1. 客户端发送请求至前端控制器(DispatcherServlet) 2. 前端控制器根据请求路径,进入对应的处理器 @@ -34,93 +28,6 @@ Spring MVC 的核心组件如下列表所示: 7. **ModelAndView**:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。 8. **ViewResolver**:视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。 -### 自动类型转换 - -自动类型转换指的是,Spring MVC 可以将表单中的字段,自动映射到实体类的对应属性上,请参考以下示例。 - -#### 1. JSP 页面代码 - -```html -<%@ page contentType="text/html;charset=UTF-8" language="java" %> - - -
- 名称:
- 年龄:
- -
- - -``` - -#### 2. 编写实体类 - -```java -public class PersonDTO { - private String name; - private int age; - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - public int getAge() { - return age; - } - public void setAge(int age) { - this.age = age; - } -} -``` - -#### 3. 编写控制器 - -```java -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -@RestController -public class PersonController { - @RequestMapping(value = "/add", produces = "text/plain;charset=utf-8") - public String add(PersonVO person) { - return person.getName() + ":" + person.getAge(); - } -} -``` - -#### 4. 执行结果 - -执行结果如下图所示: - -![2](https://images.gitbook.cn/dd1a0a40-d9da-11e9-970d-b51140896651) - -#### 中文乱码处理 - -业务的操作过程中可能会出现中文乱码的情况,以下是处理中文乱码的解决方案。 -第一步,在 web.xml 添加编码过滤器,配置如下: - -```xml - - encodingFilter - org.springframework.web.filter.CharacterEncodingFilter - - encoding - UTF-8 - - - - encodingFilter - /* - -``` - -第二步,设置 RequestMapping 的 produces 属性,指定返回值类型和编码,如下所示: - -```java -@RequestMapping(value = "/add", produces = "text/plain;charset=utf-8") -``` - ### 拦截器 在 Spring MVC 中可以通过配置和实现 HandlerInterceptor 接口,来实现自己的拦截器。 @@ -511,6 +418,3 @@ public class HomeController{ } ``` -### 总结 - -本文我们了解了 Spring MVC 运行的 8 个步骤和它的 8 大核心组件,也尝试了 Spring MVC 方面的类型转换,可将表单自动转换为实体对象,也使用 Hibernate 的验证功能优雅地实现了参数的验证,还可以通过配置和实现 HandlerInterceptor 接口来自定义拦截器,相信有了这些知识,可以帮助我们更高效地开发 Web 和接口项目。 \ No newline at end of file diff --git "a/docs/\351\235\242\350\257\225\351\242\230/Spring\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/Spring\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index c058dd0..f30f2ff 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/Spring\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/Spring\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## Spring +# 👉 Spring ### Spring 介绍 diff --git "a/docs/\351\235\242\350\257\225\351\242\230/_sidebar.md" "b/docs/\351\235\242\350\257\225\351\242\230/_sidebar.md" new file mode 100644 index 0000000..3679d2f --- /dev/null +++ "b/docs/\351\235\242\350\257\225\351\242\230/_sidebar.md" @@ -0,0 +1,12 @@ +* **👉 面试题** [↩](/README) + * [Java核心面试题汇总](docs/面试题/Java核心面试题汇总.md) + * [算法常用面试题汇总](docs/面试题/算法常用面试题汇总.md) + * [设计模式常见面试题汇总](docs/面试题/设计模式常见面试题汇总.md) + * [MySQL面试题汇总](docs/面试题/MySQL面试题汇总.md) + * [Java虚拟机面试题汇总](docs/面试题/Java虚拟机面试题汇总.md) + * [Spring面试题汇总](docs/面试题/Spring面试题汇总.md) + * [SpringMVC面试题汇总](docs/面试题/SpringMVC面试题汇总.md) + * [MyBatis面试题汇总](docs/面试题/MyBatis面试题汇总.md) + * [SpringBoot面试题汇总](docs/面试题/SpringBoot面试题汇总.md) + * [分布式框架面试题汇总](docs/面试题/分布式框架面试题汇总.md) + * [消息队列面试题汇总](docs/面试题/消息队列面试题汇总.md) diff --git "a/docs/\351\235\242\350\257\225\351\242\230/\345\210\206\345\270\203\345\274\217\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\345\220\210\351\233\206.md" "b/docs/\351\235\242\350\257\225\351\242\230/\345\210\206\345\270\203\345\274\217\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" similarity index 99% rename from "docs/\351\235\242\350\257\225\351\242\230/\345\210\206\345\270\203\345\274\217\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\345\220\210\351\233\206.md" rename to "docs/\351\235\242\350\257\225\351\242\230/\345\210\206\345\270\203\345\274\217\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index 5b2957e..800950a 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/\345\210\206\345\270\203\345\274\217\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\345\220\210\351\233\206.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/\345\210\206\345\270\203\345\274\217\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## Java 分布式框架面试题合集 +# 👉 Java 分布式框架面试题合集 #### 1.什么是 ZooKeeper? diff --git "a/docs/\351\235\242\350\257\225\351\242\230/\346\241\206\346\236\266\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md" "b/docs/\351\235\242\350\257\225\351\242\230/\346\241\206\346\236\266\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md" index 7777310..b0b9d3c 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/\346\241\206\346\236\266\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/\346\241\206\346\236\266\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md" @@ -1,4 +1,4 @@ -# Spring经典面试题汇总 +# 👉 Spring经典面试题汇总 ## 1. Spring的两大特性是什么? diff --git "a/docs/\351\235\242\350\257\225\351\242\230/\346\266\210\346\201\257\351\230\237\345\210\227\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/\346\266\210\346\201\257\351\230\237\345\210\227\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index 195c166..3c4256a 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/\346\266\210\346\201\257\351\230\237\345\210\227\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/\346\266\210\346\201\257\351\230\237\345\210\227\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## 消息队列面试题汇总 +# 👉 消息队列面试题汇总 #### 1.消息队列的应用场景有哪些? diff --git "a/docs/\351\235\242\350\257\225\351\242\230/\347\256\227\346\263\225\345\270\270\347\224\250\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/\347\256\227\346\263\225\345\270\270\347\224\250\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index ad1c989..9617287 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/\347\256\227\346\263\225\345\270\270\347\224\250\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/\347\256\227\346\263\225\345\270\270\347\224\250\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## 算法常用面试题汇总 +# 👉 算法常用面试题汇总 #### 1.说一下什么是二分法?使用二分法时需要注意什么?如何用代码实现? diff --git "a/docs/\351\235\242\350\257\225\351\242\230/\350\256\276\350\256\241\346\250\241\345\274\217\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" "b/docs/\351\235\242\350\257\225\351\242\230/\350\256\276\350\256\241\346\250\241\345\274\217\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" index ef43dc1..3eca0b4 100644 --- "a/docs/\351\235\242\350\257\225\351\242\230/\350\256\276\350\256\241\346\250\241\345\274\217\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" +++ "b/docs/\351\235\242\350\257\225\351\242\230/\350\256\276\350\256\241\346\250\241\345\274\217\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -## 设计模式常见面试题汇总 +# 👉 设计模式常见面试题汇总 #### 1.说一下设计模式?你都知道哪些? diff --git "a/image/\345\205\254\344\274\227\345\217\267\344\272\214\347\273\264\347\240\201.jpg" "b/image/\345\205\254\344\274\227\345\217\267\344\272\214\347\273\264\347\240\201.jpg" new file mode 100644 index 0000000..bd36374 Binary files /dev/null and "b/image/\345\205\254\344\274\227\345\217\267\344\272\214\347\273\264\347\240\201.jpg" differ diff --git "a/image/\345\215\225\345\220\221\345\276\252\347\216\257\351\223\276\350\241\250.png" "b/image/\345\215\225\345\220\221\345\276\252\347\216\257\351\223\276\350\241\250.png" new file mode 100644 index 0000000..0b67f1e Binary files /dev/null and "b/image/\345\215\225\345\220\221\345\276\252\347\216\257\351\223\276\350\241\250.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250.png" "b/image/\345\215\225\351\223\276\350\241\250.png" new file mode 100644 index 0000000..9248d1d Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\344\270\255\351\227\264\345\210\240\351\231\244\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\344\270\255\351\227\264\345\210\240\351\231\244\345\205\203\347\264\240.png" new file mode 100644 index 0000000..12967fc Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\344\270\255\351\227\264\345\210\240\351\231\244\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\344\270\255\351\227\264\346\226\260\345\242\236\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\344\270\255\351\227\264\346\226\260\345\242\236\345\205\203\347\264\240.png" new file mode 100644 index 0000000..96f42b3 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\344\270\255\351\227\264\346\226\260\345\242\236\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\345\244\264\351\203\250\345\210\240\351\231\244\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\345\244\264\351\203\250\345\210\240\351\231\244\345\205\203\347\264\240.png" new file mode 100644 index 0000000..db03bb3 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\345\244\264\351\203\250\345\210\240\351\231\244\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\345\244\264\351\203\250\346\226\260\345\242\236\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\345\244\264\351\203\250\346\226\260\345\242\236\345\205\203\347\264\240.png" new file mode 100644 index 0000000..e094008 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\345\244\264\351\203\250\346\226\260\345\242\236\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\345\260\276\351\203\250\345\210\240\351\231\244\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\345\260\276\351\203\250\345\210\240\351\231\244\345\205\203\347\264\240.png" new file mode 100644 index 0000000..8211ba0 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\345\260\276\351\203\250\345\210\240\351\231\244\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\345\260\276\351\203\250\346\226\260\345\242\236\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\345\260\276\351\203\250\346\226\260\345\242\236\345\205\203\347\264\240.png" new file mode 100644 index 0000000..09468e9 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\345\260\276\351\203\250\346\226\260\345\242\236\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\346\233\264\346\226\260\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\346\233\264\346\226\260\345\205\203\347\264\240.png" new file mode 100644 index 0000000..f8bbc60 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\346\233\264\346\226\260\345\205\203\347\264\240.png" differ diff --git "a/image/\345\215\225\351\223\276\350\241\250\346\237\245\346\211\276\345\205\203\347\264\240.png" "b/image/\345\215\225\351\223\276\350\241\250\346\237\245\346\211\276\345\205\203\347\264\240.png" new file mode 100644 index 0000000..90a6fa2 Binary files /dev/null and "b/image/\345\215\225\351\223\276\350\241\250\346\237\245\346\211\276\345\205\203\347\264\240.png" differ diff --git "a/image/\345\217\214\345\220\221\345\276\252\347\216\257\351\223\276\350\241\250.png" "b/image/\345\217\214\345\220\221\345\276\252\347\216\257\351\223\276\350\241\250.png" new file mode 100644 index 0000000..13d1296 Binary files /dev/null and "b/image/\345\217\214\345\220\221\345\276\252\347\216\257\351\223\276\350\241\250.png" differ diff --git "a/image/\345\217\214\345\220\221\351\223\276\350\241\250.png" "b/image/\345\217\214\345\220\221\351\223\276\350\241\250.png" new file mode 100644 index 0000000..329f31f Binary files /dev/null and "b/image/\345\217\214\345\220\221\351\223\276\350\241\250.png" differ diff --git "a/image/\345\276\252\347\216\257\351\223\276\350\241\250.png" "b/image/\345\276\252\347\216\257\351\223\276\350\241\250.png" new file mode 100644 index 0000000..01b2513 Binary files /dev/null and "b/image/\345\276\252\347\216\257\351\223\276\350\241\250.png" differ diff --git "a/image/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217.png" "b/image/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217.png" new file mode 100644 index 0000000..05e4256 Binary files /dev/null and "b/image/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\344\270\223\346\240\217.png" differ diff --git "a/image/\346\225\260\347\273\204.png" "b/image/\346\225\260\347\273\204.png" new file mode 100644 index 0000000..66169af Binary files /dev/null and "b/image/\346\225\260\347\273\204.png" differ diff --git "a/image/\346\225\260\347\273\2041.png" "b/image/\346\225\260\347\273\2041.png" new file mode 100644 index 0000000..2128d60 Binary files /dev/null and "b/image/\346\225\260\347\273\2041.png" differ diff --git "a/image/\346\225\260\347\273\2042.png" "b/image/\346\225\260\347\273\2042.png" new file mode 100644 index 0000000..9a5b7e0 Binary files /dev/null and "b/image/\346\225\260\347\273\2042.png" differ diff --git "a/image/\346\225\260\347\273\2043.png" "b/image/\346\225\260\347\273\2043.png" new file mode 100644 index 0000000..357579b Binary files /dev/null and "b/image/\346\225\260\347\273\2043.png" differ diff --git "a/image/\346\225\260\347\273\2044.png" "b/image/\346\225\260\347\273\2044.png" new file mode 100644 index 0000000..5b1c892 Binary files /dev/null and "b/image/\346\225\260\347\273\2044.png" differ diff --git "a/image/\346\240\210.276ioja9ty4.png" "b/image/\346\240\210.276ioja9ty4.png" new file mode 100644 index 0000000..824bd54 Binary files /dev/null and "b/image/\346\240\210.276ioja9ty4.png" differ diff --git "a/image/\347\240\201\344\270\212Java.webp" "b/image/\347\240\201\344\270\212Java.webp" new file mode 100644 index 0000000..a66df05 Binary files /dev/null and "b/image/\347\240\201\344\270\212Java.webp" differ diff --git "a/image/\350\256\276\350\256\241\346\250\241\345\274\217\346\200\235\347\273\264\345\257\274\345\233\276.png" "b/image/\350\256\276\350\256\241\346\250\241\345\274\217\346\200\235\347\273\264\345\257\274\345\233\276.png" new file mode 100644 index 0000000..4e22b4b Binary files /dev/null and "b/image/\350\256\276\350\256\241\346\250\241\345\274\217\346\200\235\347\273\264\345\257\274\345\233\276.png" differ diff --git "a/image/\351\223\276\350\241\250.png" "b/image/\351\223\276\350\241\250.png" new file mode 100644 index 0000000..dce6b8b Binary files /dev/null and "b/image/\351\223\276\350\241\250.png" differ diff --git "a/image/\351\223\276\350\241\250\345\215\225\344\270\252\350\212\202\347\202\271.png" "b/image/\351\223\276\350\241\250\345\215\225\344\270\252\350\212\202\347\202\271.png" new file mode 100644 index 0000000..c5b5edd Binary files /dev/null and "b/image/\351\223\276\350\241\250\345\215\225\344\270\252\350\212\202\347\202\271.png" differ diff --git "a/image/\351\241\272\345\272\217\346\240\210\344\270\216\351\223\276\345\274\217\346\240\210.png" "b/image/\351\241\272\345\272\217\346\240\210\344\270\216\351\223\276\345\274\217\346\240\210.png" new file mode 100644 index 0000000..284e1d5 Binary files /dev/null and "b/image/\351\241\272\345\272\217\346\240\210\344\270\216\351\223\276\345\274\217\346\240\210.png" differ diff --git "a/image/\351\241\272\345\272\217\351\230\237\345\210\227\342\200\224\345\205\245\351\230\237.5zboyf0cmqc0.png" "b/image/\351\241\272\345\272\217\351\230\237\345\210\227\342\200\224\345\205\245\351\230\237.5zboyf0cmqc0.png" new file mode 100644 index 0000000..8bbdf81 Binary files /dev/null and "b/image/\351\241\272\345\272\217\351\230\237\345\210\227\342\200\224\345\205\245\351\230\237.5zboyf0cmqc0.png" differ diff --git "a/image/\351\241\272\345\272\217\351\230\237\345\210\227\342\200\224\345\207\272\351\230\237.5kqhi5ajn0w0.png" "b/image/\351\241\272\345\272\217\351\230\237\345\210\227\342\200\224\345\207\272\351\230\237.5kqhi5ajn0w0.png" new file mode 100644 index 0000000..e53e448 Binary files /dev/null and "b/image/\351\241\272\345\272\217\351\230\237\345\210\227\342\200\224\345\207\272\351\230\237.5kqhi5ajn0w0.png" differ diff --git "a/image/\351\241\272\345\272\217\351\230\237\345\210\227\344\270\216\351\223\276\345\274\217\351\230\237\345\210\227.1y4xfbj2zun4.png" "b/image/\351\241\272\345\272\217\351\230\237\345\210\227\344\270\216\351\223\276\345\274\217\351\230\237\345\210\227.1y4xfbj2zun4.png" new file mode 100644 index 0000000..fe0593a Binary files /dev/null and "b/image/\351\241\272\345\272\217\351\230\237\345\210\227\344\270\216\351\223\276\345\274\217\351\230\237\345\210\227.1y4xfbj2zun4.png" differ diff --git a/images/msjava.jpg b/images/msjava.jpg deleted file mode 100644 index 1c97b3a..0000000 Binary files a/images/msjava.jpg and /dev/null differ diff --git a/index.html b/index.html index 60b0f9c..1ce2702 100644 --- a/index.html +++ b/index.html @@ -9,36 +9,302 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> + + + + + -
+
‍🏃 ‍💨 嘟嘟嘟 疯狂 加载中...
+
+ +
+ @@ -47,18 +313,130 @@ navigator.serviceWorker.register('sw.js') } + + + + - - + + + + - - + + + + + + + + + + + + + + + + + + diff --git a/out/production/msJava/com/imood/msjava/Main.class b/out/production/msJava/com/imood/msjava/Main.class deleted file mode 100644 index 0d76a21..0000000 Binary files a/out/production/msJava/com/imood/msjava/Main.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/Test$ListNode.class b/out/production/msJava/com/imood/msjava/Test$ListNode.class deleted file mode 100644 index 0b98bd0..0000000 Binary files a/out/production/msJava/com/imood/msjava/Test$ListNode.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/Test.class b/out/production/msJava/com/imood/msjava/Test.class deleted file mode 100644 index 7937240..0000000 Binary files a/out/production/msJava/com/imood/msjava/Test.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/leetcode/ListNode.class b/out/production/msJava/com/imood/msjava/leetcode/ListNode.class deleted file mode 100644 index 41642f7..0000000 Binary files a/out/production/msJava/com/imood/msjava/leetcode/ListNode.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/leetcode/MergeTwoLists.class b/out/production/msJava/com/imood/msjava/leetcode/MergeTwoLists.class deleted file mode 100644 index 752d026..0000000 Binary files a/out/production/msJava/com/imood/msjava/leetcode/MergeTwoLists.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/leetcode/RunningSum.class b/out/production/msJava/com/imood/msjava/leetcode/RunningSum.class deleted file mode 100644 index 085af53..0000000 Binary files a/out/production/msJava/com/imood/msjava/leetcode/RunningSum.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/offer/FindNumbersWithSum.class b/out/production/msJava/com/imood/msjava/offer/FindNumbersWithSum.class deleted file mode 100644 index 74c2f9a..0000000 Binary files a/out/production/msJava/com/imood/msjava/offer/FindNumbersWithSum.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/offer/MoreThanHalfNum_Solution.class b/out/production/msJava/com/imood/msjava/offer/MoreThanHalfNum_Solution.class deleted file mode 100644 index 30752b1..0000000 Binary files a/out/production/msJava/com/imood/msjava/offer/MoreThanHalfNum_Solution.class and /dev/null differ diff --git a/out/production/msJava/com/imood/msjava/sort/Sort.class b/out/production/msJava/com/imood/msjava/sort/Sort.class deleted file mode 100644 index 8fcf03a..0000000 Binary files a/out/production/msJava/com/imood/msjava/sort/Sort.class and /dev/null differ diff --git "a/out/production/msJava/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/Stack.class" "b/out/production/msJava/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/Stack.class" deleted file mode 100644 index c99812f..0000000 Binary files "a/out/production/msJava/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/Stack.class" and /dev/null differ diff --git "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\346\207\222\346\261\211\346\250\241\345\274\217.class" "b/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\346\207\222\346\261\211\346\250\241\345\274\217.class" deleted file mode 100644 index b0af221..0000000 Binary files "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\346\207\222\346\261\211\346\250\241\345\274\217.class" and /dev/null differ diff --git "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\351\245\245\346\261\211\346\250\241\345\274\217.class" "b/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\351\245\245\346\261\211\346\250\241\345\274\217.class" deleted file mode 100644 index b9c5ba7..0000000 Binary files "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\351\245\245\346\261\211\346\250\241\345\274\217.class" and /dev/null differ diff --git "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton\357\274\277\345\217\214\351\207\215\346\243\200\346\265\213\351\224\201.class" "b/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton\357\274\277\345\217\214\351\207\215\346\243\200\346\265\213\351\224\201.class" deleted file mode 100644 index 342d205..0000000 Binary files "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton\357\274\277\345\217\214\351\207\215\346\243\200\346\265\213\351\224\201.class" and /dev/null differ diff --git "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/\346\200\273\347\273\223.md" "b/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/\346\200\273\347\273\223.md" deleted file mode 100644 index 9f53c69..0000000 --- "a/out/production/msJava/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/\346\200\273\347\273\223.md" +++ /dev/null @@ -1,18 +0,0 @@ -# 单例模式 -> 单例模式是指一个类在运行期间始终只有一个实例,我们把它称之为单例模式。 -> 单例模式的典型应用场景是 Spring 中 Bean 实例,它默认就是 singleton 单例模式。 -> 单例模式的优点很明显,可以有效地节约内存,并提高对象的访问速度, -> 同时避免重复创建和销毁对象所带来的性能消耗,尤其是对频繁创建和销毁对象的业务场景来说优势更明显。 -> 然而单例模式一般不会实现接口,因此它的扩展性不是很好,并且单例模式违背了单一职责原则,因为单例类在一个方法中既创建了类又提供类对象的复合操作,这样就违背了单一职责原则,这也是单例模式的缺点所在。 -## 1. 单例模式——饥汉模式 -+ 优点是线程安全,因为单例对象在类加载的时候就已经被初始化了, -当调用单例对象时只是把早已经创建好的对象赋值给变量; -+ 缺点是可能会造成资源浪费,如果类加载了单例对象(对象被创建了), -但是一直没有使用,这样就造成了资源的浪费。 -## 2. 单例模式——懒汉模式 -+ 优点是不会造成资源的浪费,因为在调用的时候才会创建被实例化对象; -+ 缺点在多线程环境下是非线程是安全的,比如多个线程同时执行到 if 判断处,此时判断结果都是未被初始化, -那么这些线程就会同时创建 n 个实例,这样就会导致意外的情况发生。 -## 1 2 总结 -使用单例模式可以减少系统的内存开销,提高程序的运行效率,但是使用不当的话就会造成多线程下的并发问题。 -饿汉模式为最直接的实现单例模式的方法,但它可能会造成对系统资源的浪费. diff --git a/src/com/imood/msjava/Main.java b/src/com/imood/msjava/Main.java deleted file mode 100644 index 3270f6a..0000000 --- a/src/com/imood/msjava/Main.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.imood.msjava; - -/** - * @description: 三次反转实现字符串循环右边移动N位 - * @author: msJava - * @createDate: 2020/07/02 - * @version: 1.0 - */ -public class Main { - - /** - * 交换位置 - * - * @param chars - * @param begin - * @param end - */ - public void swap(char[] chars, int begin, int end) { - while (begin < end) { - char temp = chars[begin]; - chars[begin] = chars[end]; - chars[end] = temp; - begin++; - end--; - } - } - - public String moveString(String str, int n) { - char[] chars = str.toCharArray(); - swap(chars, 0, chars.length - 1); - swap(chars, 0, n - 1); - swap(chars, n, chars.length - 1); - return new String(chars); - } - /* public static void main(String[] args) { - Scanner input=new Scanner(System.in); - String str = input.nextLine(); - //移动位数 - int N = input.nextInt(); - System.out.println(new Main().moveString(str,N)); - }*/ - - - public static void main(String[] args) { - System.out.println(3 * 0.1); - } -} diff --git a/src/com/imood/msjava/Test.java b/src/com/imood/msjava/Test.java deleted file mode 100644 index 8453fcb..0000000 --- a/src/com/imood/msjava/Test.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.imood.msjava; - -/** - * @description: - * @author: msJava - * @createDate: 2020/07/02 - * @version: 1.0 - */ -public class Test { - - /** - * 输入单链表的倒数第N个元素 - * - * @param head - * @param N - * @return - */ - public int kthToLast(ListNode head, int N) { - //双指针法 - - int a; - ListNode pre = head; - ListNode low = head; - if (head.next == null) { - return head.val; - } - //先让pre在单链表上走N步,然后两个一起走, - // pre到链表尾部时,low刚好位于链表倒数第N个节点上,直接返回该节点即可 - for (int i = 0; i < N; i++) { - pre = pre.next; - } - while (pre != null) { - pre = pre.next; - low = low.next; - } - return low.val; - - } - - /** - * 单链表实体 - */ - class ListNode { - int val; - ListNode next; - - ListNode(int x) { - val = x; - } - } - - -} diff --git a/src/com/imood/msjava/leetcode/HasCycle_141.java b/src/com/imood/msjava/leetcode/HasCycle_141.java deleted file mode 100644 index e1a58b8..0000000 --- a/src/com/imood/msjava/leetcode/HasCycle_141.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description:判断链表是否存在环 - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class HasCycle_141 { - /** - * 使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。 - * - * @param head - * @return - */ - public boolean hasCycle(ListNode head) { - if (head == null) { - return false; - } - - ListNode low = head; - ListNode high = head.next; - - while (low != null && high != null && high.next != null) { - if (low == high) { - return true; - } - low = low.next; - high = high.next; - } - return false; - } -} diff --git a/src/com/imood/msjava/leetcode/IsValid_20.java b/src/com/imood/msjava/leetcode/IsValid_20.java deleted file mode 100644 index 7e7b7bf..0000000 --- a/src/com/imood/msjava/leetcode/IsValid_20.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.imood.msjava.leetcode; - -import java.util.Stack; - -/** - * @description: 用栈实现括号匹配 - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class IsValid_20 { - - - /** - * 用栈实现括号匹配 - * - * @param s - * @return - */ - public boolean isValid(String s) { - Stack stack = new Stack<>(); - for (char c : s.toCharArray()) { - if (c == '(' || c == '{' || c == '[') { - stack.push(c); - } else { - if (stack.isEmpty()) { - return false; - } - char cStack = stack.pop(); - boolean b1 = c == ')' && cStack != '('; - boolean b2 = c == ']' && cStack != '['; - boolean b3 = c == '}' && cStack != '{'; - if (b1 || b2 || b3) { - return false; - } - } - } - return stack.isEmpty(); - } - -} diff --git a/src/com/imood/msjava/leetcode/ListNode.java b/src/com/imood/msjava/leetcode/ListNode.java deleted file mode 100644 index 162fe00..0000000 --- a/src/com/imood/msjava/leetcode/ListNode.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/7/2/0002 - */ -public class ListNode { - int val; - ListNode next; - - public ListNode(int val) { - this.val = val; - } -} diff --git a/src/com/imood/msjava/leetcode/MergeTwoLists.java b/src/com/imood/msjava/leetcode/MergeTwoLists.java deleted file mode 100644 index c5e9bf6..0000000 --- a/src/com/imood/msjava/leetcode/MergeTwoLists.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/7/2/0002 - */ -public class MergeTwoLists { - - - /** - * 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。 - * - * @param l1 - * @param l2 - * @return - */ - public ListNode mergeTwoLists(ListNode l1, ListNode l2) { - - ListNode newHead = null; - - if (l1 == null) { - return l1; - } - if (l2 == null) { - return l2; - } - if (l1.val < l2.val) { - l1.next = mergeTwoLists(l1.next, l2); - return l1; - } else { - l2.next = mergeTwoLists(l1, l2.next); - return l2; - } - } -} - - - - diff --git a/src/com/imood/msjava/leetcode/MergeTwoLists_21.java b/src/com/imood/msjava/leetcode/MergeTwoLists_21.java deleted file mode 100644 index 4c82718..0000000 --- a/src/com/imood/msjava/leetcode/MergeTwoLists_21.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description:归并两个有序的链表 - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class MergeTwoLists_21 { - - /** - * 归并两个有序的链表 - * - * @param l1 - * @param l2 - * @return - */ - public ListNode mergeTwoLists(ListNode l1, ListNode l2) { - if (l1 == null) { - return l2; - } - if (l2 == null) { - return l1; - } - - if (l1.val < l2.val) { - l1.next = mergeTwoLists(l1.next, l2); - return l1; - } else { - l2.next = mergeTwoLists(l1, l2.next); - return l2; - } - } - -} diff --git a/src/com/imood/msjava/leetcode/RemoveNthFromEnd_19.java b/src/com/imood/msjava/leetcode/RemoveNthFromEnd_19.java deleted file mode 100644 index 1689f71..0000000 --- a/src/com/imood/msjava/leetcode/RemoveNthFromEnd_19.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class RemoveNthFromEnd_19 { - - /** - * 删除链表的倒数第 n 个节点 双指针 - * - * @param head - * @param n - * @return - */ - public ListNode removeNthFromEnd(ListNode head, int n) { - ListNode fast = head; - // 快指针先走n步 - while (n-- > 0) { - fast = fast.next; - } - if (fast == null) { - return head.next; - } - ListNode slow = head; - // 快慢指针一起走 - while (fast.next != null) { - fast = fast.next; - slow = slow.next; - } - //当fast.next == null 的时候,就到了 - slow.next = slow.next.next; - return head; - } - -} diff --git a/src/com/imood/msjava/leetcode/ReverseList_206.java b/src/com/imood/msjava/leetcode/ReverseList_206.java deleted file mode 100644 index 5a3afc1..0000000 --- a/src/com/imood/msjava/leetcode/ReverseList_206.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description: 链表反转 - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class ReverseList_206 { - - /** - * 递归解决 —— 链表反转 - * - * @param head - * @return - */ - public ListNode reverseList(ListNode head) { - - if (head == null || head.next == null) { - return head; - } - ListNode next = head.next; - ListNode newHead = reverseList(next); - next.next = head; - head.next = null; - return newHead; - } - -} diff --git a/src/com/imood/msjava/leetcode/RunningSum.java b/src/com/imood/msjava/leetcode/RunningSum.java deleted file mode 100644 index 427b2ff..0000000 --- a/src/com/imood/msjava/leetcode/RunningSum.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.imood.msjava.leetcode; - -import java.util.ArrayList; -import java.util.List; - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/7/2/0002 - * @version: 1.0 - */ -public class RunningSum { - - - /** - * 给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。 - *

- * 请返回 nums 的动态和。 - * - * @param nums - * @return - */ - public static int[] runningSum(int[] nums) { - int temp = 0; - for (int i = 0; i < nums.length; i++) { - temp += nums[i]; - nums[i] = temp; - } - return nums; - } - - public static void main(String[] args) { - int[] arr = {1, 2, 3, 4, 5}; - int[] ints = RunningSum.runningSum(arr); - - for (int i = 0; i < ints.length; i++) { - System.out.println(ints[i]); - } - } -} diff --git a/src/com/imood/msjava/leetcode/TwoSum_167.java b/src/com/imood/msjava/leetcode/TwoSum_167.java deleted file mode 100644 index 307b97d..0000000 --- a/src/com/imood/msjava/leetcode/TwoSum_167.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description: 167. 两数之和 II - 输入有序数组 - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class TwoSum_167 { - - /** - * 题目描述:在有序数组中找出两个数,使它们的和为 target。 - * 思路: - * 使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。 - * 如果两个指针指向元素的和 sum == target,那么得到要求的结果; - * 如果 sum > target,移动较大的元素,使 sum 变小一些; - * 如果 sum < target,移动较小的元素,使 sum 变大一些。 - * 数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。 - * - * @param numbers - * @param target - * @return - */ - public int[] twoSum(int[] numbers, int target) { - if (numbers == null) { - return null; - } - int low = 0; - int high = numbers.length - 1; - - while (low < high) { - int sum = numbers[low] + numbers[high]; - if (sum == target) { - //返回数组下标+1 - return new int[]{low + 1, high + 1}; - } else if (sum < target) { - low++; - } else { - high--; - } - } - - return null; - } -} diff --git a/src/com/imood/msjava/leetcode/judgeSquareSum_633.java b/src/com/imood/msjava/leetcode/judgeSquareSum_633.java deleted file mode 100644 index 35ad976..0000000 --- a/src/com/imood/msjava/leetcode/judgeSquareSum_633.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.imood.msjava.leetcode; - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -public class judgeSquareSum_633 { - - /** - * 题目描述:判断一个非负整数是否为两个整数的平方和。 - *

- * 可以看成是在元素为 0~target 的有序数组中查找两个数,使得这两个数的平方和为 target, - * 如果能找到,则返回 true,表示 target 是两个整数的平方和。\ - *

- *

- * 本题的关键是右指针的初始化,实现剪枝, - * 从而降低时间复杂度。设右指针为 x,左指针固定为 0,为了使 02 + x2 的值尽可能接近 target, - * 我们可以将 x 取为 sqrt(target)。 - * - * @param target - * @return - */ - public boolean judgeSquareSum(int target) { - if (target < 0) { - return false; - } - int low = 0; - int high = (int) Math.sqrt(target); - - while (low <= high) { - - int powSum = low * low + high * high; - if (powSum == target) { - return true; - } else if (target < powSum) { - high--; - } else { - low++; - } - } - return false; - } -} diff --git a/src/com/imood/msjava/offer/FindNumbersWithSum.java b/src/com/imood/msjava/offer/FindNumbersWithSum.java deleted file mode 100644 index 874eef4..0000000 --- a/src/com/imood/msjava/offer/FindNumbersWithSum.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.imood.msjava.offer; - -import java.util.ArrayList; - -/** - * @description: 剑指offer——题解(自解) - * @author: 微信公众号:码上Java - * @createDate: 2020/6/26/0026 - * @version: 1.0 - */ -public class FindNumbersWithSum { - - /** - * 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S, - * 如果有多对数字的和等于S,输出两个数的乘积最小的。 - * - * @param array - * @param sum - * @return - */ - public ArrayList findNumbersWithSum(int[] array, int sum) { - ArrayList result = new ArrayList<>(); - if (array == null || array.length == 0) { - return result; - } - - int low = 0; - int high = array.length - 1; - - while (low < high) { - if (array[low] + array[high] == sum) { - result.add(array[low]); - result.add(array[high]); - return result; - } else if (array[low] + array[high] > sum) { - high--; - } else { - low++; - } - } - return result; - } - - public static void main(String[] args) { - int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - - int num = 7; - - ArrayList integers = new FindNumbersWithSum().findNumbersWithSum(array, num); - - - for (int i = 0; i < integers.size(); i++) { - System.out.print(integers.get(i) + " "); - } - - } - - -} diff --git a/src/com/imood/msjava/offer/MoreThanHalfNum_Solution.java b/src/com/imood/msjava/offer/MoreThanHalfNum_Solution.java deleted file mode 100644 index 34780cc..0000000 --- a/src/com/imood/msjava/offer/MoreThanHalfNum_Solution.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.imood.msjava.offer; - -import java.util.*; - - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/6/26/0026 - * @version: 1.0 - */ -public class MoreThanHalfNum_Solution { - - - /** - * 题目描述: - * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 - * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 - * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 - * - * @param array - * @return - */ - public int moreThanHalfNum_Solution(int[] array) { - int len = array.length; - if (array == null || array.length == 0) { - return 0; - } - //先将数组排序,思路就是出现次数最多的数一定在中间。 - Arrays.sort(array); - - int mid = array[len / 2]; - - int count = 0; //记录出现次数 - for (int i = 0; i < len; i++) { - if (array[i] == mid) //因为分析的中间数肯定是出现次数最多的,所以直接统计次数就好了 - count++; - } - if (count > len / 2) { - return mid; - } - return 0; - - } - - public static void main(String[] args) { - int[] array = {1, 2, 2, 2, 2, 2, 7, 8, 9}; - int i = new MoreThanHalfNum_Solution().moreThanHalfNum_Solution(array); - System.out.println(i); - } -} diff --git a/src/com/imood/msjava/sort/Sort.java b/src/com/imood/msjava/sort/Sort.java deleted file mode 100644 index dba5548..0000000 --- a/src/com/imood/msjava/sort/Sort.java +++ /dev/null @@ -1,238 +0,0 @@ -package com.imood.msjava.sort; - - -/** - * @description: 常見排序算法 - * @author: 微信公众号:码上Java - * @createDate: 2020/6/21/0021 - * @version: 1.0 - */ -public class Sort { - - /** - * 冒泡排序算法 时间复杂度 N2 空间复杂度 1 稳定 - * - * @param array - * @return - */ - public static void bubbleSort(int[] array) { - //外循环控制循环比较次数 - for (int i = 1; i < array.length; i++) { - //内循环控制比较元素,针对待排序元素 - for (int j = 0; j < array.length - i; j++) { - if (array[j] > array[j + 1]) { - //元素交换位置 - int temp = array[j]; - array[j] = array[j + 1]; - array[j + 1] = temp; - } - } - } - } - - /** - * 冒泡排序算法优化 时间复杂度 N2 空间复杂度 1 稳定 - * 在第一层循环内加一个判断标识,每次赋值为 true, - * 假如在第二层循环(内层循环)时执行了位置交换,也就是 if 中的代码之后, - * 我们把此值设置成 false;如果执行完内层循环判断之后,变量依然为 true, - * 这就说明没有可以移动的元素了,冒泡排序可以结束执行了 - * - * @param array - */ - public static void bubbleSortPLus(int[] array) { - //外循环控制循环比较次数 - for (int i = 1; i < array.length; i++) { - - boolean flag = true; - //内循环控制比较元素,针对待排序元素 - for (int j = 0; j < array.length - i; j++) { - if (array[j] > array[j + 1]) { - //元素交换位置 - int temp = array[j]; - array[j] = array[j + 1]; - array[j + 1] = temp; - flag = false; - } - if (flag) { - break; - } - } - } - } - - - /** - * 插入排序算法 时间复杂度 N ~ N2 (时间复杂度与初始排序状态有关) 空间复杂度 1 稳定 - * - * @param array - * @return - */ - public static int[] insertSort(int[] array) { - for (int i = 1; i < array.length; i++) { - //插入的元素 - int inserVal = array[i]; - //被插入的位置(准备和前一个数进行比较) - int index = i - 1; - //如果插入的元素比被插入的数小 - while (index >= 0 && inserVal < array[index]) { - //则将array[index]向后移动 - array[index + 1] = array[index]; - //将index向后移动 - index--; - } - //将插入的元素放入合适的位置 - array[index + 1] = inserVal; - } - return array; - } - - - /** - * 选择排序算法 时间复杂度 N2 空间复杂度 1 不稳定 - * - * @param array - * @return - */ - public static int[] selectSort(int[] array) { - for (int i = 0; i < array.length; i++) { - //记录最小元素 - int min = array[i]; - //记录最小元素位置 - int minIndex = i; - //在未排序数组中找到最小元素和对应位置 - for (int j = i + 1; j < array.length; j++) { - if (array[j] < min) { - min = array[j]; - minIndex = j; - } - } - //元素交换位置 - int temp = array[i]; - array[i] = array[minIndex]; - array[minIndex] = temp; - } - return array; - } - - /** - * 希尔排序 时间复杂度 N 的若干倍乘于递增序列的长度 , 空间复杂度 1 不稳定 - * -----改进版插入排序 - * - * @param array - * @return - */ - public static int[] shellSort(int[] array) { - return array; - } - - - /** - * 快速排序算法 时间复杂度 NlogN 空间复杂度 logN 不稳定 - * - * @param array - * @param low - * @param high - * @return - */ - public static int[] quickSort(int[] array, int low, int high) { - if (low < high) { - int index = partition(array, low, high); - quickSort(array, 0, index - 1); - quickSort(array, index + 1, high); - } - return array; - } - - //快速排序分区操作 - private static int partition(int[] array, int low, int high) { - //1.找一个基准值 - int pivot = array[low]; - //2.当low 小于 high 重复操作 - while (low < high) { - while (low < high && array[high] >= pivot) { - high--; - } - array[low] = array[high]; - //从low开始,如果low小于pivot, low++ ,否则 low 的值直接赋值给 high - while ((low < high) && array[low] <= pivot) { - low++; - } - array[high] = array[low]; - } - //3.最后基准值 - array[low] = pivot; - //4.返回基准值位置 - return low; - } - - /** - * 二分查找算法 - 前提数组升序 ,如果是降序 就把向右查找的条件换成 target array[mid]) { //向右查找 - low = mid + 1; - } else { //向左查找 - high = mid - 1; - } - } - return -1; - } - - - /** - * 归并排序 时间复杂度NlogN 空间复杂度N 稳定 - * - * @param array - * @return - */ - public static int[] mergeSort(int[] array) { - sort(array, 0, array.length - 1); - return array; - } - - - /** - * 对左右两边的数据进行递归 - * - * @param array - * @param left - * @param right - */ - private static void sort(int[] array, int left, int right) { - if (left < right) { - return; - } - //中间索引 - int center = (left + right) / 2; - //对左边的数组递归排序 - sort(array, left, center); - //对右边的数组递归排序 - sort(array, center + 1, right); - //将两边数组进行归并 - merge(array, left, center, right); - } - - private static void merge(int[] array, int left, int center, int right) { - - //todo - } - - public static void main(String[] args) { - int[] array = {9, 8, 7, 6, 5, 4, 3, 2, 1}; - - - } - - -} diff --git a/src/com/imood/msjava/thread/BothRunnableThread.java b/src/com/imood/msjava/thread/BothRunnableThread.java deleted file mode 100644 index 8ffe4b1..0000000 --- a/src/com/imood/msjava/thread/BothRunnableThread.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.imood.msjava.thread; - -/** - * msJava - * - * @Description - * @Date 2020-11-29 - */ -public class BothRunnableThread { - - public static void main(String[] args) { - new Thread(new Runnable() { - @Override - public void run() { - System.out.println("我来自Runnable"); - } - }){ - @Override - public void run() { - System.out.println("我来自Thread"); - } - }.start(); - - /** - * lambda 表达式 创建线程 - */ - new Thread(()-> System.out.println(Thread.currentThread().getName())).start(); - } -} diff --git a/src/com/imood/msjava/thread/CantStartTwice.java b/src/com/imood/msjava/thread/CantStartTwice.java deleted file mode 100644 index e7bd3d6..0000000 --- a/src/com/imood/msjava/thread/CantStartTwice.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.imood.msjava.thread; - -/** - * msJava - * - * @Description 不能两次调用start方法 否则会抛出异常 - * java.lang.IllegalThreadStateException - * @Date 2020-11-30 - */ -public class CantStartTwice { - - - public static void main(String[] args) { - Thread thread = new Thread(); - thread.start(); - thread.start(); - } - - - - -} diff --git a/src/com/imood/msjava/thread/DemoTimerTask.java b/src/com/imood/msjava/thread/DemoTimerTask.java deleted file mode 100644 index 0d4e200..0000000 --- a/src/com/imood/msjava/thread/DemoTimerTask.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.imood.msjava.thread; - -import java.util.Timer; -import java.util.TimerTask; - -/** - * msJava - * - * @Description 定时器 创建 线程 - * @Date 2020-11-29 - */ -public class DemoTimerTask { - - public static void main(String[] args) { - Timer timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - System.out.println(Thread.currentThread().getName()); - } - },1000,1000); - } - -} diff --git a/src/com/imood/msjava/thread/RunnableStyle.java b/src/com/imood/msjava/thread/RunnableStyle.java deleted file mode 100644 index 0fcd235..0000000 --- a/src/com/imood/msjava/thread/RunnableStyle.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.imood.msjava.thread; - -/** - * msJava - * - * @Description - * @Date 2020-11-29 - */ -public class RunnableStyle implements Runnable{ - @Override - public void run() { - System.out.println("RunnableStyle ····"); - } - - public static void main(String[] args) { - Thread thread = new Thread(new RunnableStyle()); - thread.start(); - } -} diff --git a/src/com/imood/msjava/thread/ThreadStyle.java b/src/com/imood/msjava/thread/ThreadStyle.java deleted file mode 100644 index 3019552..0000000 --- a/src/com/imood/msjava/thread/ThreadStyle.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.imood.msjava.thread; - - -/** - * msJava - * - * @Description - * @Date 2020-11-29 - */ -public class ThreadStyle extends Thread { - - @Override - public void run() { - System.out.println("ThreadStyle ····"); - } - - public static void main(String[] args) { - new ThreadStyle().start(); - } -} diff --git "a/src/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/MyQueue.java" "b/src/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/MyQueue.java" deleted file mode 100644 index 863e764..0000000 --- "a/src/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/MyQueue.java" +++ /dev/null @@ -1,49 +0,0 @@ -package com.imood.msjava.数据结构; - -import java.util.Stack; - -/** - * @description: 用栈实现队列 - * @author: 微信公众号:码上Java - * @createDate: 2020/7/29/0029 - */ -class MyQueue { - - - /** - * 栈的顺序为后进先出,而队列的顺序为先进先出。 - * 使用两个栈实现队列,一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转, - * 经过第二个栈时再次被反转,此时就是先进先出顺序。 - */ - private Stack in = new Stack<>(); - private Stack out = new Stack<>(); - - - public void push(int x) { - - in.push(x); - } - - public int pop() { - in2out(); - return out.pop(); - } - - public int peek() { - in2out(); - return out.peek(); - } - - private void in2out() { - if (out.isEmpty()) { - while (!in.isEmpty()) { - out.push(in.pop()); - } - } - } - - public boolean empty() { - return in.isEmpty() && out.isEmpty(); - } -} - diff --git "a/src/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/Stack.java" "b/src/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/Stack.java" deleted file mode 100644 index fc47ea7..0000000 --- "a/src/com/imood/msjava/\346\225\260\346\215\256\347\273\223\346\236\204/Stack.java" +++ /dev/null @@ -1,71 +0,0 @@ -package com.imood.msjava.数据结构; - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/7/18/0018 - */ -public class Stack { - - private Object[] data = null; - private int maxSize = 0; //栈容量 - private int top = -1; //栈顶指针 - - // 初始化构造方法 - Stack(int initialSize) { - if (initialSize >= 0) { - this.maxSize = initialSize; - data = new Object[initialSize]; - top = -1; - } else { - throw new RuntimeException("初始化大小不能小于0: " + initialSize); - } - } - - // 初始化构造方法 默认栈容量为10 - Stack() { - this(10); - } - - //入栈操作 - - public boolean push(E e) { - //首先判断一下栈是否已经满了 - if (top == maxSize - 1) { - //todo 扩容操作 - throw new RuntimeException("栈已满,元素无法入栈"); - } else { - data[top] = e; - top++; - return true; - } - } - - //出栈操作 - public E pop() { - //首先查看一下栈是否为空 - if (top == -1) { - throw new RuntimeException("栈为空 "); - } else { - //将栈顶元素返回后维护一下栈顶指针 - return (E) data[top--]; - } - } - - //查看栈顶元素 - public E peek() { - if (top == -1) { - throw new RuntimeException("栈为空 "); - } else { - // 查看栈顶元素并不移除所以说不需要维护栈顶指针 - return (E) data[top]; - } - } - - - public boolean isEmpty() { - return maxSize == 0; - } - - -} diff --git "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\346\207\222\346\261\211\346\250\241\345\274\217.java" "b/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\346\207\222\346\261\211\346\250\241\345\274\217.java" deleted file mode 100644 index 693ac2d..0000000 --- "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\346\207\222\346\261\211\346\250\241\345\274\217.java" +++ /dev/null @@ -1,40 +0,0 @@ -package com.imood.msjava.设计模式; - -/** - * @description: 单例模式——懒汉模式也被称作为饱汉模式, - * ——当每次需要使用实例时,再去创建获取实例,而不是在类加载时就将实例创建好。 - * @author: 微信公众号:码上Java - * @createDate: 2020/6/26/0026 - * @version: 1.0 - */ -public class Singleton_懒汉模式 { - - //声明私有对象 - private static Singleton_懒汉模式 instance; - - // 获取实例(单例对象) - public static Singleton_懒汉模式 getInstance() { - - if (instance == null) { - instance = new Singleton_懒汉模式(); - } - return instance; - } - - //私有化构造方法 - private Singleton_懒汉模式() { - - } - - public void sayHi() { - System.out.println("Hi,Java"); - } - - public static void main(String[] args) { - - Singleton_懒汉模式 instance = Singleton_懒汉模式.getInstance(); - instance.sayHi(); - - } - -} diff --git "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\351\245\245\346\261\211\346\250\241\345\274\217.java" "b/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\351\245\245\346\261\211\346\250\241\345\274\217.java" deleted file mode 100644 index b1440ce..0000000 --- "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton_\351\245\245\346\261\211\346\250\241\345\274\217.java" +++ /dev/null @@ -1,36 +0,0 @@ -package com.imood.msjava.设计模式; - -/** - * @description: 单例模式——饥汉模式 - * —— 在类加载时就会进行单例的初始化,以后访问时直接使用单例对象即可。 - * @author: 微信公众号:码上Java - * @createDate: 2020/6/26/0026 - * @version: 1.0 - */ -public class Singleton_饥汉模式 { - - //声明私有对象 - private static Singleton_饥汉模式 instance = new Singleton_饥汉模式(); - - // 获取实例(单例对象) - public static Singleton_饥汉模式 getInstance() { - return instance; - } - - //私有化构造方法 - private Singleton_饥汉模式() { - - } - - public void sayHi() { - System.out.println("Hi,Java"); - } - - public static void main(String[] args) { - - Singleton_饥汉模式 instance = Singleton_饥汉模式.getInstance(); - instance.sayHi(); - - } - -} diff --git "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton\357\274\277\345\217\214\351\207\215\346\243\200\346\265\213\351\224\201.java" "b/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton\357\274\277\345\217\214\351\207\215\346\243\200\346\265\213\351\224\201.java" deleted file mode 100644 index b371c6b..0000000 --- "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/Singleton\357\274\277\345\217\214\351\207\215\346\243\200\346\265\213\351\224\201.java" +++ /dev/null @@ -1,53 +0,0 @@ -package com.imood.msjava.设计模式; - - -/** - * @description: - * @author: 微信公众号:码上Java - * @createDate: 2020/6/26/0026 - * @version: 1.0 - */ -public class Singleton_双重检测锁 { - - /** - * instance = new Singleton() 这行代码。这行代码看似是一个原子操作,然而并不是, - * 这行代码最终会被编译成多条汇编指令,它大致的执行流程为以下三个步骤: - *

- * 1. 给对象实例分配内存空间; - * 2. 调用对象的构造方法、初始化成员字段; - * 3. 将 instance 对象指向分配的内存空间。 - *

- * 但由于 CPU 的优化会对执行指令进行重排序, - * 也就说上面的执行流程的执行顺序有可能是 1-2-3,也有可能是 1-3-2。假如执行的顺序是 1-3-2, - * 那么当 A 线程执行到步骤 3 时,切换至 B 线程了,而此时 B 线程判断 instance 对象已经指向了对应的内存空间, - * 并非为 null 时就会直接进行返回,而此时因为没有执行步骤 2,因此得到的是一个未初始化完成的对象,这样就导致了问题的诞生。 - *

- * 执行时间节点如下表所示: - * 时间点 线程 执行操作 - * t1 A instance = new Singleton() 的 1-3 步骤,待执行步骤 2 - * t2 B if (instance == null) { 判断结果为 false - * t3 B 返回半初始的 instance 对象 - * 为了解决此问题,我们可以使用关键字 volatile 来修饰 instance 对象, - * 这样就可以防止 CPU 指令重排,从而完美地运行懒汉模式, - */ - private static volatile Singleton_双重检测锁 instance; - - public static Singleton_双重检测锁 getInstance() { - //第一次判断 - if (instance == null) { - synchronized (Singleton_双重检测锁.class) { - //第二次判断 - if (instance == null) { - instance = new Singleton_双重检测锁(); - } - } - } - return instance; - } - - private Singleton_双重检测锁() { - - } - - -} diff --git "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/\346\200\273\347\273\223.md" "b/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/\346\200\273\347\273\223.md" deleted file mode 100644 index 9f53c69..0000000 --- "a/src/com/imood/msjava/\350\256\276\350\256\241\346\250\241\345\274\217/\346\200\273\347\273\223.md" +++ /dev/null @@ -1,18 +0,0 @@ -# 单例模式 -> 单例模式是指一个类在运行期间始终只有一个实例,我们把它称之为单例模式。 -> 单例模式的典型应用场景是 Spring 中 Bean 实例,它默认就是 singleton 单例模式。 -> 单例模式的优点很明显,可以有效地节约内存,并提高对象的访问速度, -> 同时避免重复创建和销毁对象所带来的性能消耗,尤其是对频繁创建和销毁对象的业务场景来说优势更明显。 -> 然而单例模式一般不会实现接口,因此它的扩展性不是很好,并且单例模式违背了单一职责原则,因为单例类在一个方法中既创建了类又提供类对象的复合操作,这样就违背了单一职责原则,这也是单例模式的缺点所在。 -## 1. 单例模式——饥汉模式 -+ 优点是线程安全,因为单例对象在类加载的时候就已经被初始化了, -当调用单例对象时只是把早已经创建好的对象赋值给变量; -+ 缺点是可能会造成资源浪费,如果类加载了单例对象(对象被创建了), -但是一直没有使用,这样就造成了资源的浪费。 -## 2. 单例模式——懒汉模式 -+ 优点是不会造成资源的浪费,因为在调用的时候才会创建被实例化对象; -+ 缺点在多线程环境下是非线程是安全的,比如多个线程同时执行到 if 判断处,此时判断结果都是未被初始化, -那么这些线程就会同时创建 n 个实例,这样就会导致意外的情况发生。 -## 1 2 总结 -使用单例模式可以减少系统的内存开销,提高程序的运行效率,但是使用不当的话就会造成多线程下的并发问题。 -饿汉模式为最直接的实现单例模式的方法,但它可能会造成对系统资源的浪费. diff --git a/src/top/msjava/Main.java b/src/top/msjava/Main.java new file mode 100644 index 0000000..e0c5ea4 --- /dev/null +++ b/src/top/msjava/Main.java @@ -0,0 +1,18 @@ +package top.msjava; + +/** + * msJava + * + * @Description + * @Date 2021-12-12 + */ +public class Main { + + + public static void main(String[] args) { + + System.out.println("weixin"); + + + } +}