《揭秘互联网大厂Java面试:从基础到进阶的核心知识大考察》

89 阅读8分钟

在一间明亮却略显严肃的面试房间里,一位求职者正襟危坐在桌前,对面的面试官表情沉稳,一场决定命运的互联网大厂Java面试即将拉开帷幕。

面试官:“第一轮提问开始。先说说Java中ArrayList和HashMap的区别。” 王铁牛:“ArrayList是有序的,按顺序存储元素,基于数组实现;HashMap是无序的,基于哈希表,通过键值对存储。” 面试官:“回答得不错。那HashMap在什么情况下会发生哈希冲突,怎么解决的?” 王铁牛:“呃……数据多了可能就冲突了吧,好像是用链表或者红黑树解决。” 面试官:“还算沾边。ArrayList扩容机制了解吗?” 王铁牛:“初始容量是10,当元素个数达到容量的0.75倍时,就会扩容,新容量是原来的1.5倍。” 面试官:“第一轮表现还行。接下来第二轮。讲讲Spring的IOC和AOP是什么?” 王铁牛:“IOC是控制反转,把对象创建和管理交给Spring容器;AOP是面向切面编程,能在不修改原有代码基础上增加功能。” 面试官:“不错。那Spring Boot自动配置原理能讲讲吗?” 王铁牛:“就是Spring Boot根据依赖自动配置一些组件,具体咋实现不太清楚。” 面试官:“嗯。MyBatis的一级缓存和二级缓存有啥区别?” 王铁牛:“一级缓存是SqlSession级别的,二级缓存是Mapper级别的,二级缓存能跨SqlSession。” 面试官:“第二轮也还可以。最后一轮。Dubbo的服务调用流程是怎样的?” 王铁牛:“好像是服务提供者注册服务,消费者去注册中心找服务,然后调用。” 面试官:“那RabbitMQ的消息确认机制了解吗?” 王铁牛:“有个生产者确认,还有个消费者确认,具体细节不太熟。” 面试官:“xxl - job的调度原理呢?” 王铁牛:“不太清楚,好像是有个调度中心啥的。” 面试官:“Redis的持久化方式有哪些?” 王铁牛:“RDB和AOF,RDB是快照,AOF是记录写操作。” 面试官:“今天的面试就到这里。整体来看,你对一些基础知识点掌握得还可以,但对于一些稍微深入的技术原理,理解得还不够透彻。我们后续会综合评估所有候选人,你回家等通知吧,无论结果如何,我们都会在一周内给你回复。感谢你今天来参加面试。”

