北京药帮忙科技有限公司-Java 一面 面经
1. 谈谈 ArrayList 和 LinkedList 的区别
- 底层数据结构:
ArrayList基于动态数组实现;LinkedList基于双向链表实现。 - 访问性能:
ArrayList支持随机访问,通过索引定位的时间复杂度为;
LinkedList需从头或尾遍历,时间复杂度为。
- 增删效率:
ArrayList在末尾增删较快,但在中间插入或删除需移动后续元素;LinkedList插入或删除只需修改指针,复杂度为,但定位到目标节点仍需
。
- 内存开销:
ArrayList空间连续,但有容量预留导致的碎片;LinkedList每个节点需额外存储前后指针,单节点内存占用更高。
2. Thread、Runnable、Callable 的区别是什么?
- 实现方式:
Thread是类,受 Java 单继承限制;Runnable和Callable是接口,扩展性更好。 - 返回值:
Runnable的run()方法没有返回值;Callable的call()方法支持返回结果,通常配合FutureTask使用。 - 异常处理:
Runnable只能在内部处理异常;Callable允许声明抛出受检异常。 - 推荐做法:生产环境通常使用
Runnable或Callable配合线程池执行,以实现资源复用和任务管理。
3. 索引的作用是什么?在项目中你是如何建索引的?
- 核心作用:索引的本质是排好序的数据结构(B+ 树),通过减少磁盘 I/O 次数来加速数据检索。
- 建索原则: 高频筛选:针对 WHERE、JOIN、ORDER BY 中的字段建立索引。区分度:优先选择离散度高的字段(如 ID、手机号),避免对重复率高的字段(如性别)建索引。复合索引:遵循最左匹配原则,优先建立联合索引以覆盖更多查询场景。覆盖索引:尽量让索引包含所有需要查询的列,避免回表操作提高性能。
4. 主键索引和联合索引的区别是什么?底层结构有何不同?
- 主键索引(聚簇索引):叶子节点直接存储完整的行数据。一张表只能有一个主键索引。
- 联合索引(非聚簇索引):叶子节点存储的是索引列的值值和对应的主键值。如果查询字段不在索引中,需要通过主键值进行“回表”。
- 底层结构:两者都采用 B+ 树。区别在于联合索引的排序是基于多个列组合的,且叶子节点不含整行数据。
5. 线上高并发场景下你会选择什么集合?
- 线程安全映射:使用
ConcurrentHashMap。Java 8 之后通过 CAS +synchronized锁桶节点,保证了极高的并发写入性能。 - 读多写少列表:使用
CopyOnWriteArrayList。采用“写时复制”策略,读操作完全无锁,适合配置表、白名单等场景。 - 异步缓冲队列:使用
ArrayBlockingQueue或LinkedBlockingQueue。利用其阻塞特性实现生产者-消费者模型,平衡系统负载。
6. 你对内存泄露有了解吗?通常如何解决?
- 定义理解:对象不再被程序使用,但由于仍被 GC Root 引用导致无法被回收,最终可能引发 OOM。
- 常见场景: 静态集合:长生命周期的 Map/List 持续持有对象。未关闭资源:IO 流、数据库连接、Socket 未手动关闭。ThreadLocal:使用完未调用 remove(),导致 Entry 堆积。
- 解决方法:使用
jmap或 Arthas 导出堆转储文件(Heap Dump),通过 VisualVM 或 MAT 分析引用链,定位强引用的根源并修复代码。
7. 动态代理你在哪些场景下使用到?
- 框架层面: Spring AOP:实现声明式事务(@Transactional)和日志监控。MyBatis:为 Mapper 接口生成代理实现类,执行 SQL。
- 业务应用: RPC 远程调用:为远程接口生成本地代理(Stub),隐藏底层网络传输细节。权限校验:在方法执行前统一进行用户身份认证和鉴权。
8. 介绍一下 Agent 项目的流程、RAG 与 Agent Loop 链路
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经
查看10道真题和解析