“你 Java 基础怎么样HashMap 看过源码吗Spring 的循环依赖怎么解决的你们微服务拆了哪些服务分布式事务用的什么方案”这套组合拳打下来很多准备过“八股文”的 Java 全栈开发工程师都会有点招架不住。原因很简单现在的面试已经不太认单纯的背诵型答案了面试官更关心你到底是“用过这些技术”还是“真正理解这些技术背后的设计逻辑”。我自己这几年以不同身份经历了多轮 Java 全栈开发工程师面试有被人问倒的时候也有坐在对面问别人的时候最大的感触是从基础语法到微服务架构面试官考察的从来不是零散的知识点而是一条完整的“技术理解链路”。这篇文章我不打算罗列面试题清单那网上到处都是。我想换一个更实用的角度把 Java 全栈开发工程师面试中最高频的几大块——集合与并发、Spring 框架、数据库与缓存、微服务与分布式、代码面试与线上排查——拆开来讲清楚“为什么会被这样问”以及“怎样回答才能让面试官觉得你是真的懂”。文章会从实际面试场景出发穿插我踩过的坑和后来总结出的答题思路适合正在准备面试的初级、中级 Java 开发也适合想系统梳理知识体系的同学。全程高密度干货但尽量说人话。1. 先捋清楚主线Java 全栈面试到底在考察什么先别急着刷题。磨刀不误砍柴工我建议每个准备面试的人做的第一件事是搞清楚面试官手里的“考察地图”长什么样。1.1 一场典型技术面的“火力配置”我经历过的大多数 Java 岗位技术面流程上可以概括为三个阶段第一个阶段是基础盘问。以集合、并发、JVM、MySQL 为主时长大概 20 到 30 分钟。这个阶段的核心目的是快速确认“你有没有扎实的底层功底”。问法通常是从一个点开始不断向深处追问比如“HashMap 怎么扩容”可以一路追到“为什么链表转红黑树的阈值是 8”“红黑树和 AVL 树的区别是什么”。第二个阶段是框架与项目。围绕 Spring、Spring Boot、微服务组件和你简历上写的项目展开时长 30 到 40 分钟。这里考察的是“你平时写代码时有没有想过框架为什么这么设计”“你的项目里技术选型是怎么做的、遇到过什么问题、怎么解决的”。第三个阶段是手写代码或系统设计。可能是 1 到 2 道算法题也可能是一道开放式设计题比如“设计一个秒杀系统”“你们的订单超时未支付怎么处理”。很多人在第一阶段就被刷掉不是因为不会而是因为答得太“标准”。标准得像背课文——每个概念都能说出来但问到两层以下就卡壳。面试官判断你有没有真正理解一个知识点最好的方法就是连续追问两三个“为什么”这时候死记硬背的东西会迅速现出原形。1.2 面试官真正想验证的三条能力线我把这些年遇到的面试问题归了归类发现不管面试官的问题怎么变本质上都在验证三条能力线底层原理理解能力。你对 Java 语言本身、JVM、常用中间件原理的掌握深度。能不能讲清楚 HashMap 的底层结构变化过程能不能说清线程池的核心参数如何协同工作能不能解释 MySQL 的索引为什么用 B 树。架构设计与取舍能力。你在做技术选型时知不知道每个方案的优势和代价。比如微服务拆分的粒度怎么把握分布式事务选型时为什么不用 2PC 而用最终一致性方案Redis 缓存和数据库的一致性你怎么保证。工程落地与排障能力。你面对线上问题时有没有一套可执行的排查思路。内存溢出怎么定位、接口变慢怎么排查、消息积压了怎么办这些问题的答案没有固定标准但能看出来一个工程师的实战水平。想清楚这三点你就知道复习的时候不应该平均用力。底层原理要能一层层往深讲架构选型要能说出取舍依据排障思路要有清晰的操作路径。接下来我就按照面试中最常遇到的顺序把这三大块逐个拆开讲。2. 基础层集合、并发与 JVM 的追问深度基础层是 Java 面试的“入场券”也是刷人最多的地方。这一部分看书笔记就能应对的概念题我就不重复了重点说几个高频考点背后的深层逻辑和应答思路。2.1 HashMap 连环问从 put 流程到红黑树阈值HashMap 几乎是一面必考题因为它一题能带出一大片考点。我推荐准备一份“从 put 开始讲”的完整叙述先讲清楚 put(key, value) 的完整过程计算 key 的 hash 值通过扰动函数进一步散列算出数组下标如果对应位置为空就直接放入如果有冲突就挂链表如果链表长度超过阈值 8就转红黑树插入后如果整个数组元素个数超过负载因子 0.75 × 容量就触发扩容。再讲为什么这么设计。扰动函数是为了让高位信息参与低位运算减少碰撞链表转红黑树是为了防止极端哈希冲突下查询退化成 O(n)阈值 8 的选择背后是泊松分布模型在随机哈希下链表长度达到 8 的概率已经极低转树可以避免最坏情况又不会因为树化开销过大影响正常性能。这里我想多说一句真正让面试官眼前一亮的关键在于你能不能讲清楚“为什么要用红黑树而不是平衡二叉树”“为什么数组容量总是 2 的 n 次幂”。这两个问题背后藏着一个共同原因为了让(n - 1) hash这个位运算等效于取模运算。因为 n 是 2 的幂n-1 的二进制低位全是 1与运算结果就能均匀分散。而红黑树的插入和删除时间复杂度是 O(log n)和 AVL 树相比牺牲了部分查询的绝对平衡换来了更少的旋转次数。在高频插入删除的场景下红黑树的整体表现更稳。2.2 线程池从参数协同到拒绝策略并发编程里线程池是必问考点核心问题一般是线程池的核心参数有哪些它们是怎么协同工作的一般人都能背出来核心线程数、最大线程数、空闲存活时间、工作队列、线程工厂、拒绝策略。但面试官真正想听的不是参数列表而是任务提交后的完整流转过程当线程池接到一个新任务先判断当前工作线程数是否小于核心线程数是则新建线程执行任务。如果核心线程已经满了新任务进入工作队列等待。如果工作队列也满了再判断当前线程数是否小于最大线程数是则创建新线程这些线程是应急用的。如果线程数已经达到最大值任务就只能交给拒绝策略处理。围绕这个流程有两个容易被追问的实际问题。第一个是核心线程数怎么设置。纯 CPU 密集型任务推荐设为 CPU 核数 1IO 密集型任务可以设得更高比如 CPU 核数的 2 倍左右。但更实际的做法是先压测通过观测线程池任务提交速率、执行耗时和队列积压情况来调整而不是凭公式拍脑袋。第二个问题是线程池的队列选型。注意几乎不会用无界队列因为无界队列会让“最大线程数”形同虚设任务无限排队最终可能导致内存耗尽。一般用有界队列配合合适的拒绝策略比较稳妥。2.3 JVM 内存分区与 OOM 实战理解JVM 相关问题里被问最多的除了内存分区就是“线上 OOM 了怎么排查”。内存分区的背诵题我就不展开了单说 OOM 排查的思路这属于典型的“有没有实战经验”题。标准的排查链路是发现服务异常或收到监控告警后把堆 dump 文件导出来用分析工具打开找到占用内存最大的对象再顺着引用链看它被谁持有、为什么没被回收。举一个我实际处理过的场景某服务定期内存上涨最后溢出。dump 分析后发现大量对象挂在 ThreadLocal 上。原因是线程池里的线程是复用的而代码在请求结束后忘记调用 ThreadLocal 的 remove 方法导致对象一直被线程引用无法回收。这种问题定位到根因后解决很简单但没经验的开发者可能会卡在“内存为什么只涨不降”这个现象上很久。JVM 的考点里还有一个高频组合堆内存怎么划分、GC 算法有哪些、CMS 和 G1 的区别。回答的关键是要能结合你实际的 JVM 参数来说明比如“我那个服务设置的是 -Xms4g -Xmx4g用的 G1为什么设置初始堆和最大堆一样因为避免运行期动态扩容缩容带来的停顿。”这种结合实践的表述比单纯背“G1 把堆分成 Region”要打动人得多。3. 框架层Spring 核心机制与 Spring Boot 自动配置框架层面的问题背诵型选手和实战型选手的区别最明显。你可以在简历上写“熟悉 Spring”但面试官三个问题就能判断出你的熟悉程度Bean 生命周期是什么循环依赖怎么解决Spring Boot 自动配置的原理是什么3.1 Bean 生命周期与三级缓存解循环依赖Bean 生命周期这个问题建议不要按源码从后往前背而是按一条主线讲实例化 → 属性填充 → 初始化包括 Aware 回调、BeanPostProcessor 前后置处理、InitializingBean 和 init-method→ 使用 → 销毁。面试官通常会在你讲的时候插入追问“Spring 怎么解决构造器循环依赖怎么解决 Setter 循环依赖”为什么这么问因为这两个答案不一样能答出区别才是真懂。Spring 解决 Setter 注入的循环依赖靠的是三级缓存一级缓存存完整的单例 Bean二级缓存存早期暴露的半成品 Bean没有完成属性填充的对象三级缓存存的是对象工厂ObjectFactory。当 A 依赖 B、B 依赖 A 时A 实例化后会先把一个工厂放入三级缓存此时 A 还是半成品A 去填充属性时发现需要 B于是去创建 BB 实例化后也把工厂放入三级缓存B 填充属性时发现需要 A此时在三级缓存里找到 A 的工厂通过工厂获得 A 的早期引用完成 B 的创建B 完整创建后A 再从缓存中拿到 B完成自己的属性填充最终 A 也成为完整 Bean。但构造器注入的循环依赖是无解的因为构造器注入在实例化阶段就必须拿到完整依赖此时 Bean 还没进入缓存体系没法提前暴露。所以 Spring 会在启动时直接抛出异常。回答里如果能顺带提一句“Spring Boot 2.6 之后默认禁止了循环依赖”说明你对版本演进也有关注这是加分项。3.2 AOP 代理的本质与典型应用AOP 的考点一般集中在动态代理有哪两种实现方式区别是什么Spring AOP 默认用哪种回答框架Spring AOP 默认使用 JDK 动态代理要求目标类必须实现接口代理对象和目标对象实现同一个接口通过 InvocationHandler 拦截方法调用如果目标类没有实现接口Spring 会回退到 CGLIB 代理通过生成目标类的子类来覆盖方法子类在运行时通过 MethodInterceptor 回调实现增强。Spring Boot 2.x 之后默认已经改为 CGLIB 优先。容易被追问的是这两种代理各自的限制。JDK 动态代理只能代理接口方法CGLIB 不能代理 final 方法和 final 类。还有一个实战细节被同一个类内部方法调用时AOP 增强可能不生效。因为代理对象通过拦截方法入口实现增强而内部方法走的是 this 调用没有经过代理。这个点说出来面试官就知道你是真在项目里踩过这个坑。AOP 的经典应用场景也要准备好事务管理、日志记录、权限校验、接口耗时统计。回答时可以结合自己项目里的实际例子比如“我在项目里用一个 AOP 切面统一打印了接口入参出参和耗时还用它做了操作日志记录”比只背概念强得多。3.3 Spring Boot 自动配置机制Spring Boot 的自动配置是框架层的必问题也是区分“会用 Spring Boot”和“懂 Spring Boot”的分水岭。核心回答路径是Spring Boot 启动类上有 SpringBootApplication这个注解是由 SpringBootConfiguration、EnableAutoConfiguration 和 ComponentScan 组合而成的。其中 EnableAutoConfiguration 通过 Import 引入了自动配置导入选择器这个选择器会扫描所有 jar 包中 META-INF 下的 spring.factories 文件Spring Boot 3 则读取 META-INF/spring 下的 AutoConfiguration.imports 文件拿到所有标注了自动配置的候选类名再根据条件注解逐个判断是否满足生效条件。比如 ConditionalOnClass 判断类路径下有没有对应的类ConditionalOnMissingBean 判断容器里是否已经存在用户自定义的 Bean只有条件全部满足这段自动配置才会生效。这个机制理解透了很多现象就能解释通了。比如为什么你引入一个依赖后不需要自己装配相关 Bean因为自动配置类背后有大量的 Conditional 判断。为什么你自己定义了一个数据源后Spring Boot 不会再帮你创建一个默认的因为数据源自动配置类上有 ConditionalOnMissingBean你既然已经自定义了条件不满足它就自动退出了。面试时能说出这一层比单纯说“Spring Boot 可以自动配置很方便”要深刻得多。4. 数据层MySQL 与 Redis 的高频组合题数据库和缓存是 Java 后端面试的重头戏也是项目经验最容易挂钩的部分。这一块我不打算展开所有的 SQL 语法重点讲三个面试最常驻的高频考区索引与 SQL 优化、事务隔离与 MVCC、Redis 缓存三大经典问题。4.1 索引失效场景与一条慢 SQL 的复盘关于索引准备面试的核心不是背“哪些情况会导致索引失效”而是理解 B 树的结构特征后自己推导出结论。我说几个最常见的提问场景为什么最左前缀原则生效因为联合索引本质上是一个按第一列、第二列……依次排序的 B 树。只查第二列时索引树的有序性在第一列之后才体现无法定位范围所以不能走索引。为什么对索引列做函数运算会导致失效因为函数运算破坏了索引列原有的有序排列。面试时如果能现场画出一个联合索引树的结构再用它解释为什么where a 1 and b 2能走索引、where b 2走不了基本就能让面试官点头了。关于慢 SQL 优化我比较推荐一个实战答题模板先说定位数据库开启慢查询日志抓出耗时超过阈值的 SQL再做分析用 EXPLAIN 看执行计划重点看 type 是不是达到了 ref 或 range有没有出现 Using filesort、Using temporary最后是优化手段加合适的索引、改写 SQL 避免不必要的回表、拆分大查询、必要时引入缓存。能背出一个你自己处理过的慢 SQL 案例哪怕是很简单的场景效果也远好于泛泛而谈。4.2 事务隔离级别与 MVCC 的连带回答事务这一块更容易被追问的是“MVCC 在 RR 和 RC 下的区别”“当前读和快照读的区别”。我建议的回答结构是先解释 MVCC 的核心是隐藏字段加 undo log 版本链。每一行数据有隐藏的事务 ID 字段和回滚指针字段UPDATE 时生成新版本并通过回滚指针串成版本链。然后讲 ReadView 的生成机制RC 隔离级别下每次快照读都会生成一个新的 ReadView因此能读到其他事务已提交的最新版本RR 隔离级别下第一次快照读生成 ReadView 后后续一直复用这个 ReadView因此同一个事务内多次读取结果一致这就是可重复读的实现基础。一部分面试官还会追一句“那 RR 下幻读还可能出现吗”关键在于区分快照读和当前读。如果事务中先做了一次快照读再执行当前读比如SELECT ... FOR UPDATE在当前读生成新 ReadView 时会看到之前不可见的新插入行所以幻读在当前读下依然可能发生InnoDB 是通过间隙锁或临键锁来兜底解决的。把这个区别讲出来整道题才算闭环。4.3 Redis 缓存穿透、击穿、雪崩的工程防御缓存这一块现在已经不算难题了但每次面试我都会被问到一个更深的问题“缓存方案本身会带来一致性问题你怎么解决” 所以不能只背“缓存三大问题”的解决方案还要准备一致性的问答。先快速列出三大问题及常用防御穿透查询一个根本不存在的数据请求直接打到数据库。防御方案用布隆过滤器先拦截同时缓存空值并设置较短过期时间。击穿某个热点 key 过期瞬间大量请求同时打到数据库。防御方案是热点 key 不设置过期时间或者用互斥锁保证只有一个请求去重建缓存。雪崩大量 key 同时过期数据库压力瞬间暴涨。防御方案是过期时间加随机抖动或者多级缓存、限流降级兜底。这里我要多说一句很多人忽略了一个细节就是缓存和数据库的写一致性。比较务实的做法是读多写少的场景采用 Cache Aside 模式读的时候先读缓存没有就查库再回填写的时候先更新数据库再删除缓存。删除缓存而不是更新缓存是因为更新缓存有并发时序问题容易把旧值写进去而删除缓存后下次读的时候再回填即使并发下出现问题最多多查一次数据库影响面可控。这个方案并非完美但在绝大多数业务场景下是性价比最高的选择面试时能说出这层逻辑就够了。5. 微服务与分布式从注册中心到分布式事务Java 全栈开发工程师的中高级面试绕不开微服务。这一部分的考察重点已经从“会用什么组件”转向了“为什么这么拆、数据一致性问题怎么处理、线上怎么排查”。5.1 服务拆分与数据一致性的矛盾面试官常问的第一个问题是“你们为什么做微服务拆分的依据是什么”这个问题答不好后面基本很难加分。一个比较完整的回答思路是从业务痛点出发而不是“为了微服务而微服务”。比如团队人数变多、代码仓库混乱、发布相互牵制、某个模块流量暴涨却难以独立扩容这些才是引入微服务的动机。拆分的依据可以用领域边界来划比如按用户、订单、商品、支付这样的业务域拆分或者按调用频率和变更频率拆分原则是让每个服务能独立开发、独立部署、独立扩容。但微服务带来的最大代价就是分布式数据一致性。以前在一个数据库里一个事务就能搞定的事拆开后变成跨服务调用了。面试官此时通常会追问“跨服务的数据一致性你们怎么保证”这就引出了下一个核心考点。5.2 分布式事务方案的选型逻辑分布式事务方案的回答核心不是把所有方案都背一遍而是说清楚“什么场景该用什么方案”。我建议按下面这个思路组织答案强一致性要求极高的短事务比如账户余额操作可以使用事务消息或 TCC 这类方案但要注意两阶段提交2PC这种强一致方案的性能开销大、协调者本身是单点风险实际业务中很少直接裸用。大多数业务场景其实允许短暂的不一致推荐基于消息的最终一致性方案。比如订单创建后本地事务里先写订单表同时往本地消息表里写一条待发送消息事务提交后通过后台任务把消息投递到 MQ下游库存服务消费消息后扣减库存。如果消费失败就靠 MQ 的重试机制不断重试直到成功。这个方案的好处是不依赖全局事务性能可控坏处是需要处理消息重复消费所以要配合幂等。TCCTry-Confirm-Cancel方案比较适合资金类、强管控类业务但实现成本很高每个业务操作都要写预留、确认、取消三个动作一般公司业务体量不到一定程度不建议上。这样答下来面试官会觉得你不光知道概念还能根据业务场景做权衡。最后可以补充一句“拍板选型时我会考虑团队对方案的熟悉程度、现有中间件支持情况、业务对数据不一致的容忍度这三件事而不是单看某个方案的理论优劣。”这种务实态度会非常加分。5.3 幂等、分布式 ID 与跨服务追踪微服务面里还有几个高频小问题单独说一下。幂等是必须答好的为什么需要幂等因为网络重试、MQ 重复投递、前端重复提交都会导致同一操作被执行多次。怎么做幂等常用方案是让每次业务请求携带一个全局唯一业务流水号服务端用唯一索引或 Redis 的 setnx 记录这个流水号处理前先校验重复已处理过的请求直接返回成功。或者用数据库表的唯一约束来兜底。我实际项目里最常用的是“唯一业务键 Redis 记录 数据库唯一索引”双重保障因为单靠任何一层都可能偶发失效。分布式 ID 可以回答这几个主流方案数据库自增主键不适合做全局 ID因为单点有压力、Redis 自增有持久化风险、号段模式预先取一段 ID 放内存使用性能好、雪花算法时间戳 机器 ID 序列号高性能且趋势递增。面试时重点说雪花算法的结构并指出它的时钟回拨问题以及生产环境里通常会用哪种方式规避这就够了。链路追踪也是微服务方案的常见题。可以简单说明一次跨服务请求会生成一个全局 TraceId每经过一个服务产生的内部调用会生成 SpandId这些 ID 在日志中传递并采集到一个追踪系统中就能还原一条完整调用链路。回答时加上一句“我在项目里用拦截器在入口生成 TraceId通过 HTTP 头在服务间传递业务日志里统一打印排查跨服务慢请求时就靠它串起来”会让面试官觉得你的方案是实际跑过的。6. 代码面与线上诊断决定 offer 级别的一小时最后这一小时往往决定你能不能拿到 offer以及拿到的是什么级别。它包含手写代码、场景设计和线上问题排查三类题算法功底固然重要但更关键的其实是答题的思维框架。6.1 手写代码的评分点边界、效率和意识很久以前我以为算法面试考的是“能不能做出来”后来自己坐在面试官那一侧才明白评分点其实有三个层次第一层是能不能写出正确代码包括考虑空数组、边界值、溢出等异常情况。第二层是时间复杂度有没有优化意识暴力解和最优解之间面试官会给一个梯度分数。第三层的隐藏分是会不会和面试官沟通解题思路、能不能说明自己代码的优缺点、对空间和时间做权衡。这里有个经验之谈不要拿到题就闷头写。你先跟面试官说清楚自己的思路用普通例子推演一遍再开始编码这个过程本身就展示了你解决复杂问题的拆解能力。如果你能主动分析“如果用哈希表空间复杂度会到 O(n)但当数据量小的时候这反而是最简单可维护的做法”面试官会觉得你有工程取舍思维这比默写出一个标准最优解更打动他。6.2 一个线上 OOM 问题的完整排查路径线上问题排查题本质上考的是“有没有一套稳定的方法论”。我举一个真实的排查思路作为模板这类题可以照搬这个框架假设线上服务报 OutOfMemoryError堆内存一直在涨。我不会直接去翻代码而是按下面几步走保留现场。第一时间把堆 dump 文件拉下来保留日志和监控数据然后处置措施可以先重启或摘流量恢复服务。初步分析。用内存分析工具打开 dump查看大对象和留存对象分布定位占用内存最多的类。追踪引用链。顺着这些大对象的引用找到它被谁持有。常见的结果是某个静态集合一直往里放对象没清理或者 ThreadLocal 值没有被 remove或者缓存框架没有设置过期策略。结合业务逻辑确认根因。比如我发现是一个定时任务每次全量拉取数据放到内存做处理数据量涨到一定程度就溢出。修复方式改成批量处理 分批释放引用。复盘与预防。设置 JVM 参数发生 OOM 时自动导出 dump监控堆内存使用率和 GC 频率建立告警代码评审时加入对大集合、全局缓存的使用约束。面试时把这个流程完整讲出来哪怕不是你真实经历过的面试官也能看出你有排查意识。如果刚好是真实经历再补一个“花了多久定位、中间走弯路没有”的细节效果更好。6.3 系统设计题的回答框架可扩展、不炫技系统设计题比如“设计一个秒杀系统”“设计一个短链接服务”“设计一个扫码登录流程”很多没准备过的人当场就懵了。我的建议是无论什么题都按这四步走先澄清需求“用户量多大峰值 QPS 多少数据量级多大一致性要求多高”大多数设计题的信息都是不完整的会提反问本身就是加分行为。画整体架构客户端、网关、业务服务、缓存、数据库、消息队列每层的职责是什么请求的流转路径是什么。拆解关键难点哪些点是性能瓶颈、一致性风险点、可用性隐患针对每个难点给出具体应对方案。比如秒杀系统的核心难点是“流量集中导致库存扣减压力”应对方案是前端限流、网关层限流、Redis 预扣库存、MQ 异步落库、数据库乐观锁更新。说明方案的取舍这个设计在极端情况下会出现什么问题比如 Redis 和数据库库存不一致怎么办。能主动说出自己方案的缺陷和补偿手段面试官会觉得你有架构思维。会犯的错通常有两个一上来堆高深组件仿佛不用消息队列和分库分表就显得不专业或者完全不考虑成本数据量才几百万就设计了一整套分库分表方案。正确的状态是“设计跟着规模走”。7. 面试之外几次被问倒之后我总结的复习方法文章最后我不做什么总结就说说我自己被问倒过几次之后总结出的一套复习节奏。第一个感受是不要按目录顺序从头看到尾。正确做法是先摸底拿近三年的真实面试题对自己做一次模拟哪一块答得不顺畅就集中攻哪一块。比如你发现事务隔离级别说不清就一次性把 MySQL 事务、锁、MVCC 这一条线全部打通而不是今天看点 Java 集合、明天看个 Redis、后天背两道算法题。第二个感受是每个知识点都要准备到“能讲给别人听”的程度。分享一个我一直在用的自测法——“电梯讲解法”假设你在电梯里遇到一位同事要求你在三分钟内把一个技术点讲清楚如果中间有卡壳、有“这个地方我还没想明白”那就说明你掌握得还不够。这种自测方式比做笔记管用得多。最后一个建议是面试不是终点它其实是一次极好的知识体系体检。每次面试后把没答上来的问题记下来回去查资料补齐你会发现每一次面试后自己的能力都会明显跳一小步。多面几次之后你的知识网络会从碎片化变得结构化这也是我从最初被问得有点懵到后来能比较从容地应对各种深度追问的真实路径。希望你下一次面试也能体会到这种“终于心里有底”的感觉。
阅读完成 · 觉得有帮助?