问题答案

  1. ArrayList和HashMap的区别
    • 存储结构:ArrayList基于数组,按顺序存储元素,有索引,可通过索引快速访问元素;HashMap基于哈希表,以键值对形式存储,通过哈希算法计算键的哈希值来确定存储位置,无序。
    • 数据特点:ArrayList允许重复元素,HashMap键不能重复,值可以重复。
    • 应用场景:ArrayList适合需要顺序访问、频繁插入删除操作少的场景;HashMap适合根据键快速查找值的场景。
  2. HashMap哈希冲突及解决
    • 哈希冲突原因:不同的键经过哈希算法计算后得到相同的哈希值。比如两个不同的字符串,由于哈希算法的局限性,可能算出一样的哈希值。
    • 解决方法
      • 链地址法:JDK1.8之前主要采用,当发生哈希冲突时,在该哈希值对应的位置用链表存储冲突的元素。JDK1.8之后,当链表长度大于8且数组长度大于64时,链表会转化为红黑树,以提高查找效率。
      • 开放定址法:当发生冲突时,通过某种探测算法在哈希表中寻找下一个空的位置来存储元素。
  3. ArrayList扩容机制
    • 初始容量:默认初始容量为10。
    • 扩容触发条件:当添加元素时,若当前元素个数达到数组容量的0.75倍(即size >= capacity * 0.75),就会触发扩容。
    • 扩容方式:新容量是原来容量的1.5倍(即newCapacity = oldCapacity + (oldCapacity >> 1)),然后将原数组内容复制到新数组。
  4. Spring的IOC和AOP
    • IOC(控制反转)
      • 概念:将对象的创建和管理控制权从应用程序代码转移到Spring容器。比如在传统Java开发中,我们自己创建对象并管理其生命周期;而在Spring中,由Spring容器负责创建、配置和管理对象。
      • 实现方式:通过依赖注入(DI),常见的有构造函数注入、Setter方法注入和接口注入。以构造函数注入为例,在类的构造函数中声明依赖对象,Spring容器在创建该类实例时,会自动将依赖对象注入进来。
    • AOP(面向切面编程)
      • 概念:将一些与业务逻辑无关但又贯穿多个业务模块的功能(如日志记录、事务管理、权限控制等)抽取出来,形成一个独立的切面,在不修改原有业务代码的基础上,将这些切面功能动态地织入到目标业务模块中。
      • 实现方式:基于动态代理,有JDK动态代理和CGLIB动态代理。JDK动态代理基于接口实现,CGLIB动态代理基于继承实现,用于为没有实现接口的类创建代理。
  5. Spring Boot自动配置原理
    • 核心机制:Spring Boot通过@EnableAutoConfiguration注解开启自动配置功能。它会根据项目中引入的依赖,在classpath下寻找META - INF/spring.factories文件,该文件中定义了各种自动配置类。例如,当引入spring - boot - starter - web依赖时,会自动配置Tomcat、Spring MVC等相关组件。Spring Boot会根据条件注解(如@ConditionalOnClass、@ConditionalOnProperty等)判断是否满足自动配置条件,只有满足条件才会进行配置。
  6. MyBatis的一级缓存和二级缓存区别
    • 一级缓存
      • 作用域:SqlSession级别,在同一个SqlSession内,执行相同的SQL查询时,MyBatis会先从一级缓存中查找结果,若有则直接返回,不再执行SQL。
      • 生命周期:与SqlSession生命周期一致,当SqlSession关闭或提交事务时,一级缓存会被清空。
    • 二级缓存
      • 作用域:Mapper级别,多个SqlSession可以共享二级缓存。不同SqlSession执行相同Mapper的SQL查询时,若二级缓存中有数据,则直接返回。
      • 生命周期:应用程序运行期间,除非手动清空或配置了缓存刷新策略,否则二级缓存一直存在。需要注意的是,使用二级缓存时,缓存的对象必须实现Serializable接口。
  7. Dubbo的服务调用流程
    • 服务注册:服务提供者启动时,将自己提供的服务注册到注册中心(如Zookeeper),注册中心记录服务提供者的地址等信息。
    • 服务订阅:服务消费者启动时,向注册中心订阅自己所需的服务,注册中心返回服务提供者的地址列表。
    • 服务调用:服务消费者从地址列表中选择一个服务提供者进行调用。调用过程中,Dubbo支持负载均衡策略(如随机、轮询等)选择具体的服务实例。若服务提供者出现故障,注册中心会感知并通知服务消费者,消费者会重新选择可用的服务提供者。
  8. RabbitMQ的消息确认机制
    • 生产者确认(Publisher Confirm)
      • 开启方式:通过调用channel.confirmSelect()方法开启。
      • 原理:生产者发送消息后,RabbitMQ会给生产者发送一个确认消息,告知消息是否成功到达Broker。如果消息成功到达,生产者会收到一个ACK确认;如果消息未成功到达,生产者会收到一个NACK确认,此时生产者可以选择重发消息等处理方式。
    • 消费者确认(Consumer Ack)
      • 开启方式:默认自动确认(auto - ack=true),但这种方式存在风险,若消费者在处理消息过程中宕机,消息可能丢失。所以通常设置为手动确认(auto - ack=false)。
      • 原理:消费者接收并处理完消息后,向RabbitMQ发送一个确认消息(ACK),RabbitMQ收到ACK后才会将该消息从队列中删除。如果消费者未发送ACK或发送NACK,RabbitMQ会根据配置的策略(如重新入队等)处理该消息。
  9. xxl - job的调度原理
    • 调度中心:是xxl - job的核心组件,负责管理调度任务,包括任务的新增、修改、删除,以及触发任务调度。调度中心基于Quartz实现定时任务调度,通过数据库存储任务信息和调度日志。
    • 执行器:部署在业务系统中,负责接收调度中心的调度请求并执行任务。执行器启动时会向调度中心注册自己,调度中心根据任务配置,定时向对应的执行器发送调度请求,执行器执行任务后将结果返回给调度中心。
  10. Redis的持久化方式
  • RDB(Redis Database)
    • 原理:在指定的时间间隔内,将内存中的数据集快照写入磁盘,生成一个dump.rdb文件。恢复时,直接将rdb文件读入内存。
    • 优点:适合大规模数据恢复,生成的文件紧凑,占用空间小。
    • 缺点:可能会丢失最后一次快照后的所有数据,因为是定期快照。
  • AOF(Append - Only - File)
    • 原理:以日志的形式记录Redis服务器执行的写操作,恢复时重新执行这些写操作来重建数据集。
    • 优点:数据安全性高,基本可以保证不丢失数据,因为是实时记录写操作。
    • 缺点:文件体积可能较大,恢复速度相对RDB较慢,因为需要重放所有写操作。