跳转到内容

平安银行 Java 开发一面 面经深度解析

来源:牛客网 王牌飞行员007 岗位:平安银行 Java 开发 特点:27 题覆盖 Java 基础、AOP/字节码增强、JVM 排查、内存泄漏、AI Agent 开发、项目经验,广度极大。


一、Java 基础与 AI

Q1-Q2:自我介绍 + Java 语言了解程度

基础热身题,按简历如实回答即可。Java 了解程度从基础语法 → 集合 → 并发 → JVM → 框架源码递进说明。

Q3:有接触过 AI 相关的开发吗?

参考回答:AI Agent 开发(OpenClaw/Claude Code)、RAG 检索增强生成、Prompt Engineering、大模型 API 调用(Chat Completion API)。


二、AOP 与字节码增强

Q4-Q5:AOP 是什么?应用场景?无侵入字节码植入?

AOP(面向切面编程):将横切关注点(日志、事务、权限)从核心业务逻辑中抽离出来。

@Aspect
@Component
public class LogAspect {
    @Around("@annotation(Log)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        log.info("方法: {}", point.getSignature().getName());
        long start = System.currentTimeMillis();
        Object result = point.proceed();
        log.info("耗时: {}ms", System.currentTimeMillis() - start);
        return result;
    }
}

应用场景:日志记录、权限校验、事务管理、性能监控、缓存处理、异常统一处理。

Q6:如何实现无侵入的字节码植入?(其他工程不需要依赖你的代码)

考点:Java Agent + 字节码增强。

方式

原理

侵入性

AOP 切面(Spring AOP)

编译时/运行时生成代理

需依赖 Spring,侵入

AspectJ 编译时织入

编译期修改 .class

需 AspectJ 编译器

Java Agent + ASM/ByteBuddy

运行时修改类字节码

无侵入

Java Agent 实现

// 1. premain-agent.jar —— 代理 JAR
public class MyAgent {
    public static void premain(String args, Instrumentation inst) {
        inst.addTransformer((loader, className, classBeingRedefined,
                             protectionDomain, classfileBuffer) -> {
            if (className.equals("com/example/target/UserService")) {
                ClassReader cr = new ClassReader(classfileBuffer);
                ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
                // ASM 修改字节码:在方法前后插入代码
                cr.accept(new ClassVisitor(ASM9, cw) {
                    @Override
                    public MethodVisitor visitMethod(int access, String name, ...) {
                        // 在目标方法前后插入耗时统计
                        ...
                    }
                }, 0);
                return cw.toByteArray();
            }
            return classfileBuffer;
        });
    }
}
# 2. 目标应用启动时加 -javaagent 参数
java -javaagent:premain-agent.jar -jar target-app.jar

# 3. attach 动态挂载(运行时不重启)
# Arthas 就是用的这个方式

Q7:了解 Arthas 或 SkyWalking 吗?

工具

原理

用途

Arthas(阿里)

Java Agent + Instrumentation API,运行时动态增强

在线诊断:查看方法耗时、反编译 class、监控调用链路、热替换代码

SkyWalking(Apache)

Java Agent + 插件体系,自动探针

APM 全链路追踪:服务拓扑、调用链 Trace、性能指标

# Arthas 常用命令
jad com.example.UserService          # 反编译
watch com.example.UserService * '{params, returnObj, throwExp}'  # 观察方法入参/返回值
trace com.example.UserService *      # 追踪方法调用链路
tt -t com.example.UserService getById  # 记录方法每次调用的耗时和参数

核心:二者都基于 Java Agent + 字节码增强,在不修改源码的情况下"插桩"监控。


三、JVM 排查

Q8:Java 项目出现内存溢出怎么排查?

OOM 排查流程

1. 确认 OOM 类型:
   ├── java.lang.OutOfMemoryError: Java heap space → 堆溢出
   ├── java.lang.OutOfMemoryError: Metaspace → 方法区溢出
   ├── java.lang.OutOfMemoryError: unable to create new native thread → 线程溢出
   └── java.lang.OutOfMemoryError: Direct buffer memory → 堆外内存溢出

2. 开启 OOM 自动 Dump:
   -XX:+HeapDumpOnOutOfMemoryError
   -XX:HeapDumpPath=/tmp/heapdump.hprof

3. 用 MAT 分析 hprof:
   ├── Leak Suspects Report → 定位最大嫌疑对象
   ├── Dominator Tree → 按保留集大小排序
   └── Path to GC Roots → 找到引用链

