自我介绍
手撕算法(反转字符串)
介绍项目
讲一下项目中遇到的困难
了解Spring框架吗
熟悉Linux吗,Linux中如何查询ip,Linux中的常见命令
cookie和session作用和区别
长连接和短链接
输入url后的过程
说一说你知道的Java中的集合(答的HashMap和CocurrentHashMap)
HashMap的底层,它和Hashtable有什么区别
String是Java的基本数据类型吗,它和StringBuffer、StringBuilder的区别
看一个捕获异常的代码段,问你执行顺序
‘==’ 是比较的是数值还是地址
了解JVM吗
主键索引和非主键索引
主键索引和非主键索引叶子节点存的是什么
只要创建了索引,就一定会走索引吗
什么时候索引会失效
了解Redis吗
反问环节
1. Linux中查询ip
在terminal输入命令
ifconfig
或 ip addr
或 ip address
或 ip addr show
或 ip address show
ifconfig命令:在终端输入ifconfig命令,它会显示当前系统中所有网络接口的配置信息,包括IP地址、子网掩码和网关等。
ip命令:在终端输入ip addr命令,它会列出当前系统中所有网络接口的详细信息,包括IP地址、子网掩码和网关等。
https://blog.csdn.net/linux_tcpdump/article/details/131361721
Linux中常见命令: https://blog.csdn.net/weixin_38320674/article/details/130002737
2. cookie和session作用和区别
cookie:
是一段保存在客户端的小文本;能够用来将用户活动过程中的状态信息保存到客户端,服务器可以获得该信息以便进行处理,跟踪到用户的状态.
session:
Session是存储在服务器(应用服务器)上的对象,该对象由服务器创建并维护
服务器为客户端与服务器的每一次会话过程都创建并维护一个Session对象
区别
1.存储位置: Session 是存储在服务器端的,Cookie 是存储在客户端的。
2.安全性: Session 比 Cookie 安全
存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
3. 有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
4. 存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
3. 长连接和短连接
长连接: Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收。
- 优点: 可以节省较多的TCP连接和释放的操作,节约时间,对于频繁请求资源的用户来说,适合长连接。
- 缺点: 由于有保活功能,当遇到大量的恶意连接时,服务器的压力会越来越大。这时服务器需要采取一些策略,关闭一些长时间没有进行读写事件的的连接。
短链接: Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点 通讯,比如多个Client连接一个Server。
- 优点: 短连接对服务器来说管理比较简单,只要存在的连接都是有效连接,不需要额外的控制手段,而且不会长时间占用资源 。
- 缺点: 如果客户端请求频繁的话,会在TCP的建立和释放上浪费大量的时间。
4.输入url后的过程
在浏览器中输入 URL 之后,它会执行以下几个流程:
- 执行 DNS 域名解析
- 封装 HTTP 请求数据包
- 封装 TCP 请求数据包
- 建立 TCP 连接
- 参数从客户端传递到服务器端
- 服务器端得到客户端参数之后,进行相应的业务处理,再将结果封装成 HTTP 包,返回给客户端
- 服务器端和客户端的交互完成,断开 TCP 连接
- 浏览器通过自身执行引擎,渲染并展示最终结果给用户
4.1 DNS 域名解析
- 用户输入域名: 用户在浏览器中输入想要访问的域名,例如"www.example.com"。
- 本地域名解析器(Local DNS Resolver): 用户的计算机系统会向本地域名解析器发送域名解析请求。本地域名解析器通常由互联网服务提供商(ISP)或其他网络服务提供商提供。
- 本地域名解析器查询根域名服务器: 如果本地域名解析器不知道目标域名的 IP 地址,它会向根域名服务器发送查询请求。根域名服务器是 DNS 层次结构的最顶层,它负责管理顶级域名(例如.com、.net、.org 等)的信息。
- 根域名服务器引导: 根域名服务器会回复本地域名解析器,指示它前往负责目标顶级域名(例如.com 域)的顶级域名服务器。
- 本地域名解析器查询顶级域名服务器: 本地域名解析器向负责目标顶级域名的顶级域名服务器发送查询请求。
- 顶级域名服务器引导: 顶级域名服务器会回复本地域名解析器,指示它前往负责目标域名的权威域名服务器。
- 本地域名解析器查询权限域名服务器: 本地域名解析器向负责目标域名的权威域名服务器发送查询请求。
- 权限域名服务器回复: 权威域名服务器会回复本地域名解析器,提供目标域名对应的 IP 地址,或者如果域名不存在,则返回相应的错误信息。
- 本地域名解析器缓存: 本地域名解析器会将接收到的 IP 地址存储在缓存中,以便将来的查询可以更快地获得结果。
- 本地域名解析器回复用户: 本地域名解析器将获得的 IP 地址返回给用户的计算机系统。
- 用户访问目标服务器: 用户的计算机系统使用获得的 IP 地址连接到目标服务器,开始与该服务器通信。
4.2 封装 HTTP 请求数据包
一个 HTTP 请求对象包含 :请求行、请求报头、空行、请求正文。
在得到了服务器 IP 之后,紧接着会将本地的请求封装成一个 HTTP 数据包,如下:
4.3 封装 TCP 请求数据包
HTTP 协议基于 TCP/IP 协议实现的,所以在底层数据传输时,会将 HTTP 请求包进一步封装成 TCP 数据包。
4.4 建立 TCP 连接
建立TCP连接也就是我们常说的三次握手,具体步骤如下:
- 客户端发送SYN包给客户端,表明要建立连接
- 服务器端接收客户端的包,并将SYN、ACK置一回发给客户端,表明服务器端收到客户端请求建立连接的包,并请求与客户端建立连接
- 客户端接收服务器端的SYN+ACK包,向服务器发送一个带有 ACK 标志的数据包,表示已经收到了服务器的确认,连接已建立。
4.5 参数从客户端传递到服务器端
数据在经过 TCP 传到到服务器程序之后,又会将 TCP 的数据包转换成 HTTP 数据包(这一切都是 TCP/IP 协议的功劳),这样服务器端就可以得到客户端发送的请求数据了。
4.6 服务器端执行业务处理,并返回数据
服务器端拿到了客户端的请求参数之后,会进行相应的业务处理,处理完成之后,再将处理的结果返回给客户端。返回的流程和发送的流程类似,先将结果封装成 HTTP 数据包,HTTP 数据包可分为:状态行、响应报头、空行、响应正文。它的基本格式如下:
状态行用于描述服务器的返回状态,它由 3 部分组成:
HTTP 版本号,
状态码,
状态描述信息;
常见的状态码有以下几个:
- 200:返回成功;
- 301:永久重定向;
- 302:临时重定向;
- 404:未找到页面;
- 500:服务器程序出错。
响应正文就是返回给客户端的所有数据。
4.7 断开 TCP 连接
与建立连接相似,断开TCP连接又被称为四次挥手,具体步骤如下:
- 客户端发送一个带有 FIN标志的数据包给服务器,表示客户端不再发送数据,请求关闭连接。
- 服务器接收到客户端的 FIN 数据包后,会发送一个带有 ACK标志的数据包给客户端,表示服务器已经收到了客户端的关闭请求。
- 服务器发送一个带有 FIN 标志的数据包给客户端,表示服务器也不再发送数据,同意关闭连接。
- 客户端接收到服务器的 FIN 数据包后,会发送一个带有 ACK 标志的数据包给服务器,表示客户端已经收到了服务器的关闭请求确认。
4.8 浏览器渲染并展示结果
经过 TCP 交互之后,客户端也得到了服务器端返回的数据,然后使用浏览器自身的执行引擎,将最终的结果展示给用户。
5. HashMap
HashMap 底层
-
它基于hash算法,通过put方法和get方法存储和获取对象。
-
存储对象时,我们将K/V传给put方法时,它调用K的hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Facotr则resize为原来的2倍)。
-
获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。
-
如果发生碰撞的时候,HashMap通过链表将产生碰撞冲突的元素组织起来。在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。
HashMap和Hashtable的区别
- Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable的性能高一点。
- Hashtable不允许使用null作为key和value,如果试图把null值放进Hashtable中,将会引发空指针异常,但HashMap可以使用null作为key或value。
6. String、StringBuilder和StringBuffer的区别
- String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。
- StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象
- StringBuffer是线程安全的,而StringBuilder是非线程安全的,所以StringBuilder性能略高。一般情况下,要创建一个内容可变的字符串,建议优先考虑StringBuilder类。
7. 异常处理
在Java中,可以按照如下三个步骤处理异常:
- 捕获异常
将业务代码包裹在try块内部,当业务代码中发生任何异常时,系统都会为此异常创建一个异常对象。创建异常对象之后,JVM会在try块之后寻找可以处理它的catch块,并将异常对象交给这个catch块处理。 - 处理异常
在catch块中处理异常时,应该先记录日志,便于以后追溯这个异常。然后根据异常的类型、结合当前的业务情况,进行相应的处理。比如,给变量赋予一个默认值、直接返回空值、向外抛出一个新的业务异常交给调用者处理,等等。 - 回收资源
如果业务代码打开了某个资源,比如数据库连接、网络连接、磁盘文件等,则需要在这段业务代码执行完毕后关闭这项资源。并且,无论是否发生异常,都要尝试关闭这项资源。将关闭资源的代码写在finally块内,可以满足这种需求,即无论是否发生异常,finally块内的代码总会被执行。
8. == 的作用
- 作用于基本数据类型时,是比较两个数值是否相等;
- 作用于引用数据类型时,是比较两个对象的内存地址是否相同,即判断它们是否为同一个对象
9. JVM
9.1 JVM的组成
JVM 主要由四大部分组成:ClassLoader(类加载器),Runtime Data Area(运行时数据区,内存分区),Execution Engine(执行引擎),Native Interface(本地库接口),下图可以大致描述 JVM 的结构。
9.2 JVM运行过程
JVM的启动过程分为如下四个步骤:
- JVM的装入环境和配置
java.exe负责查找JRE,并且它会按照如下的顺序来选择JRE:
自己目录下的JRE;
父级目录下的JRE;
查注册中注册的JRE。 - 装载JVM
通过第一步找到JVM的路径后,Java.exe通过LoadJavaVM来装入JVM文件。LoadLibrary装载JVM动态连接库,然后把JVM中的到处函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMIntArgs 挂接到InvocationFunction 变量的CreateJavaVM和GetDafaultJavaVMInitArgs 函数指针变量上。JVM的装载工作完成。 - 初始化JVM,获得本地调用接口调用InvocationFunction -> CreateJavaVM,也就是JVM中JNI_CreateJavaVM方法获得JNIEnv结构的实例。
- 运行Java程序
JVM运行Java程序的方式有两种:jar包 与 class。
运行jar 的时候,java.exe调用GetMainClassName函数,该函数先获得JNIEnv实例然后调用JarFileJNIEnv类中getManifest(),从其返回的Manifest对象中取getAttrebutes(“Main-Class”)的值,即jar 包中文件:META-INF/MANIFEST.MF指定的Main-Class的主类名作为运行的主类。之后main函数会调用Java.c中LoadClass方法装载该主类(使用JNIEnv实例的FindClass)。运行Class的时候,main函数直接调用Java.c中的LoadClass方法装载该类。
10. 索引
10.1 主键索引和非主键索引:
- 主键索引和非主键索引是有区别的,主键索引存放的值是整行字段的数据,非主键索引上存放的值不是整行字段的数据,而是存放主键字段的值。其中非主键索引也被称为二级索引,而主键索引也被称为聚簇索引
例如对于下面这个表,ID是主键
主键索引和非主键索引的示意图如下:
10.2 索引失效的情况
-
数据分布不均匀: 如果索引的列中的数据分布不均匀,即某些值出现的频率非常高,而其他值很少出现,那么数据库可能会选择不使用索引,而是执行全表扫描来获取数据。这可能会导致索引失效,因为使用索引的代价太高。
-
索引选择性低: 索引的选择性是指索引列中不同值的数量与总行数的比例。如果选择性很低,即索引列中的许多值是重复的,那么使用索引进行查询可能并不高效,数据库可能会选择不使用索引。
-
表太小: 对于很小的表,使用索引可能不如直接进行全表扫描高效,因为索引的维护和使用本身也需要一些开销。在这种情况下,数据库可能会选择不使用索引。
-
使用函数或表达式: 如果在查询中使用了函数、表达式或类型转换,可能会导致索引失效。数据库可能无法使用索引来加速这些操作,从而选择不使用索引。
-
联合索引顺序问题: 对于联合索引,查询条件的顺序可能会影响索引的使用。如果查询条件不符合联合索引的顺序,索引可能不会被有效使用。
-
更新操作频繁: 当表中的数据频繁地进行插入、更新或删除操作时,索引的维护成本会增加。有时数据库可能会选择不使用索引,以避免影响更新操作的性能。
-
表有大量的NULL值: 索引通常不包含NULL值,因此如果索引列中有大量的NULL值,那么索引可能不会被使用。
-
查询条件不使用索引列: 如果查询的条件不包括索引列,数据库可能无法使用索引来加速查询,从而导致索引失效。
10.3 只要创建了索引,就一定会走索引吗
不一定
比如,在使用组合索引的时候,如果没有遵从“最左前缀”的原则进行搜索,则索引是不起作用的。
举例,假设在id、name、age字段上已经成功建立了一个名为MultiIdx的组合索引。索引行中按id、name、age的顺序存放,索引可以搜索id、(id,name)、(id, name, age)字段组合。如果列不构成索引最左面的前缀,那么MySQL不能使用局部索引,如(age)或者(name,age)组合则不能使用该索引查询。
11. Redis
11.1 Redis可以用来做什么?
- Redis最常用来做缓存,是实现分布式缓存的首先中间件
- Redis可以作为数据库,实现诸如点赞、关注、排行等对性能要求极高的互联网需求
- Redis可以作为计算工具,能用很小的代价,统计诸如PV/UV、用户在线天数等数据
- Redis还有很多其他的使用场景,例如:可以实现分布式锁,可以作为消息队列使用
11.2 Redis和传统的关系型数据库有什么不同?
Redis是一种基于键值对的NoSQL数据库,而键值对的值是由多种数据结构和算法组成的。Redis的数据都存储于内存中,因此它的速度惊人,读写性能可达10万/秒,远超关系型数据库。
关系型数据库是基于二维数据表来存储数据的,它的数据格式更为严谨,并支持关系查询。关系型数据库的数据存储于磁盘上,可以存放海量的数据,但性能远不如Redis。
11.3 Redis有哪些数据类型?
- Redis支持5种核心的数据类型,分别是字符串、哈希、列表、集合、有序集合;
- Redis还提供了Bitmap、HyperLogLog、Geo类型,但这些类型都是基于上述核心数据类型实现的;
- Redis在5.0新增加了Streams数据类型,它是一个功能强大的、支持多播的、可持久化的消息队列。