# java后端面经笔记 **Repository Path**: BJERGSEN97/java-notes ## Basic Information - **Project Name**: java后端面经笔记 - **Description**: 根据往上面经整理笔记 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-04-23 - **Last Updated**: 2023-07-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 作者:BJERGSEN(欢迎你的加入) 创建时间:2022/4/23 联系方式:1345600853@qq.com 说明:本文参考知乎、javaguide、尚硅谷、b站视频等资料,侵删。 **维护须知:** 1. 在已完成答案问题前加入序号格式统一为序号顿号形式,在后面的括号中添加上作者缩写。 2. 面经首先加入到面经汇总中,解决后加入文档中,遇到面经中无法解决的问题,加入到对应模块,不要标记序号。 3. 引入外部文档,将文档加入java-notes文件夹中,并将外部文件拖入到文档中。 4. 文件->偏好设置中设置下图 ![image-20220423203511933](README.assets/image-20220423203511933.png) 5. 本文秉持着谁写谁讲原则,放入笔记中的面经问题要尽可能的全面,细致。 6. 如果需要补充其他作者已经写好的问题,请在格式中选择注释加入其中,括号中写入作者,待与另一位作者讨论过后,改变为正文加入到文档中。 比如: 7. 加入大模块尽量按照学习顺序。 8. 本文尽量写入的是面经问题而不是网上总结的知识点(一问一答的形式) 9. 如果文档不显示图片,就把README.assets文件夹打开试试 # java基础 ## 1、java的集合类(BJ) Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 `Collection`接口,主要用于存放单一元素;另一个是 `Map` 接口,主要用于存放键值对。对于`Collection` 接口,下面又有三个主要的子接口:`List`、`Set` 和 `Queue`。 ## 2、ArrayList,LinedList,HashMap介绍、区别、使用场景、底层实现原理?(BJ) [集合篇.pdf](集合篇.pdf) ### 1、ArrayList,LinedList区别? 1. 都线程不安全 2. 数组、链表 3. arr支持快速随机访问 4. 内存占用其实差不多 5. 不要下意识地认为 LinkedList 作为链表就最适合元素增删的场景。我在上面也说了, LinkedList 仅仅在头尾插入或者删除元素的时候时间复杂度近似 O(1),其他情况增删元素的时间复杂 度都是 O(n) 。 ### 2、HashMap底层原理?为什么在链表长度为8转换成红黑树? JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置 (这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。 treeify 过程会把原本的 Node 对象转化为 TreeNode 对象,而 TreeNode 大小是 Node 的两倍;除去内存的损耗,treeify 本身也是一个耗时的过程,并且在红黑树节点数小于等于 UNTREEIFY_THRESHOLD(默认为 6)时,红黑树又会重新转换为链表,如果出现频繁的相互转化,这是一笔不小的开销。 # JVM ## JVM内存模型是什么? # java并发 ## 1、什么是线程和进程?(BJ) 系统运行一个程序即是一个进程从创建,运行到消亡的过程。 线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的**堆**和**方法区**资源,但每个线程有自己的**程序计数器**、**虚拟机栈**和**本地方法栈**,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。 ## 2、进程间的通信方式?(有待补充) 1. 管道模式(linux常用) 2. 消息队列 3. 共享内存+信号模型 4. 信号 5. socket 管道模型:比如cat xx.txt | grep -n 'xxx' 这个'|'可以看作一个单向的匿名管道,使得前后两个进程之间进行通信,前一个命名的输出作为后一个命令的输入,该管道使用结束则立即销毁。命名管道在linux中以文件的形式存在,只要访问该文件就可以实现任意两个进程间的通信,命名管道可以看作是是硬盘上存在的设备文件,所以打开需要使用open。 消息队列模型:比如生产者消费者模式,一端生产一端消费数据。遵循严格的先进先出。进程中并不常用,线程中更常用一些 共享内存:多用于传输一些大文件,如果采用管道或者消息队列传输大文件,涉及到重复拷贝,比较消耗性能,因此模拟多线程,在内存中开辟一块特殊的内存用于多个进程共享访问。也是进程间最高效的通信方式。 信号量机制:信号量可以看作一种数据操作锁,通过对临界资源的控制访问以管理进程之间的通信,PV原语操作。 socket:用于多个进程之间的网络传输。可以是单机多进程也可以是不同机器上的多进程通信。打开的socket在linux下也是以文件描述符fd存在。服务端创建套接字,绑定ip端口,监听端口号,等待客户端调用,客户端创建之后与服务端TCP三次握手建立连接完成,双方就可以发送和接收数据。 # 计算机网络 ## 1、HTTPS的加密方式?(BJ) tls加密 非对称加密➕数字证书➕数字签名➕对称加密 非对称加密 image-20220418170915530 非对称加密+对称加密 服务器将公钥发送给客户端 客户端将要发送的信息使用加密算法进行加密,将加密算法利用服务器的公钥进行加密,将密文和加密后的加密算法发送给服务器 服务器利用私钥解开加密算法,利用对称加密的加密算法解开密文 问题:如果客户端收到的公钥不是服务器端发送的而是伪造的,那么会被黑掉 解决:数字证书和数字签名 数字证书和数字签名,客户端、服务器都信任的组织,对服务端的密钥进行加密,发送给客户端。 CA的公钥是写死在操作系统中的,**CA中包括用户的公钥,用户的信息,证书机构信息,证书有效期,并将上述信息利用ca的公钥加密,生成数字签名。** 用户接收到服务端传来的ca证书后,会根据本地已经存在的ca机构公钥解密得到服务器公钥,还会检查证书所颁发的域名与当前域名是否一致,是否在证书有效期以内。 ![img](README.assets/v2-5c0610bf16a7baf9bae7c6787dd7756a_720w.jpg) image.png img ## 2、TCP/UDP的区别(BJ) ![image-20220423185533204](README.assets/image-20220423185533204.png) ![TCP、UDP协议的区别](README.assets/68747470733a2f2f6d792d626c6f672d746f2d7573652e6f73732d636e2d6265696a696e672e616c6979756e63732e636f6d2f323031392d31312f7463702d76732d7564702e6a7067.jpeg) UDP 在传送数据之前不需要先建立连接,远地主机在收到 UDP 报文后,不需要给出任何确认。虽然 UDP 不提供可靠交付,但在某些情况下 UDP 却是一种最有效的工作方式(一般用于即时通信),比如: QQ 语音、 QQ 视频 、直播等等 TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。 TCP 不提供广播或多播服务。由于 TCP 要提供可靠的,面向连接的传输服务(TCP 的可靠体现在 TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源),这难以避免增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。TCP 一般用于文件传输、发送和接收邮件、远程登录等场景。 ## 3、ddos攻击是啥?(BJ) ddos分布式拒绝服务攻击,利用分布式的大量主机同时请求服务试图耗尽服务器资源导致服务无法为正常用户提供。分为直接型ddos和反射型ddos # 操作系统 # 数据结构与算法 # MySQL ## 1、MySQL索引(BJ) ### 何为索引?有什么作用? **索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树, B+树和 Hash。** 索引的作用就相当于目录的作用。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了 ## 2、B+树?聚簇索引?(BJ) ![image-20220422170738255](README.assets/image-20220422170738255.png) 叶子节点存放的是数据的全部信息时,称之为聚簇索引 与聚簇索引对应的是二级索引(叶子节点的信息只存放表中的某几条数据),查询后想获得全部信息,还要进行回表操作(再到聚簇索引中查一遍)。 ### InnoDB的B+树索引的注意事项 1.根页面位置万年不动 ![image-20220422171321920](README.assets/image-20220422171321920.png) 总结:放进去,多出来的话,把数据复制,原来的页面变为储存目录项记录的页 2.内节点中目录项记录的唯一性 如果说表中的属性有大量的相同值,比如萧亚轩的男朋友都是18岁,但是要保证每一个男朋友都是唯一的(方便查找),就把名字加上(主键) 3.一个页面最少存储2条记录 ## 3、为什么使用B+树,不用其它数据结构?(BJ) 首先由于磁盘io读写非常消耗时间,减少磁盘io的读写次数对索引的使用效率至关重要。加快查找速度的数据结构:树、哈希 **与全表遍历对比** **与hash结构对比,hash算法,相同的输入永远可以得到相同的输出** 1. hash索引仅能满足=、<>、和in查询。如果进行范围查询会退化为o(n) 2. 数据的存储没有顺序 3. 对于联合索引(表中非主键的其他属性)来说,hash值是将联合索引合并后一起计算的,无法对单独一个键或几个索引进行查询 4. 当hash的重复列过多时,效率会降低(hash冲突,遍历链表或红黑树) innodb引入了自适应的hash索引,当某个数据经常被访问的时候,就会将这个数据页地址存放到hash表中,下次再查询的时候,就可与i快速找到页面所在位置。 **与二叉搜索树对比** 会出现一种特殊的情况,树退化成链表,比如根节点之后的val不断增大,一直添加至右子树。 ![image-20220423172733713](README.assets/image-20220423172733713.png) 过于高瘦,而磁盘io读写的次数又与树的高度有关,因此不选择。 **与 AVL树对比**(平衡二叉搜索树) 如果也是二叉的话,高度也会很多,叉数越多高度越小 **与 B-Tree对比** ![image-20220423173120765](README.assets/image-20220423173120765.png) ![image-20220423173954557](README.assets/image-20220423173954557.png) 多路平衡查找树,表中的信息并不是存放在叶子节点,而是跟随主键值移动。 差异: | b+树 | b树 | | :----------------------------------: | :-------------------: | | 孩子数量=关键字数量 | 孩子数量=关键字数量+1 | | 非叶子结点的关键字会存在子节点中 | 不会 | | 非叶子节点仅用于索引 | 即索引又数据 | | 只看叶子节点即可找到所有数据,且排序 | 找不到呀,需要遍历 | 中间节点不存数据的好处: 1. 查询效率稳定 2. 由于非叶子节点只存放索引,不存放数据,因此b+树势必要比b树更矮,因此磁盘io次数(将数据读取到内存中做操作的次数)更少 3. 如果要找>5这种范围查找,b+树只需要遍历叶子节点就好,而b树依然要遍历非叶子节点 **与r树对比** ![image-20220423180252728](README.assets/image-20220423180252728.png) 一些思考题 ![image-20220423175414336](README.assets/image-20220423175414336.png) ![image-20220423175532145](README.assets/image-20220423175532145.png) ![image-20220423175839106](README.assets/image-20220423175839106.png) ![image-20220423180020540](README.assets/image-20220423180020540.png) ![image-20220423180046898](README.assets/image-20220423180046898.png) # redis # MongoDB # Spring大家族 # MyBatis ## 1、什么是 Mybatis?(BJ) 1、Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql 执行性 能,灵活度高。 2、MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数 据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。 3、通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。(从执行 sql 到返回 result 的过程)。 ## 2、#{}和${}的区别是什么?(BJ) 1)#{}是[预编译](https://so.csdn.net/so/search?q=预编译&spm=1001.2101.3001.7020)处理,$ {}是字符串替换。 2)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;mybatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。 3)使用 #{} 可以有效的防止SQL注入,提高系统安全性。 ## 3、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?(BJ) 第 1 种: 通过在查询的 sql 语句中定义字段名的别名,让字段名的别名和实体类 的属性名一致。 第 2 种: 通过来映射字段名和实体类属性名的一一对应的关系。 ## 4、 模糊查询 like 语句该怎么写?(BJ) 第 1 种:在 Java 代码中添加 sql 通配符。 第 2 种:在 sql 语句中拼接通配符,会引起 sql 注入 ## 5、通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, 请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法, 参数不同时,方法能重载吗?(BJ) Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值; 接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法内的 参数,就是传递给 sql 的参数。 Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符 串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个