4. 修复 → 压测验证 → 上线

Q9:堆外内存溢出怎么解决?

堆外内存:JVM 堆之外的内存,GC 不管理。

堆外内存来源

解决方式

NIO DirectByteBuffer(Netty 大量使用)

-XX:MaxDirectMemorySize=512m 设上限;检查是否未释放 ByteBuffer

JNI/Unsafe

检查代码中 Unsafe.allocateMemory 是否配对 freeMemory

线程栈(每个线程 1MB 栈空间)

-Xss 控制栈大小;检查线程数是否过多

GZIP/Deflater

确认 end() 是否被调用,否则 Native 内存泄漏

排查工具pmap -x <pid>jcmd <pid> VM.native_memory summary(需开启 NMT:-XX:NativeMemoryTracking=detail)。


Q10-Q11:内存泄漏怎么判断?隐蔽的缓慢泄漏怎么排查?

判断方法

# 1. jstat 持续观察
jstat -gc <pid> 1000 100    # 每秒输出一次 GC 情况,共 100 次
# 关注:OU(老年代使用量)持续上升且 Full GC 后不降

# 2. 多次 Dump 对比
jmap -dump:live,format=b,file=heap1.hprof <pid>
# 等待 30 分钟
jmap -dump:live,format=b,file=heap2.hprof <pid>
# MAT → Compare Basket → 对比两个 Dump → 找出数量持续增长的类

隐蔽泄漏排查(长周期)

策略:长期监控 + 定期 Dump + 对比分析

1. 开启 JMX 监控:
   - Prometheus + JMX Exporter 长期记录 JVM 指标
   - Grafana 展示堆使用趋势曲线

2. 定期自动 Dump:
   - 写脚本每天凌晨 Dump 一次堆快照
   - 对比相邻两天的 Dump,找数量异常增长的类

3. 业务维度分析:
   - 内存增长率与 QPS 是否有相关性
   - 是否某次上线后内存趋势改变

4. Arthas 在线分析:
   - vmtool --action getInstances --className com.xxx --limit 100
   - 查看具体对象的字段值,判断业务来源

四、数据结构与并发

Q12:大量数据去重用什么数据结构?

数据结构

时间复杂度

空间

适合场景

HashSet

O(1)

O(n)

内存充足,数据量几百万内

BitMap

O(1)

O(n/8)

数据是正整数范围(如用户 ID 1~10^8)

布隆过滤器

O(k)

O(m)

亿级数据,可容忍少量误判(0.1%)

RoaringBitmap

O(1)

压缩高效

稀疏大范围整数集

HyperLogLog

O(1)

12KB

只统计去重计数,不存具体值


Q13:Set 有并发问题吗?

答案:有。HashSet 非线程安全。

多线程同时 add() 可能导致数据丢失或内部数据结构损坏。并发场景用:

  • Collections.synchronizedSet(new HashSet&lt;&gt;())
  • ConcurrentHashMap.newKeySet()(JDK 8+)
  • CopyOnWriteArraySet(读多写少)

Q14:HashMap 线程不安全体现在哪些方面?

方面

说明

数据覆盖

多线程 put 同一桶,value 互相覆盖

size++ 不准确

size++ 非原子操作,并发导致计数偏小

链表/红黑树结构破坏

并发 put 导致链表成环或树节点丢失

get 返回 null

扩容期间 get 可能定位到错误的桶

死循环(JDK 7)

头插法扩容导致环形链表,get 时死循环


五、项目经验

Q15:实习选择测试开发的原因?职业规划?

测试开发经历对质量意识有帮助,了解自动化测试框架、CI/CD 流程。未来想做后端开发,偏基础设施/AI 中间件方向。

Q16:Agent 验证如何做的?

验证体系:
├── 单元测试:每个 Tool 独立测试
├── 集成测试:Mock LLM 响应,测试 Agent 流程完整性
├── E2E 测试:真实 LLM,固定 Query 集 → 自动评判答案
├── 回归测试:每次 Prompt 变更后跑全量 E2E
└── 人工抽检:随机抽取 5% 用户对话,人工评分

Q17:和需求方怎么交流业务?遇到什么问题?

  • 需求评审会 + 需求文档 + 原型图
  • 难点:需求变更频繁 → 建立变更流程,评估影响后再排期
  • 跨部门对接:接口文档 + 定期同步进度

