Java 后端与 RAG 面试高频要点
文章目录
- Java 后端与 RAG 面试高频要点
- Java 基础
- MySQL 数据库
- Redis 与分布式锁
- AI 应用与 RAG
- 算法题:两数之和
- 小结
Java 基础
最有挑战的需求怎么讲
可以用 STAR 结构:
- S 情境:什么项目、什么业务。
- T 任务:遇到了什么难点。
- A 行动:你做了什么优化。
- R 结果:性能提升、错误率下降、响应时间降低。
示例:
在做旅游行程规划系统时,用户查询行程时接口响应较慢。我通过日志定位到数据库查询和外部数据拉取耗时较高,于是增加了缓存、优化了查询字段,并把串行调用改成并行处理。优化后接口响应时间明显下降,用户体验更好。
浅拷贝和深拷贝
| 类型 | 特点 | 实现方式 |
|---|---|---|
| 浅拷贝 | 引用类型共享同一块内存 | Object.clone() |
| 深拷贝 | 引用类型也创建新对象 | 重写 clone、序列化、JSON 转换 |
浅拷贝后,修改引用类型字段会影响原对象;深拷贝后,新旧对象完全独立。
JVM 运行时数据区
- 线程私有:程序计数器、虚拟机栈、本地方法栈。
- 线程共享:堆、方法区。
JDK 8 之后,方法区主要由元空间实现,使用本地内存。堆是对象主要存放区域,也是 GC 的重点区域。
ThreadLocal 原理与内存泄漏
- 每个线程内部有一个
ThreadLocalMap。 - Key 是
ThreadLocal,Value 是存储的数据。 - Key 是弱引用,Value 是强引用。
- 如果线程不销毁,比如线程池复用线程,Value 可能无法回收,造成内存泄漏。
- 解决方式:使用完后在
finally中调用remove()。
数组和链表区别
- 数组:内存连续,随机访问快,增删慢。
- 链表:内存不连续,随机访问慢,增删快。
- 数组适合读多写少,链表适合频繁插入删除。
- Java 中
ArrayList基于数组,LinkedList基于双向链表。
HashMap 原理及 1.7 和 1.8 区别
- JDK 1.7:数组 + 链表。
- JDK 1.8:数组 + 链表 + 红黑树。
- 1.7 使用头插法,1.8 使用尾插法。
- 1.8 在链表长度较长且数组长度达到阈值时会转成红黑树,提升查询性能。
- HashMap 不是线程安全的,高并发场景可以使用
ConcurrentHashMap。
重载和重写
- 重载:同一个类中,方法名相同,参数列表不同。
- 重写:子类重写父类方法,方法名和参数列表相同。
- 重载是编译时多态,重写是运行时多态。
异常处理体系
Throwable分为Error和Exception。Error通常是 JVM 级别错误,比如 OOM。Exception分为运行时异常和受检异常。- 运行时异常不强制捕获,受检异常必须处理或抛出。
synchronized 和 ReentrantLock
| 对比点 | synchronized | ReentrantLock |
|---|---|---|
| 类型 | 关键字 | JDK 类 |
| 释放锁 | 自动释放 | 需要手动释放 |
| 灵活性 | 较低 | 支持超时、可中断、公平锁 |
| 底层 | Monitor | AQS + CAS |
一般情况下优先使用synchronized;需要更灵活控制锁时使用ReentrantLock。
MySQL 数据库
ACID 如何实现
- 原子性:Undo Log,事务失败可以回滚。
- 一致性:由原子性、隔离性、持久性共同保证。
- 隔离性:MVCC 和锁机制。
- 持久性:Redo Log,崩溃后可以恢复数据。
索引失效常见场景
- 不满足最左前缀原则。
- 对索引列做运算或使用函数。
- 字符串查询不加引号,发生隐式类型转换。
- 使用
LIKE '%xxx'。 - 使用
OR且部分字段没有索引。 - 使用
NOT IN、!=等可能导致索引失效。
SQL 慢查询怎么排查
- 开启慢查询日志,定位慢 SQL。
- 使用
EXPLAIN分析执行计划。 - 关注
type、key、rows、Extra。 - 优化方式包括增加索引、改写 SQL、减少返回字段、优化分页。
什么时候分库分表
- 单表数据量过大,比如千万级。
- 单表体积过大,影响查询和维护。
- 单库压力过高,QPS 难以支撑。
分库分表方式:
- 垂直拆分:按业务或字段拆分。
- 水平拆分:按某个字段哈希或范围拆分。
需要注意分布式 ID、跨库查询、数据迁移等问题。
索引为什么用 B+ 树
- B+ 树非叶子节点只存索引,树更矮,IO 次数更少。
- 叶子节点通过链表连接,适合范围查询。
- Hash 索引不支持范围查询和排序。
- 红黑树树高较高,不适合磁盘存储场景。
Redis 与分布式锁
Redis 持久化方式
- RDB:定时快照,恢复快,但可能丢失最近数据。
- AOF:记录写命令,数据更安全,但文件较大。
- 混合持久化:结合 RDB 和 AOF 的优点,恢复速度和数据安全性更好。
AI 应用与 RAG
让 AI 生成 SQL 怎么优化
- 在提示词中提供表结构、字段含义和关联关系。
- 给出几个正确示例,帮助模型理解。
- 明确数据库类型,比如 MySQL、PostgreSQL。
- 限制输出格式,只返回 SQL。
如果生成错误,可以把报错信息、原始问题、表结构再返回给模型,让它自我修正。
如何评估 AI 应用效果
可以从几个方面看:
- 检索结果是否相关。
- 生成答案是否准确。
- 是否出现幻觉。
- 响应速度是否可接受。
- 用户点赞、点踩或继续追问情况。
RAG 基本流程
- 加载数据。
- 文本切块。
- 生成向量。
- 存入向量库。
- 用户提问。
- 检索相关文档。
- 拼接提示词。
- 大模型生成答案。
文本切块怎么做
- 可以按固定长度切分。
- 相邻块保留一定重叠,避免语义断裂。
- 也可以按段落、标题、文档结构切分。
- 切块太大会引入噪声,太小会丢失上下文。
效果不好怎么排查
- 先看检索到的文档是否相关。
- 如果不相关,可能是切块不合理、向量模型不合适、检索数量不足。
- 如果文档相关但答案不好,可能是提示词不清晰,或模型总结能力不足。
- 可以分别打印检索结果和生成结果,定位问题环节。
关键词匹配能否匹配“天气”和“气温”
传统关键词匹配很难匹配,因为两者字面不同。向量检索可以捕捉语义相似度,所以“天气”和“气温”在向量空间中会比较接近。更好的做法是使用向量检索和关键词检索结合。
Embedding 模型怎么选
中文场景可以优先选择 BGE 系列模型,中文语义理解效果较好。多语言场景可以考虑 OpenAI 的 embedding 模型或 E5 系列。选择时还要考虑维度、速度、成本和使用场景。
切块大小怎么定
一般可以在几百个 Token 左右调整。具体大小要结合 Embedding 模型限制、大模型上下文窗口、文档类型和业务场景来定。可以通过实验比较不同切块大小下的检索效果和回答质量。
算法题:两数之和
题目:给定一个数组和一个目标值,找出两个数,使它们的和等于目标值,返回它们的下标。
思路:使用 HashMap 保存已经遍历过的数字和下标。遍历时计算target - 当前数,如果这个值已经在 Map 中,说明找到了答案。
publicint[]twoSum(int[]nums,inttarget){Map<Integer,Integer>map=newHashMap<>();for(inti=0;i<nums.length;i++){intcomplement=target-nums[i];if(map.containsKey(complement)){returnnewint[]{map.get(complement),i};}map.put(nums[i],i);}thrownewIllegalArgumentException("No two sum solution");}时间复杂度是 O(n),空间复杂度是 O(n)。
小结
这份整理覆盖了 Java 后端基础和 RAG 应用常见面试题。面试时不必死记硬背,更重要的是能把知识点和自己的项目经历结合起来,说清楚“为什么用”“怎么用”“遇到过什么问题”“怎么解决”。
需要我帮你把这份内容再压缩成一篇 1500 字以内的精简版吗?