客诺信息技术 Java后端 一二面面经:八股、项目与 Agent 追问
- 轮次
- 一面+二面
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
一面(9.23,15 分钟)
- 自我介绍。
- 实习的时候做过的最有挑战性的事是什么?
==比较的是什么?- 为什么使用 equals 之前我们也要重写 hashCode?
String a = new String("abc");和String b = new String("abc");,a == b和a.equals(b)的答案分别是什么?- 让你设计订单表,你会怎么设计?
- 一个商品今天卖 100,明天卖 120,那么昨天的订单价格会变化吗?
- 电脑连接 wifi,局域网 IP 是什么?
- 127.0.0.1 是什么 IP?
- 你平时使用的 AI 模型是什么?
- 你平时怎么去审查代码?
二面(9.29,50 分钟)· 实习相关
- 结合最近做的项目进行自我介绍。
- 实习项目中 RBAC 权限是怎么设计的?最终在后端是怎么控制用户调用接口的?
- 如果让你自己去实现权限注解,你会怎么设计?
- 实习中做的 Excel 数据表格导入这一块具体是怎么实现的?
- 邮件推送中的异常告警是怎么设计和触发的?
- 触发告警后怎么保证发送成功,链路是怎样的?失败了会怎么处理?
二面 · 八股和场景题
- 讲一下 Java 的集合框架。
- 讲一下这些集合容器有哪些常用的 API?
- 现在有一个学生成绩表(学生名字、各个科目的成绩),假设有一万条,现在要找出单科前十、总分前十的学生信息,使用集合进行实现。
- 在一个 controller 里面注入另一个 service,那么这个 service 是单例的还是多例的?
- 为什么 Spring 默认提供单例的 bean,为什么不是多例呢?有什么优缺点?
- 使用单例 bean 时有哪些需要注意的事项?
- SpringBoot 中你常使用的注解有哪些?
- 如果要将一个字符串存入数据库,那么有哪些字段类型可以进行存储?
- MySQL 中索引的创建和使用有哪些原则和技巧?
- 假设有班级表和学生表(有班级 id 冗余字段),现在要统计每个班级中有多少学生,具体 SQL 怎么写?
- 在上面的基础上,我还要统计男生人数和女生人数,应该怎么实现?
- Redis 中常见的数据结构有哪些?
- 对于这些数据结构,常见使用的 API 有哪些?
- git 中的常见操作有哪些?
- commit 和 push 的区别是什么?
- 浏览器中调试的开发者工具有使用过吗?
- network 里面你一般关注什么?
- 讲一下 HTTP 中你熟悉的状态码。
二面 · Agent 相关
- 大模型两种 API 的调用方式分别是什么?
- 这两种方式有什么区别?
- Agent 中的系统提示词和用户提示词有什么区别?
- 项目中 RAG 的评测是怎么做的?
- 精排的过程是怎么做的?
《参考解析》
== 与 equals、hashCode:== 对基本类型比的是值,对引用类型比的是地址;equals 默认也是比地址,被 String、Integer 这些类重写成比内容。重写 equals 就必须重写 hashCode,因为 HashMap、HashSet 先用 hashCode 定位桶、再用 equals 在桶内比较,两者不一致会出现「明明相等却查不到」或者同一个对象被存进两个桶的情况。规范写法是用同一个字段集合参与两者的计算,并且保证对象在放进集合后关键字段不再变化。
订单表设计与商品调价:订单表的核心是「下单那一刻的价格必须冻结」。所以订单表里除了商品 id,还要落成交价、数量、优惠金额、应付与实付,商品表改价不会回头改历史订单。第 7 题考的就是这个:昨天的订单价格不会变,因为订单存的是快照价而不是关联查询商品表当前价格。表结构上注意金额用 decimal 不要用 float、订单号独立于主键、状态字段配操作流水,方便对账和排查。
RBAC 与权限注解:RBAC 三张核心表——用户、角色、权限(或资源),加两张关联表。后端控制通常分两层:路由或方法级用注解声明所需权限,拦截器或 AOP 切面在调用前取出当前用户的权限集合做比对,越权直接抛异常。要自己实现一个权限注解,思路是自定义 @RequiresPermission 注解 → 在切面里通过反射拿到方法上的注解值 → 从 SecurityContext 或 ThreadLocal 取当前用户 → 查权限集合判断 → 不通过就抛 403,同时把校验结果做缓存避免每次打库,再补上超管放行和数据行级过滤这两处例外。
Spring 单例 bean:默认单例,因为绝大多数 bean 是无状态的(Service、DAO、工具类),复用同一个实例省去了反复创建的开销,也让依赖注入和生命周期管理简单得多。单例的代价是必须无状态:不能往成员变量里塞请求相关数据,否则并发下会互相串数据。所以单例 bean 的注意事项集中在一处——成员变量只放线程安全的、不可变的东西,请求级数据走方法参数或 ThreadLocal;真要持有可变状态就把作用域改成 prototype 或 request。
两条统计 SQL:每个班级的学生数是 select class_id, count(*) from student group by class_id。加男女分列不用查两次,用条件聚合一次出来:select class_id, count(*) total, sum(case when gender = 'M' then 1 else 0 end) male, sum(case when gender = 'F' then 1 else 0 end) female from student group by class_id。MySQL 里也可以写 count(if(gender = 'M', 1, null)),效果一样、更短,回答时点出「用 count 而不是 sum,避免没有男生时返回 0 行语义不一致」更容易加分。
Redis 数据结构与选型:String 做缓存与计数器(incr、setnx 做锁),Hash 存对象字段(hget、hincrby),List 做队列(lpush/rpop、brpop 阻塞取),Set 做去重与共同好友(sadd、sinter),ZSet 做排行榜与延时队列(zadd、zrange、按 score 取区间),再往上就是 bitmap 做签到、HyperLogLog 做 UV 估算、Stream 做消息。面试官问 API 其实是在问「你会不会按场景选结构」,把「什么场景用什么结构、为什么」讲出来比背命令列表值钱。
大模型的两种 API:Completion(文本补全,输入一段 prompt 直接续写)与 Chat(对话,输入是 role 为 system / user / assistant 的消息数组)。区别在三点:Chat 有角色区分、能多轮维护上下文,模型侧按对话格式训练,指令跟随和拒答表现更好;Completion 更接近裸的下一 token 预测,适合补全、改写这类任务,且没有多轮状态。现在新模型基本都推荐 Chat 接口,Completion 更多是兼容遗留代码或纯续写场景。
系统提示词与用户提示词:system 是调用方(应用)设定的角色、边界和输出格式,对整段会话生效,属于「规则」;user 是这次请求的具体输入,属于「内容」。两者冲突时模型通常优先遵守 system,这也是 prompt injection 要从这里防的原因——用户输入里出现「忽略以上指令」这类内容时,应用侧要做拼接隔离和输入校验,不能指望模型自己分辨。
RAG 评测与精排:评测一般分两层——检索层看 recall@k 和 MRR(该被召回的资料有没有进前 k、排得靠不靠前),生成层看忠实度(答案是否只依据召回内容,也就是幻觉率)、答案相关性、上下文利用率,手里要有标注好的问答对当测试集,改一次参数跑一遍对比。精排(rerank)在粗排召回之后,用 cross-encoder 这类模型把 query 与每篇候选文档拼在一起打分,比向量相似度更准但更慢,所以只对前几十条做;工程上还要注意截断长度、批次大小和打分归一化,否则排序结果在不同 query 之间不可比。