Q18-Q19:代码缺陷检测?和静态代码扫描的区别?

对比

静态代码扫描(SonarQube)

AI Agent 缺陷检测

检测方式

基于规则匹配(正则/AST)

基于 LLM 语义理解

检测范围

已知模式(SQL 注入、空指针)

业务逻辑缺陷、异常处理遗漏

误报率

低(LLM 上下文理解)

能发现

语法级别 Bug

语义级别 Bug(如死锁风险、并发安全问题)

缺陷分类:空指针、资源未关闭、并发安全、异常吞没、逻辑错误、性能隐患。


Q20:基于代码哈希构建方法级缓存表的作用?增量分析?

// 代码哈希计算
class MethodCache {
    Map<String, String> methodHashMap;  // methodName → methodBodyHash

    boolean isAnalyzed(String methodName, String newCodeHash) {
        String oldHash = methodHashMap.get(methodName);
        return Objects.equals(oldHash, newCodeHash);
    }
}

作用:判断某个方法自上次分析后是否变更,未变更则跳过分析。增量分析:只分析 Git diff 中改动的方法 → 大幅节省分析时间。

Q21:后端如何解析前端代码?

  • 静态解析:AST 解析器(Babel for JS/TS、@babel/parser
  • 抽象语法树遍历:提取函数调用、变量定义、组件结构
  • 数据流分析:追踪变量从定义到使用,检测未定义变量、未使用导入

六、AI Agent 与工具

Q22-Q23:有其他 Offer 吗?AI Agent 开发处于什么阶段?

已落地使用阶段:Agent 验证 + RAG + 多轮对话 + 工具调用全链路都已实现。

Q24:OpenClaw 有部署过吗?

OpenClaw 本地部署

# 安装
npm install -g openclaw

# 配置
openclaw config init

# 本地拉起
openclaw gateway start

# 配置 Agent 和模型
# openclaw.yml:
agents:
  - id: dev-assistant
    model: claude-sonnet-4
    skills: [java, spring, docker]

Q25:AI 编程工具能解决大部分需求开发吗?

答案:能解决 60-70% 的编码工作,但以下仍需人工:

AI 能做

仍需人工

CRUD 样板代码

复杂业务逻辑设计

SQL 编写

数据库表结构设计

Bug 修复辅助

架构决策

单元测试生成

跨系统集成方案

代码重构建议

性能极致优化


Q26:RAG 混合检索整体思路?

混合检索流程:
                         用户 Query
                            │
            ┌───────────────┼───────────────┐
            ▼               ▼               ▼
      ┌──────────┐   ┌──────────┐   ┌──────────┐
      │ 关键词检索 │   │ 向量检索  │   │ 知识图谱  │
      │ (BM25)   │   │ (Embedding)│   │ 检索     │
      │ 精确匹配  │   │ 语义相似   │   │ 结构化关系│
      └────┬─────┘   └────┬─────┘   └────┬─────┘
           │              │              │
           └──────────────┼──────────────┘
                          ▼
                    ┌──────────┐
                    │ 融合排序   │  ← RRF (Reciprocal Rank Fusion)
                    │ Rerank    │  ← Cross-encoder 重排序
                    └────┬─────┘
                         ▼
                    取 Top-K 结果
                         │
                         ▼
                    注入 LLM Prompt

关键环节

  1. 多路召回:关键词(精确)+ 向量(语义)+ KG(结构化),互补覆盖
  2. RRF 融合RRF(d) = Σ 1/(k + rank_i(d)),综合多路排名
  3. Rerank 精排:用 Cross-encoder(如 BGE-Reranker)对融合结果重新打分

面经总结

领域

题数

核心

AOP/字节码

4

AOP 原理 → 无侵入植入 → Arthas/SkyWalking

JVM 排查

4

OOM 分类 → 堆外内存 → 缓慢泄漏对比 Dump

数据结构/并发

3

去重数据结构选型 → Set/HashMap 线程安全

AI Agent

6

验证体系 → OpenClaw → RAG 混合检索

项目

7

代码缺陷检测 → 增量分析 → 业务沟通

综合

3

职业规划 → AI 工具认知 → 反问

面试特点:从 AOP 基础一路追问到 Java Agent 无侵入字节码实现(Q4→Q5→Q6→Q7),考察知识深度和广度。AI Agent + Java 后端双线并行,要求候选人既有传统 Java 功底,又了解 AI 开发。