互联网大厂 Java 求职者面试场景

72 阅读7分钟

互联网大厂 Java 求职者面试场景

第一轮提问

面试官:王铁牛,先简单说说 Java 中的 ArrayList 和 HashMap 的区别吧。 王铁牛:ArrayList 是数组列表,按顺序存储元素,HashMap 是键值对存储,通过键来快速查找值。 面试官:回答得不错。那 ArrayList 的扩容机制是怎样的呢? 王铁牛:嗯……好像是当元素数量超过容量时就扩容,具体不太清楚。 面试官:HashMap 的底层数据结构是什么? 王铁牛:是数组加链表,后来好像有红黑树什么的。

第二轮提问

面试官:说说 Spring 中 Bean 的生命周期吧。 王铁牛:就是创建、初始化、使用、销毁吧,具体细节不太记得了。 面试官:Spring Boot 自动配置的原理能讲讲吗? 王铁牛:好像是根据一些条件来自动配置相关组件,但具体怎么弄的不太清楚。 面试官:MyBatis 中 #{} 和 {} 的区别是什么? 王铁牛:#{} 是预编译,{} 是直接拼接 SQL,#{} 更安全。

第三轮提问

面试官:Dubbo 服务注册与发现的原理是什么? 王铁牛:就是把服务注册到注册中心,消费者从注册中心获取服务地址,具体细节不太了解。 面试官:RabbitMQ 中的消息确认机制是怎样的? 王铁牛:有发送确认和消费确认,发送确认保证消息发送成功,消费确认保证消息被正确消费,具体流程有点模糊。 面试官:xxl - job 是如何实现分布式任务调度的? 王铁牛:不太清楚,好像是有个调度中心和执行器。

面试官:好了,今天的面试就到这里,你回家等通知吧。

