恒生电子一面面经(Java 开发)
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 简短自我介绍。
- 介绍一下 final 关键字。
- 讲一下反射。
- 哪些框架用了反射?
- 讲一下多线程。
- 你用过哪些中间件?
- 怎样实现分布式锁?
- 什么时候会用到分布式锁?
- Spring 你掌握得怎么样?
- AOP 的实现方式有哪些?
- 讲一下 HTTPS。
- HTTPS 的加密传输过程是怎样的?
- 数据库你熟悉哪一种?
- SQL 慢查询怎么处理?
- 有接触过 AI 编程吗?
- 工作地点确认。
- 期望薪资是多少?
- 手头有没有别的 offer?
- 反问。
《参考解析》
final 关键字。它有三处语义:修饰变量表示只能赋值一次(成员变量必须在声明处或构造器中初始化,引用不可变不代表对象内容不可变,比如 final List 仍能 add);修饰方法表示不能被子类重写;修饰类表示不能被继承(如 String、Integer 这些不可变类)。有两个容易被追问的点:一是 final 与 JMM 的关系——正确构造的对象的 final 字段有「安全发布」保证,其他线程能看到构造完成后的值,不需要额外同步;二是 static final 常量在编译期折叠进调用方字节码,改了常量值需要重新编译引用方,这是线上「改了配置没生效」的经典坑。
反射与框架。反射是在运行期获取类信息并操作对象的能力:Class.forName 或 类.class 拿到 Class 对象,通过 getDeclaredFields/Methods/Constructors 获取成员,用 setAccessible(true) 突破私有访问,再 newInstance 与 invoke 发起调用。它的代价是绕过编译期检查(错误推迟到运行期)、性能比直接调用差(现代 JVM 在调用点稳定后会有膨胀与内联优化,差距已经不大,主要成本在查找与装箱)、以及破坏封装。几乎所有主流框架都靠它:Spring 的依赖注入与注解扫描、MyBatis 的结果集映射、Jackson 的序列化、JUnit 的用例发现、以及各类 ORM 与 AOP 代理。
AOP 的实现方式。AOP 把日志、事务、权限、埋点这类横切关注点从业务代码里抽出来,核心概念是切面、切点、通知与织入时机。实现方式有两类:静态织入(AspectJ 的编译期或类加载期织入,性能最好但需要额外编译器或 agent)和动态代理(Spring AOP 默认走这条)。动态代理又分两种:接口代理用 JDK 的 Proxy 加 InvocationHandler,通过实现同一接口生成代理类,因此要求目标类至少实现一个接口;类代理用 CGLIB 生成目标类的子类并覆写方法,因此不能代理 final 类与 final 方法,私有方法与同类内部调用也不会走代理——这是「@Transactional 或 @Cacheable 加了却不生效」的第一大原因,解法是从容器里拿代理对象调用自己(AopContext.currentProxy())或把方法拆到另一个 Bean。另外 Spring Boot 2.x 之后默认用 CGLIB(proxyTargetClass=true),「代理边界即事务边界」这句话能把事务失效的场景串起来。
分布式锁的实现与使用场景。单机锁(synchronized、ReentrantLock)只在同一 JVM 内有效,一旦服务多实例部署,需要用外部存储做互斥。主流有三种:Redis、ZooKeeper、数据库。Redis 的标准做法是 SET key value NX PX ttl,value 用 UUID 加线程标识,释放时用 Lua 脚本先比对 value 再删除(保证原子性,防止误删别人的锁);必须有过期时间防止持有者宕机造成死锁;业务可能超时就要续期(Redisson 的看门狗默认每 10 秒续到 30 秒,只在未显式指定 leaseTime 时启用)。ZooKeeper 用临时顺序节点加 Watch,天然有会话失效释放与公平排队,一致性更强但性能低于 Redis、且需要额外运维。数据库可以用唯一索引插入或 SELECT ... FOR UPDATE,实现简单但并发差,适合低频任务互斥。使用场景的共同特征是「跨进程需要互斥的临界区」:定时任务多实例只让一个跑、秒杀或抢券的库存扣减、防止同一订单被重复处理、幂等控制、以及跨服务的资源占用。要强调的边界是:分布式锁只能降低并发冲突,不能替代幂等——主从切换、网络分区、GC 停顿都可能让锁失效,所以业务侧仍要有唯一约束与状态机兜底;锁的粒度要尽量小、等待要用带超时的 tryLock 避免线程堆积,Redlock 在强一致要求下的争议也要能说出一二。
HTTPS 的加密传输过程。HTTPS 就是 HTTP 加 TLS,目标是在不安全的信道上同时实现机密性、完整性与身份认证。握手(以 TLS 1.2 的常见流程为例)大致是:客户端发 ClientHello(支持的版本、密码套件、随机数 A);服务端回 ServerHello(选定套件、随机数 B)与证书链;客户端校验证书(有效期、域名、签发链,验证书是否被吊销),校验证书公钥确实能解开服务端用私钥做的签名,从而确认服务端身份;客户端生成预主密钥,用服务器证书里的公钥加密后发过去(RSA 密钥交换;现代用 ECDHE 则双方各自算共享密钥,具备前向安全性),双方用三个随机数派生出会话密钥;之后交换 Finished(对前面所有握手消息的摘要做校验)确认握手未被篡改,再切换为对称加密传输应用数据。TLS 1.3 把握手压到一次往返(1-RTT)并砍掉了 RSA 密钥交换、只保留前向安全的方案。要理解「为什么用非对称加密协商、用对称加密传输」:非对称算法慢且只能加密小块数据,适合做密钥交换与签名;对称算法(AES-GCM)快,适合加密业务数据,同时 GCM 这类 AEAD 模式顺带提供完整性校验。证书体系的根在操作系统与浏览器的受信任根 CA 列表,中间证书用于减少根证书暴露风险。
SQL 慢查询与数据库选型。治理慢查询先定位再优化:开启慢查询日志(slow_query_log 加 long_query_time,线上可先用 pt-query-digest 聚合),用 EXPLAIN 看执行计划,重点看 type(出现 ALL 是全表扫描)、key(实际用了哪个索引)、rows(预估扫描行数)、Extra(Using filesort、Using temporary 是常见瓶颈信号)。优化手段按性价比排序:建合适的联合索引并遵守最左前缀、避免索引失效(对列做函数运算、隐式类型转换、前导模糊 like '%x'、or 混用非索引列、!= 与 is null 视情况)、用覆盖索引减少回表、只查需要的列而不是 select *、大分页改用游标或延迟关联(where id > last_id limit n)、拆分大事务与批量写、必要时做归档与分表,以及从业务上减少查询次数(缓存、异步化)。数据库选型方面,OLTP 业务默认 InnoDB(事务、行锁、MVCC、崩溃恢复),需要离线分析或海量写入才考虑列存或 ClickHouse 这类专用引擎;被问「熟悉哪种」时,把 InnoDB 的索引结构(B+ 树聚簇索引、二级索引回表)、事务与锁、以及上面这套慢查询方法论讲清就够了。
面试节奏。原帖记录面试 15 分钟结束、问题常规,这类「短平快」的一面关键是把每个问题答成「结论加一层原理加一个例子」的三段式,不要展开成讲座;同时把工作地点、期望薪资、手头 offer 这类问题准备成确定性回答(给区间、说明依据、表达意向),它们是这一轮真正的筛选项。被问 AI 编程时,如实说清用在哪些环节(写样板代码、生成测试、读陌生代码),并强调验证手段(跑测试、读 diff、类型检查),比声称「全靠 AI」更可信。