一面

1.面向对象的三个特征?

答案:

  • 封装:将数据(属性)和操作数据的方法(行为)绑定在一起,并隐藏内部实现细节,只暴露必要的接口。这样可以提高安全性和易用性,降低耦合。
  • 继承:允许一个类(子类)基于另一个类(父类)来定义,从而复用父类的属性和方法。子类可以扩展或重写父类的行为,实现代码重用和层次化设计。
  • 多态:同一个行为(方法)在不同的对象上可以表现出不同的形态。通常通过方法重写(运行时多态)和方法重载(编译时多态)来实现,提升程序的灵活性和可扩展性。

2.接口与抽象类的区别?

答案:

  • 继承关系:抽象类单继承,接口支持多实现。
  • 成员:抽象类可定义成员变量、构造方法;接口变量默认是常量,没有构造方法。
  • 方法:抽象类能有普通方法和抽象方法;接口主要定义行为规范,JDK8 后新增默认、静态方法。
  • 设计思想:抽象类描述是什么,体现类的共性;接口描述能做什么,定义行为能力。、

3.ArrayList 的底层实现?

答案:ArrayList 的底层采用的动态数组,默认大小是10,查找快,增删慢,查找时间复杂度为O(1),在数组末尾增加和删除元素的时间复杂度为O(1),在数组的头部或尾部增加和删除元素的时间复杂度为O(n),并且底层会维护一个负载因子,默认大小为0.75,当存储容量达到数组大小的0.75倍,则会进行动态扩容,底层使用的是Object类中的数组复制方法,扩容大小默认为原来的1.5倍。

4.String StringBuilder的区别?

答案:

  • String 的底层维护的是一个 final 关键修饰的字符数组,String 对象引用存储在栈中,如果 String 对象是通过 new 关键字进行创建,则对象信息存储在堆中,对象中的字符数组又指向常量池中的字符串数据,故而每次修改String对象中的数据时都会重新在常量池中创建字符串数据,进而多次修改时会导致常量池中出现许多无用数据,浪费空间。
  • StringBuilder 的底层维护的是一个字符数组,故而可以修改该字符数组中的内容,不会浪费空间,修改字符串数据的速度也比 String 快,但它是线程不安全的,只允许单个线程操作。

5.线程的sleep方法和wait方法,这两个方法哪个方法会释放锁,哪个方法不会释放锁?

答案:

  • wait():属于 Object 方法,调用后立即释放当前持有的锁,进入等待池,需被 notify/notifyAll 唤醒后再重新竞争锁。
  • sleep():属于 Thread 方法,只是让线程休眠指定时间,全程持有锁不释放,时间结束后继续执行。

6.MySQL 中聚簇索引、非聚簇索引、普通索引的区别?

答案:

  • 聚簇索引(主键索引):数据和索引存放在同一棵 B + 树,叶子节点就是整行数据。一张表只能有一个,默认用主键创建;无主键则选唯一非空列,都没有则 MySQL 自动生成隐藏聚簇索引。查询主键直接拿到整行数据,速度最快。
  • 非聚簇索引(二级索引 / 辅助索引)叶子节点不存整行数据,只存索引列值 + 主键值。一张表可以有多个。查到主键后,再回聚簇索引查完整数据,这个过程叫回表。
  • 普通索引:属于非聚簇索引的一种,是最基础的二级索引,仅加速单列查询,无唯一性约束。除此之外非聚簇索引还包含:唯一索引、联合索引等。

7.什么时候会触发MySQL 的回表?

答案:

  • 触发场景:查询字段不在当前二级索引(普通 / 唯一 / 联合索引)的列中时,会触发回表。 二级索引叶子节点只存索引列 + 主键,拿到主键后,再去聚簇索引查询完整数据。
  • 不会回表:使用覆盖索引,查询字段全部包含在二级索引内,直接从索引取值,无需访问聚簇索引。
  • 特例:查询条件是主键,直接走聚簇索引,永远不回表。

8.解释一下 Redis 的缓存穿透

答案:当 Redis 和 MySQL 中都没有用户需要请求的数据时,用户发送大量该请求,导致请求直接全部都打到 MySQL 数据库中,导致 MySQL 数据库崩溃,这种就是缓存穿透。解决办法如下:

  • 入口校验:参数合法性检查放在最前面,ID 小于 0 直接拒绝,格式不对直接返回。
  • 布隆过滤器:用 Guava 或者 Redis 自带的 RedisBloom 模块,把所有合法 key 预先加载进去。请求来了先问布隆过滤器,说不存在就肯定不存在,直接返回。布隆过滤器可能误判存在,但不会误判不存在。
  • 缓存空值:数据库查了确实没有,也往缓存里写一个空标识,过期时间设短点比如 2-5 分钟,防止同一个不存在的 key 反复穿透。

9.Java 中怎么降低哈希冲突的风险?

答案:对原始 hashCode 做高低位混合扰动,让高位哈希值也参与数组下标计算,减少低位重复导致的冲突。JDK8 中 hash() 方法,通过 h ^ (h >>> 16) 扰动,把高 16 位打散到低 16 位。

10.线程和进程的区别?

答案:

  • 资源所属:进程是资源分配的最小单位;线程是调度执行的最小单位,共享所在进程资源。
  • 开销:创建 / 销毁进程开销大;线程开销更小、切换更快。
  • 独立性:进程间相互独立,一个进程崩溃不影响其他;同一进程内线程共享资源,一个线程异常可能导致整个进程挂掉。
  • 通信:进程间通信复杂;同进程线程可直接共享变量,通信简单。

11.定制化代码生成器共享平台的流程、你主要负责哪些模块、在做这些模块的时候遇到了哪些问题,如何解决的?

答案:我主要负责定制化代码生成中的根据原始项目生成项目模板,再根据模板生成代码生成器。开发者上传原始原始项目、并在前端输入参数,后端根据输入的原始项目和参数生成对应的模板文件,动态文件通过 FreeMark 进行生成、静态文件通过 Hutool 工具类中的递归复制进行生成,开发者根据拿到的模板文件,生成对应的代码生成器,其他开发者可以在前端输入关键字查找自己想要的代码生成器,在前端输入参数,后端会根据输入的参数改变项目中的文件或者代码,以达到零代码实现自己想要的页面效果。我在开发根据需要生成对应的项目模板时,开始采用一次制作流程,由于开发者对原始项目的改动之处可能存在相同点,导致文件修改出现异常,即生成的模板效果不好,后面采用多次制作的方式,并且根据 雪花算法 创建工作空间隔开每个开发者的模板文件,每次制作都去更新其对应空间的模板文件。

12.vue2 和 vue3 的区别?

13.vue2 的生命周期和 vue3 的生命周期有什么区别?

二面

大概就是问未来的发展,对ai的看法,已经写代码全部由ai来代替会出现的问题,薪资待遇之类的