问题答案

  1. ArrayList 和 HashMap 的区别:ArrayList 是基于数组实现的有序列表,按顺序存储元素,查询元素通过索引,时间复杂度为 O(1),增删元素在中间位置时需要移动后续元素,时间复杂度为 O(n)。HashMap 是基于哈希表实现的键值对集合,通过键的哈希值快速定位存储位置,查询、插入和删除操作平均时间复杂度为 O(1),但在哈希冲突严重时性能会下降。
  2. ArrayList 的扩容机制:当向 ArrayList 中添加元素时,如果当前元素数量超过了 ArrayList 的容量,ArrayList 会进行扩容。默认情况下,扩容后的容量是原容量的 1.5 倍。例如,初始容量为 10,当添加第 11 个元素时,会创建一个新的容量为 15 的数组,并将原数组中的元素复制到新数组中。
  3. HashMap 的底层数据结构:在 JDK 1.8 之前,HashMap 的底层数据结构是数组 + 链表。当发生哈希冲突时,会将冲突的元素以链表的形式存储在数组的同一个位置。在 JDK 1.8 及之后,当链表长度达到 8 且数组容量大于 64 时,链表会转换为红黑树,以提高查找效率。红黑树是一种自平衡的二叉查找树,它能保证在最坏情况下,查找、插入和删除操作的时间复杂度为 O(log n)。
  4. Spring 中 Bean 的生命周期
    • 实例化:通过构造函数创建 Bean 的实例。
    • 属性赋值:Spring 容器通过依赖注入(DI)为 Bean 的属性赋值。
    • 初始化前:如果 Bean 实现了 BeanNameAware 接口,Spring 容器会调用其 setBeanName 方法,将 Bean 的名称注入到 Bean 中;如果实现了 BeanFactoryAware 接口,会调用其 setBeanFactory 方法,将 BeanFactory 注入到 Bean 中;如果实现了 ApplicationContextAware 接口,会调用其 setApplicationContext 方法,将 ApplicationContext 注入到 Bean 中。
    • 初始化:如果 Bean 实现了 InitializingBean 接口,Spring 容器会调用其 afterPropertiesSet 方法;如果在配置文件中为 Bean 配置了 init - method 属性,Spring 容器会调用该方法进行初始化。
    • 使用:Bean 初始化完成后,可以被其他组件使用。
    • 销毁前:如果 Bean 实现了 DisposableBean 接口,在 Spring 容器关闭时,会调用其 destroy 方法;如果在配置文件中为 Bean 配置了 destroy - method 属性,Spring 容器会调用该方法进行销毁前的处理。
    • 销毁:Spring 容器关闭时,会销毁 Bean,释放资源。
  5. Spring Boot 自动配置的原理:Spring Boot 自动配置是基于条件配置(Conditional Configuration)和自动配置类(Auto - Configuration Classes)实现的。Spring Boot 会扫描 classpath 下的 META - INF/spring.factories 文件,该文件中定义了一系列自动配置类。这些自动配置类上使用了各种条件注解(如 @ConditionalOnClass@ConditionalOnProperty 等),只有当满足这些条件时,对应的自动配置类才会生效。例如,@ConditionalOnClass 注解表示当 classpath 中存在指定的类时,该自动配置类才会生效。
  6. **MyBatis 中 #{} 和 {} 的区别**:#{} 是预编译占位符,MyBatis 会将其替换为一个占位符 `?`,在 SQL 执行前会进行预编译,将参数值设置到占位符中,这种方式可以有效防止 SQL 注入攻击。{} 是直接将参数值拼接在 SQL 中,在 SQL 执行前不会进行预编译,因此存在 SQL 注入的风险。例如,当使用 ${} 拼接表名时,如果传入的表名是恶意的 SQL 代码,就可能导致数据库被攻击。
  7. Dubbo 服务注册与发现的原理:Dubbo 支持多种注册中心,如 Zookeeper、Redis 等。以 Zookeeper 为例,服务提供者启动时,会将自己的服务信息(如服务接口、服务地址等)注册到 Zookeeper 上的指定节点。服务消费者启动时,会从 Zookeeper 上获取服务提供者的地址列表,并根据一定的负载均衡策略选择一个服务提供者进行调用。当服务提供者的状态发生变化(如上线、下线)时,Zookeeper 会通知服务消费者,服务消费者会更新自己的服务地址列表。
  8. RabbitMQ 中的消息确认机制
    • 发送确认:生产者发送消息到 RabbitMQ 后,可以通过开启发送确认机制来确保消息被成功接收。RabbitMQ 会给生产者发送确认消息,告知消息是否被成功接收。发送确认有两种模式:普通确认模式和批量确认模式。普通确认模式下,生产者每发送一条消息,都需要等待 RabbitMQ 的确认;批量确认模式下,生产者可以发送一批消息后,再一次性等待确认。
    • 消费确认:消费者从 RabbitMQ 接收消息后,需要向 RabbitMQ 发送确认消息,告知消息已经被成功消费。消费确认也有两种模式:自动确认和手动确认。自动确认模式下,消费者接收到消息后,RabbitMQ 会自动将消息标记为已消费;手动确认模式下,消费者需要在处理完消息后,显式地向 RabbitMQ 发送确认消息。如果消费者在处理消息过程中出现异常,没有发送确认消息,RabbitMQ 会将消息重新放入队列,等待其他消费者或重新消费。
  9. xxl - job 是如何实现分布式任务调度的:xxl - job 有一个调度中心,负责管理任务的调度配置、任务的触发和调度日志的记录等。执行器部署在各个业务服务器上,负责接收调度中心的任务调度请求,并执行具体的任务。调度中心通过 HTTP 协议与执行器进行通信,将任务信息发送给执行器。执行器执行完任务后,会将任务执行结果返回给调度中心。调度中心可以根据任务的执行结果进行相应的处理,如重试任务、记录任务执行状态等。同时,xxl - job 还支持任务的分片执行,将一个任务分成多个子任务,由多个执行器并行执行,提高任务的执行效率。