diff --git "a/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225.md" "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225.md"
index 01f4180..5b82053 100644
--- "a/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225.md"
+++ "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225/\345\246\202\344\275\225\345\207\206\345\244\207\347\256\227\346\263\225.md"
@@ -1,6 +1,6 @@
# 如何准备算法
-作者:[石皮幼鸟](https://juejin.cn/user/3437526047270291)
+作者:石皮幼鸟 [掘金](https://juejin.cn/user/3437526047270291) | [B 站](https://space.bilibili.com/30915729)
这篇文章是专门为计算机相关专业或想走这一行的同学朋友们准备的,主要是为了帮助你们更好地准备算法,提高你们的算法能力,从而更好地应对秋招春招的挑战。
diff --git "a/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/SpringBoot/index.md" "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/SpringBoot/index.md"
new file mode 100644
index 0000000..385bf56
--- /dev/null
+++ "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/SpringBoot/index.md"
@@ -0,0 +1,138 @@
+**本模块适合 `Java后端研发(业务岗、架构岗)`的同学。**
+
+## 讲讲 SpringBoot 的优点
+
+SpringBoot 的优点主要有以下几点:
+
+1. 简化开发:SpringBoot 提供了自动配置、快速启动、依赖管理等功能,简化了开发流程,提高了开发效率。
+2. 零配置:SpringBoot 采用约定大于配置的方式,减少了配置文件,提高了代码的可读性、可维护性、可扩展性。
+3. 内嵌服务器:SpringBoot 内置了 Tomcat、Jetty、Undertow 等服务器,方便部署和运行。
+4. 微服务架构:SpringBoot 支持微服务架构,提供了 RESTful API、消息队列、服务注册、服务发现等功能,适合微服务架构。
+5. 生态系统:SpringBoot 有庞大的生态系统,提供了大量的插件、工具、框架等,方便开发和部署。
+
+## 为什么选择 SpringBoot,不选择 Nodejs?(简历写全栈的同学必定会被问到)
+
+SpringBoot 是一种 Java 框架,主要用于开发企业级应用,支持事务管理、安全认证、数据访问等,适合大型项目。
+
+Nodejs 是一种 JavaScript 框架,主要用于开发 Web 应用,支持异步 IO、事件驱动、非阻塞 IO 等,适合小型项目。
+
+选择 SpringBoot 的主要原因有以下几点:
+
+1. Java 生态系统:SpringBoot 是基于 Java 生态系统,有庞大的生态系统,提供了大量的插件、工具、框架等,方便开发和部署。
+2. 企业级应用:SpringBoot 支持事务管理、安全认证、数据访问等,适合开发大型项目,提高代码的可读性、可维护性、可扩展性。
+3. 性能稳定:SpringBoot 是基于 Java 虚拟机,性能稳定,适合高并发场景,提高系统的性能和可靠性。
+
+因此,根据不同的需求选择合适的框架,SpringBoot 适合开发大型项目,Nodejs 适合开发小型项目。
+
+## 讲讲 SpringBoot 的自动装配原理
+
+SpringBoot 的自动装配原理主要有以下几个步骤:
+
+1. SpringBoot 启动时,会扫描所有的类路径,查找`@SpringBootApplication`注解。
+2. SpringBoot 会根据`@SpringBootApplication`注解的配置,自动装配`@Configuration`、`@ComponentScan`、`@EnableAutoConfiguration`等注解。
+3. SpringBoot 会根据`@EnableAutoConfiguration`注解的配置,自动装配`spring-boot-autoconfigure`模块中的配置类。
+4. SpringBoot 会根据`spring.factories`文件中的配置,自动装配`spring-boot-starter`模块中的依赖。
+
+SpringBoot 的自动装配原理是为了简化开发流程,提高开发效率,减少配置文件,提高代码的可读性、可维护性、可扩展性。
+
+## 什么叫 AOP,SpringBoot 底层如何实现的 AOP?
+
+AOP(Aspect-Oriented Programming)是一种面向切面编程的方法,亦是代理模式的直接实现。
+
+AOP 提供另一个角度来考虑程序的结构,主要是为了解耦业务逻辑和横切关注点,提高代码的可读性、可维护性、可扩展性。
+
+使用 AOP 的好处包括:
+
+1. 代码重用:将横切关注点抽象成切面,提高代码的可重用性。
+2. 代码解耦:将业务逻辑和横切关注点解耦,提高代码的可维护性。
+3. 代码扩展:将横切关注点动态织入业务逻辑,提高代码的可扩展性。
+
+AOP 主要包含如下几个概念:
+
+1. 切面(Aspect):横切关注点,包括通知、切点、连接点等。
+2. 通知(Advice):在连接点上执行的动作,包括前置通知、后置通知、环绕通知、异常通知、最终通知等。
+3. 切点(Pointcut):连接点的集合,用于匹配连接点。
+4. 连接点(Joinpoint):程序执行的某个特定点,如方法调用、方法返回、方法异常等。
+5. 织入(Weaving):将切面应用到目标对象的过程,包括编译时织入、类加载时织入、运行时织入等。
+6. 代理(Proxy):代理对象,用于控制对目标对象的访问,包括静态代理、动态代理、CGLIB 代理等。
+7. 目标对象(Target):被代理的对象,包括业务逻辑、数据访问等。
+
+实现 AOP 主要包含 JDK 动态代理和 CGLIB 动态代理两种方式:
+
+1. JDK 动态代理:基于接口的代理,通过`java.lang.reflect.Proxy`类实现,要求目标对象必须实现接口。
+2. CGLIB 动态代理:基于类的代理,通过`net.sf.cglib.proxy.Enhancer`类实现,不要求目标对象必须实现接口。
+
+其原理很简单,调用`Method.invoke()`方法时,会先调用`MethodInterceptor.intercept()`方法,最后将参数传递给目标对象。
+
+## 什么是 IOC 和 DI?
+
+IOC(Inversion of Control)是一种控制反转的思想,主要是将对象的创建和管理交给容器,提高代码的可读性、可维护性、可扩展性。
+
+DI(Dependency Injection)是一种依赖注入的方式,主要是将对象的依赖关系交给容器,提高代码的可读性、可维护性、可扩展性。
+
+SpringBoot 的 IOC 和 DI 主要有以下几个概念:
+
+1. Bean:SpringBoot 的核心对象,由容器管理,包括配置类、组件类、代理类等。
+2. Configuration:SpringBoot 的配置类,用于配置 Bean 的创建和管理,包括`@Configuration`、`@ComponentScan`、`@EnableAutoConfiguration`等。
+3. Component:SpringBoot 的组件类,用于定义 Bean 的依赖关系,包括`@Component`、`@Service`、`@Repository`、`@Controller`等。
+4. Autowired:SpringBoot 的依赖注入,用于注入 Bean 的依赖关系,包括`@Autowired`、`@Qualifier`、`@Resource`、`@Inject`等。
+5. BeanFactory:SpringBoot 的容器类,用于管理 Bean 的创建和管理,包括`BeanFactory`、`ApplicationContext`、`AnnotationConfigApplicationContext`等。
+
+SpringBoot 的 IOC 和 DI 主要是为了解耦对象的创建和使用,提高代码的可读性、可维护性、可扩展性,根据不同的需求选择合适的配置类、组件类、代理类等。
+
+## 讲讲 SpringBoot 的启动流程
+
+SpringBoot 的启动流程主要有以下几个步骤:
+
+1. 加载配置:SpringBoot 会加载`application.properties`、`application.yml`等配置文件,读取配置信息,初始化配置类。
+2. 扫描注解:SpringBoot 会扫描`@SpringBootApplication`、`@Configuration`、`@ComponentScan`、`@EnableAutoConfiguration`等注解,初始化配置类。
+3. 自动装配:SpringBoot 会根据`@EnableAutoConfiguration`注解的配置,自动装配`spring-boot-autoconfigure`模块中的配置类,初始化 Bean 对象。
+4. 启动容器:SpringBoot 会启动`Tomcat`、`Jetty`、`Undertow`等服务器,监听端口,接收请求,处理响应。
+5. 处理请求:SpringBoot 会根据`@Controller`、`@RestController`、`@RequestMapping`等注解,处理请求,返回响应。
+
+SpringBoot 的启动流程是为了简化开发流程,提高开发效率,减少配置文件,提高代码的可读性、可维护性、可扩展性。
+
+## 什么是 Starter?
+
+Starter 是 SpringBoot 的一个插件,本质是对依赖的集合,主要是为了简化依赖管理,提高代码的可读性、可维护性、可扩展性。
+
+Starter 主要包含如下几个概念:
+
+1. Starter:SpringBoot 的插件,用于管理依赖关系,提供一组依赖的集合,方便开发和部署。
+2. Autoconfigure:SpringBoot 的自动配置,用于自动装配依赖关系,提供一组配置的集合,方便开发和部署。
+3. Starter Parent:SpringBoot 的父项目,用于管理依赖关系,提供一组依赖的集合,方便开发和部署。
+4. Starter Test:SpringBoot 的测试插件,用于测试依赖关系,提供一组测试的集合,方便开发和部署。
+
+Starter 是为了简化依赖管理,提高代码的可读性、可维护性、可扩展性,根据不同的需求选择合适的 Starter。
+
+值得注意的是,如果是官方的 Starter,一般是以`spring-boot-starter-`开头,如`spring-boot-starter-web`、`spring-boot-starter-data-jpa`等,如果是三方的 Starter,一般是以`xxx-spring-boot-starter`开头,如`mybatis-spring-boot-starter`、`dubbo-spring-boot-starter`等。
+
+## SpringBoot 在注入时如何解决循环依赖?(不常考,但如果说自己读过源码,必问)
+
+循环依赖是一个非常棘手的问题,SpringBoot 是通过三级缓存解决的,具体来说,有如下三级缓存:
+
+1. singletonObjects:存放完全实例化好的 Bean,可以直接使用。类型是`ConcurrentHashMap`。
+2. earlySingletonObjects:存放早期暴露出来的 Bean,还没有完成属性注入和初始化的 Bean,但是可以提前暴露出来给其他 Bean 使用。类型是`ConcurrentHashMap`。
+3. singletonFactories:存放未完成属性注入和初始化的 Bean 的工厂,用于解决循环依赖问题。类型是`ConcurrentHashMap>`。
+
+在注册和依赖注入过程中,SpringBoot 首先会调用构造函数创建 Bean 的实例。创建完之后,会先将 Bean 的名称作为 Key,一个获得提前暴露的半成品 Bean 的工厂方法作为 value 放入三级框架中。注册完成后,进入属性注入阶段。
+
+正常情况下,属性注入会先从一级缓存中获取 Bean,如果没有,再从二级缓存中获取 Bean,如果还没有,一般就出现了循环依赖问题,直接从三级缓存中获取工厂方法,得到半成品,移入二级缓存,删除三级缓存当中对应的方法,再进行属性注入。这个过程中,如果对象允许被创建代理,那么放入二级缓存的是代理对象。
+
+完成注入后,再将 Bean 移入一级缓存,删除二级和三级缓存中对应的内容,这就是总体的注册和依赖注入过程。
+
+## SpringBoot 底层是如何解决基于里氏替换原则实现类型注入的?(不常考,但如果说自己读过源码,必问)
+
+先说说里氏替换原则,里氏替换原则是面向对象设计的一个重要原则,主要是为了保证子类可以替换父类,提高代码的可读性、可维护性、可扩展性。
+
+简单可以理解为,如果 A 是 B 的子类,那么在任何使用 B 的地方,都可以替换成 A,而不影响程序的正确性,即大装小,如:`List list = new ArrayList();`。
+
+既然要实现基于里氏替换原则的类型注入,就意味着,我们必须从 Bean 对应类型的实现链和继承链中找到对应的类型,然后再进行注入。
+
+但这样会导致每次类型注入都要遍历整个所有 Bean 的实现链和继承链,如果有 m 个字段,n 个 Bean,那么复杂度就是 O(mn),这种设计是不可取的。
+
+SpringBoot 为了定位 Bean 对应的类型的父类和接口,维护了`allBeanNamesByType`和`singletonBeanNamesByType`两个 Map,类型是`ConcurrentHashMap`,key 是 Bean 的类型,包括接口和父类,value 是 Bean 的名称数组。在 Bean 刚刚实例化的时候,会将 Bean 的类型和名称,以及整个继承链和实现链上的类型和名称都放入这两个 Map 中。
+
+在依赖注入阶段,如果三级缓存都拿不到对应的 Bean,就意味着这个注入是基于类型的,那么就会从这两个 Map 中找到对应的 Bean 名称数组,然后又从一级缓存中找到对应的 Bean,进行注入。
+
+这样就实现了基于里氏替换原则的类型注入,时间复杂度从 O(mn) 降低到了近乎 O(1)(因为哈希表会出现哈希冲突导致在链表或红黑树上查找,所以不是完全的 O(1))。
\ No newline at end of file
diff --git "a/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/index.md" "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/index.md"
new file mode 100644
index 0000000..ae68770
--- /dev/null
+++ "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/index.md"
@@ -0,0 +1 @@
+**本模块适合 `Java后端研发(业务岗、架构岗)`、`Java安卓原生研发`等 Java 相关岗位的同学。**
\ No newline at end of file
diff --git "a/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/jvm/index.md" "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/jvm/index.md"
new file mode 100644
index 0000000..ed44181
--- /dev/null
+++ "b/\345\255\246\344\271\240\347\233\270\345\205\263/\345\260\261\344\270\232/\350\256\241\347\256\227\346\234\272\345\270\270\350\200\203\345\205\253\350\202\241\346\226\207\346\200\273\347\273\223/Java\345\237\272\347\241\200/jvm/index.md"
@@ -0,0 +1,153 @@
+**本模块适合 `Java后端研发(业务岗、架构岗)`、`Java安卓原生研发`等 Java 相关岗位的同学。**
+
+## 讲讲 jvm 的内存结构,细分到 JDK 7 和 JDK 8 的区别
+
+Java 虚拟机(JVM)的内存结构主要分为以下几个区域:
+
+1. 程序计数器(Program Counter Register):线程私有,用来存储当前线程执行的字节码指令地址。
+2. Java 虚拟机栈(Java Virtual Machine Stacks):线程私有,每个线程都有一个栈,用来存储方法的局部变量、操作数栈、动态链接、方法出口等信息。
+3. 本地方法栈(Native Method Stack):线程私有,用来存储本地方法的信息。
+4. Java 堆(Java Heap):所有线程共享,用来存储对象实例。
+5. 方法区(Method Area):所有线程共享,用来存储类的结构信息、常量、静态变量等。
+6. 运行时常量池(Runtime Constant Pool):方法区的一部分,用来存储编译期生成的字面量和符号引用。
+7. 直接内存(Direct Memory):不是虚拟机运行时数据区的一部分,但是也会被频繁使用,主要是 NIO 中使用的堆外内存。
+
+JDK 7 和 JDK 8 的内存结构区别主要在于永久代的移除和元空间的引入。
+
+- JDK 7 中,方法区是永久代(Perm)的实现,存储类的结构信息、常量、静态变量等。永久代的大小是有限的,当类的数量增多时,会导致永久代内存溢出。永久代的垃圾回收主要是通过`Full GC`来进行,效率较低。
+- JDK 8 中,永久代被移除,取而代之的是元空间(Metaspace),元空间是使用本地内存来存储一些元数据(常量池和静态变量则被移动至 Java 堆中)。元空间的大小是受限于本地内存,当类的数量增多时,会导致本地内存溢出。元空间的垃圾回收主要是通过`Full GC`来进行,效率较高。
+
+JDK 8 中的元空间相比于 JDK 7 中的永久代有以下几个优点:
+
+1. 元空间使用本地内存,不受永久代大小的限制,可以动态调整。
+2. 元空间的垃圾回收效率高,不会出现永久代内存溢出的情况。
+3. 元空间的内存分配和回收更加灵活,可以避免内存泄漏。
+
+## 讲讲 JVM 的垃圾回收时的可达性检测算法
+
+Java 虚拟机的垃圾回收可达性分析算法主要采用的是根搜索算法。
+
+根搜索算法是通过一系列的`GC Roots`对象作为起始点,从这些节点开始向下搜索,搜索过程中所走过的路径称为引用链,当一个对象到`GC Roots`没有任何引用链相连时,则证明此对象是不可达的,即为垃圾对象。
+
+`GC Roots`对象包括以下几种:
+
+1. 虚拟机栈中引用的对象。
+2. 本地方法栈中引用的对象。
+3. 方法区中静态属性引用的对象。
+4. 方法区中常量引用的对象。
+
+根搜索算法的优点是不需要暂停用户线程,可以并发执行,不会影响用户线程的执行。
+
+可达性检测算法还包含了引用计数算法,但是引用计数算法无法解决循环引用的问题,会导致内存泄漏。
+
+## 讲讲 JVM 的垃圾回收算法
+
+先说说常见的垃圾回收算法:
+
+1. 标记 - 清除算法(Mark-Sweep):标记 - 清除算法是一种基础的垃圾回收算法,分为标记和清除两个阶段。首先标记所有存活对象,然后清除所有未标记的对象。标记 - 清除算法优点是实现简便,不需要移动对象,但由于算法过程中需要暂停应用,且会产生内存碎片,导致如果需要分配大对象时,可能会因为内存碎片不足而提前触发垃圾回收。
+2. 复制算法(Copying):复制算法是一种高效的垃圾回收算法,将内存空间划分为两块,每次只使用其中一块,当这一块内存用完时,将存活对象复制到另一块内存中,然后清除当前内存。复制算法优点是实现简单,不会产生内存碎片,但缺点是需要额外的内存空间。
+3. 标记 - 整理算法(Mark-Compact):标记 - 整理算法是一种高效的垃圾回收算法,结合了标记 - 清除算法和复制算法的优点,标记存活对象,然后将存活对象向一端移动,清除另一端的内存。标记 - 整理算法优点是不会产生内存碎片,但缺点是需要移动对象,可能会影响性能。
+4. 分代收集算法(Generational):分代收集算法是一种高效的垃圾回收算法,根据对象的存活周期将内存划分为不同的代,一般分为新生代和老年代。新生代使用复制算法,老年代使用标记 - 整理算法。分代算法优点是根据对象的存活周期选择合适的算法,提高了垃圾回收效率。
+
+Java 虚拟机的垃圾回收算法主要采用的是分代收集算法。
+
+在新生代中,分为 Eden 区、Survivor 区的 From 区和 Survivor 区的 To 区,比例为 8:1:1,使用复制算法。首先将 Eden 区存活的对象复制到 From 区,然后将 Eden 清空。当 From 区满时,将存活的对象复制到 To 区,清空 Eden 和 From 区,然后将 From 区和 To 区交换。循环往复直到 To 区放不下存活的对象。新生代发生的 GC 称为 Minor GC。
+
+在老年代中,使用标记 - 整理算法,标记存活对象,然后将存活对象向一端移动,清除另一端的内存。老年代发生的 GC 称为 Major GC 或 Full GC。Major GC 的触发会连带触发 Minor GC。
+
+## 讲讲 JVM 的垃圾回收器(不常考)
+
+Java 虚拟机的垃圾回收器主要分为以下几种:
+
+1. 串行垃圾回收器(Serial GC):串行垃圾回收器是一种单线程的垃圾回收器,使用复制算法,适用于单核 CPU 的环境。串行垃圾回收器在新生代使用复制算法,在老年代使用标记 - 整理算法。
+2. 并行垃圾回收器(Parallel GC):并行垃圾回收器是一种多线程的垃圾回收器,使用复制算法,适用于多核 CPU 的环境。并行垃圾回收器在新生代使用复制算法,在老年代使用标记 - 整理算法。
+3. CMS 垃圾回收器(Concurrent Mark-Sweep GC):CMS 垃圾回收器是一种并发的垃圾回收器,使用标记 - 清除算法,适用于对响应时间有要求的场景。CMS 垃圾回收器在新生代使用复制算法,在老年代使用标记 - 清除算法。
+4. G1 垃圾回收器(Garbage-First GC):G1 垃圾回收器是一种面向服务端的垃圾回收器,使用分代收集算法,适用于大内存、多核 CPU 的环境。G1 垃圾回收器将堆内存划分为多个区域,每个区域独立进行垃圾回收,可以控制垃圾回收的时间和内存占用。
+
+不同的垃圾回收器适用于不同的场景,可以根据应用的特点和需求选择合适的垃圾回收器。
+
+## 讲讲常见的引用类型(不常考)
+
+Java 中的引用类型主要分为以下几种:
+
+1. 强引用(Strong Reference):强引用是最常见的引用类型,只要存在强引用,垃圾回收器就不会回收对象。例如:
+
+```java
+Object obj = new Object();
+```
+
+2. 软引用(Soft Reference):软引用是一种相对弱化的引用类型,只有在内存不足时,垃圾回收器才会回收对象。例如:
+
+```java
+SoftReference