
前阵子有个准备跳槽的同事问我华为OD的技术面到底考什么我看网上全是经验帖越看越慌。我干脆把Java开发方向最近被反复问到的几类题整理了一遍从机试到技术面、从手撕代码到基础八股顺带把我自己踩过的坑也写进去。这篇先出第一期围绕华为OD机试和Java技术面最核心的考点展开目标是让准备OD机考和Java面试的人都能拿去做对标复习——你不需要把面经全背下来但至少要清楚每一类题背后的考察逻辑以及怎么在有限时间内把分拿稳。1. 华为OD面试到底在考察什么流程拆解与备考思路华为OD的招聘流程和大厂社招不太一样它更看重标准化筛选和项目匹配度。很多第一次接触OD的人一上来就刷题刷到一半才发现真正卡人的不是难度而是对流程和信息的不熟悉。我这里先把完整流程和各环节的考察重点说清楚。1.1 完整面试流程与各环节的送分/送命属性一般来说华为OD的流程是这样走的投递简历 → 机试上机考试→ 性格测评 → 技术一面 / 技术二面 → 主管面 → HR面 / 综合面之后走审批和定级。不同部门、不同地区会有细微差别但大体就是这个结构。简历筛选这一环主要看你的技术栈和工作年限Java开发方向的核心是项目经历和框架使用情况有Spring Boot、微服务、高并发相关的项目经验会明显加分。机试这是第一道硬门槛也是最容易莫名其妙被刷的环节。很多人算法基础还行但因为没有提前熟悉在线评测平台的操作和出题风格导致时间分配失误第一题都没AC。性格测评别不当回事超过一半的人是在这里被系统标记的。它不是考试但会通过大量重复题目判断你的抗压性、团队协作倾向和风险偏好。如果你前面的题答得太完美后面突然出现矛盾选项很容易被判为不真实。技术面一般一到两轮以手撕代码 Java基础八股 项目深挖为主。项目深挖往往会追到你不熟悉的细节比如你项目里用了Redis面试官会追问缓存穿透、缓存击穿、缓存雪崩以及你当时的存储结构设计。主管面 / 综合面重点考察沟通能力、学习能力、对加班和驻场开发的态度。这一轮技术比重下降但会考察你对华为文化的理解和岗位预期。这里要提醒一下OD的机试成绩会直接关联到你的定级不是说过了就行。分数越高后续技术面可能给你匹配的项目也越好甚至影响起薪区间。所以备考的重点不是能不能过线而是尽量拿高分。1.2 机试命题逻辑与评分规则先搞清楚游戏规则再动手华为OD机试一般是在线评测系统上完成的限时150分钟左右共三道题分值通常是100分、200分、300分总分600分通过线一般在150分左右但具体以当次通知为准。这里最核心的信号就是你不需要三道题全对才能过线但第一题和第二题基本是能不能过线、能不能拿高分的关键。第一题典型是模拟题或字符串题考察基本功第二题开始上难度常见的有动态规划、DFS/BFS、双指针之类的中间难度题第三题则是综合题经常涉及复杂模拟、图论或多种数据结构的组合使用考察的是代码组织能力和边界处理能力。建议大家做题顺序严格按 1 → 2 → 3 来第一题必须稳稳AC第二题至少拿到80%的分数第三题即便做不出来也要把暴力的部分分写上。很多人在第三题上死磕了一个多小时回头发现第二题简单思路被自己忽略了这才是最可惜的。机试一般支持C、Java、Python我强烈建议Java方向的同学直接选Java因为你后续技术面也是Java熟练度更高。但要注意在线评测的Java运行效率确实不如C遇到大数据量题目时尽量用StringBuilder代替String拼接能用数组就不要硬套Map这些细节会在判分时体现出来。还有一点容易忽略机试的输入输出格式非常严格经常有多组输入字符串中含空格整数范围超int这类坑。平时的练习里至少要有10%的时间单独训练输入输出解析别让代码逻辑写对了却因为读取格式不对而丢掉AC。2. 上机考试真题解析三道题的分层破题思路这里我不写具体标准答案式的背题而是把机试里最常出现的三类题型各拆一道讲清楚破题点和实现思路。下面两组题目会反复在OD机试中出现类似的变体。2.1 第一题字符串处理类真题怎么稳稳拿满分先说一道出现频率极高的第一题类型给定一个字符串要求去除重复字符并按字典序输出。类似变体包括统计字符出现次数、反转字符串、判断回文、字符串转数字等。这类题核心考点是字符处理是否熟练、是否了解Java字符串操作的性能特征。典型的思路是用一个HashSet去重然后收集到List里排序但机试为了效率也可以直接用int[26]或int[128]的数组做字符计数边扫描边标记最后按字符顺序输出。直接看代码public static String removeDuplicateAndSort(String input) { if (input null || input.length() 0) { return ; } boolean[] visited new boolean[128]; for (char c : input.toCharArray()) { visited[c] true; } StringBuilder sb new StringBuilder(); for (char c a; c z; c) { if (visited[c]) { sb.append(c); } } return sb.toString(); }这个写法有几个好处第一用boolean数组代替Set省去装箱拆箱的开销第二输入的范围如果限定在小写字母直接遍历a到z天然有序第三StringBuilder避免频繁字符串拼接。如果题目要求保留原顺序而不是字典序就改成LinkedHashSet或者直接用boolean数组加一次追加遍历思路是一样的。做题时我习惯先写一个朴素版本保证正确性再考虑优化。第一题只要逻辑清晰、边界条件处理好空字符串、null、大小写混合基本都能AC。2.2 第二题动态规划/搜索类真题套路化拆解第二题最常见的是动态规划。这里拿爬楼梯的升级版举例——一个人爬楼梯每次可以走1级或2级台阶问走到第n级有几种走法。这是最原始版本OD机试里更多变体会变成每次可以走1级、2级或3级或者某些台阶不能停留考察的还是状态转移的思想。核心DP代码public static int climbStairs(int n) { if (n 2) { return n; } int[] dp new int[n 1]; dp[1] 1; dp[2] 2; for (int i 3; i n; i) { dp[i] dp[i - 1] dp[i - 2]; } return dp[n]; }有些同学会问这不就是斐波那契吗对本质就是斐波那契但重点在于你要能灵活迁移。比如题目改成一次可以走1~k级你就会发现dp[i] dp[i-1] dp[i-2] ... dp[i-k]再比如加了限制第m级台阶不能踩那初始化时dp[m] 0即可。这种由浅入深的思考方式才是面试官想看到的。如果遇到的是DFS/BFS类问题比如岛屿数量矩阵路径或者迷宫最短步数核心套路就是四方向遍历、visited数组标记、递归边界判断。这类题在机试中占的比重大建议提前把DFS的模板写到条件反射的程度不要现场想。2.3 第三题综合模拟题不求全对但求有分第三题经常是复杂业务模拟例如多个任务按优先级和到达时间调度输出每个任务的完成时间或者一个矩阵地图上有多个道具要求规划路径收集道具后到达终点。这类题信息量很大读题本身可能就要花十分钟。我的策略是先花5分钟把题目需求用伪代码写下来理清实体和操作再看数据范围决定解法。如果没思路直接写暴力版本哪怕超时也能拿到部分分——OD机试是按测试用例给分的暴力过几个小数据用例比你交白卷强得多。举个例子如果第三题是给定一串进程的到达时间和执行时长模拟非抢占式调度输出平均等待时间你完全可以先用优先队列维护当前已到达进程的执行时间每次取执行时间最短的进程执行。这种用PriorityQueue模拟的方式代码短思路清晰即使不是最优解也能覆盖绝大多数用例。PriorityQueueint[] pq new PriorityQueue((a, b) - a[1] - b[1]); // 按执行时间2.4 机试刷题策略如何在有限时间拿到最高分机试备考不是刷得越多越好而是按题型分类击破。按我的经验合理的刷题分配是40%的时间刷字符串/模拟题35%刷动态规划和搜索25%刷贪心、双指针、栈队列和常见数据结构题。刷题平台优先选牛客网的华为OD真题库和LeetCode热题100因为OD机试的题目风格和LeetCode不完全一致牛客的题型更贴近实际的在线评测环境。每天保持两道题的量一道简单巩固基础一道中等难度锻炼思维周末做一次完整的模拟机试150分钟三道题。这样坚持三周通过机试基本没问题。在模拟时尤其要练写代码的速度因为第一题往往不难但如果你在输入输出解析上浪费了20分钟后面第二题的思考时间就被压缩了。3. 技术面手撕代码与Java八股高频考点实录通过机试后技术面才是真正拉开差距的地方。技术面一般分成三个环节自我介绍、手撕代码、基础八股和项目问答。Java方向的考题通常不会太偏但会在基础概念上往深处挖比如问HashMap的原理时很多同学只背了数组链表就答完了但面试官后面还会追问红黑树的引入条件、扩容时的rehash、JDK 8为什么用尾插法。3.1 手撕代码环节排序与链表是重灾区技术面的手撕代码题量不大通常一到两道但要求边写边说思路。高频题目是手写快速排序、链表反转、合并两个有序链表、判断链表是否有环。我建议把所有基础排序都练到闭眼能写因为面试官很可能会在你写完快排后追问时间复杂度怎么来的最坏情况是什么。手写一个链表反转public ListNode reverseList(ListNode head) { ListNode prev null; ListNode curr head; while (curr ! null) { ListNode nextTemp curr.next; curr.next prev; prev curr; curr nextTemp; } return prev; }这类题不考智商考熟练度和代码手感。写的时候要注意边界的引用传递别把链表写断开同时嘴里要同步说出当前节点指向pre然后移动指针这样的过程。面试官很在意你能不能把思路讲清楚而不仅仅是默默写完。3.2 Java容器源码考点从HashMap到ConcurrentHashMapJava容器是OD技术面的必考区尤其HashMap。一个完整的HashMap答案应该包含五层递进底层结构JDK 8 是数组链表红黑树数组的每个位置叫桶。put流程计算hashkey.hashCode()高低位异或、找桶下标、判断是否为空、遍历链表找相同key、判断是否需要树化链表长度≥8且数组长度≥64、插入后判断容量是否超阈值触发扩容。扩容机制默认初始容量16负载因子0.75扩容为原来的2倍元素重新散列。为什么用红黑树链表过长时查询退化为O(n)红黑树把查询降到O(logn)。线程安全问题HashMap不是线程安全的多线程put可能导致死循环JDK7头插法或数据丢失。在此基础上面试官大概率会追问ConcurrentHashMap。JDK 8的ConcurrentHashMap用了CAS synchronized锁粒度细到单个桶读操作不加锁依赖volatile保证可见性。回答的时候可以把分段锁和CASsynchronized做个对比说明JDK 8为什么放弃分段锁。这里有个经验之谈答容器题时不要一上来就背源码。先说我从底层结构、插入流程、扩容、线程安全四个角度回答然后按顺序展开。面试官会默认你有清晰的逻辑哪怕有小细节记错了整体印象也不会差。3.3 JVM与并发考点从内存模型到锁升级JVM和并发在OD技术面里的比重不如容器但几乎每次都会被点到。JVM的常问题是Java内存区域有哪些什么是类加载的双亲委派机制GC如何判断对象可回收你项目里有没有调过JVM参数。关于内存区域要把线程私有和线程共享分清楚线程私有的是程序计数器、虚拟机栈、本地方法栈线程共享的是堆和方法区JDK 8改成元空间。类加载的双亲委派简单的理解就是先让爸爸加载加载不了自己才上好处是避免核心类被重复加载。并发方面最常问的是synchronized和ReentrantLock的区别、volatile的作用、线程池的参数和执行流程、锁升级过程。锁升级这个考点很典型无锁 → 偏向锁 → 轻量级锁 → 重量级锁。很多人搞混的是偏向锁是不是一定比轻量级锁好实际上偏向锁适合只有一个线程访问同步块的场景一旦出现竞争就升级。我建议准备一个自己项目里的并发场景比如订单号生成、库存扣减用来回答你项目中怎么处理并发这类问题。单纯背AQS、CAS的理论定义远不如一个真实场景让人信服。3.4 数据库与Spring考点看似基础实则深挖Java开发方向的技术面一定绕不开MySQL和Spring。MySQL最常考的包括索引为什么用B树、聚簇索引和非聚簇索引的区别、事务的ACID、事务隔离级别、MVCC原理、一条SQL执行很慢怎么排查。这里要特别说一下B树面试官往往期待你先回答和B树的区别而不是直接说B树快。正确的对比思路是B树数据只在叶子节点非叶子节点只存索引所以树更矮、IO更少叶子节点有链表指针适合范围查询和排序B树的每个节点都存数据树相对更胖范围查询需要回溯。Spring常问的是IOC和AOP原理、Bean的生命周期、循环依赖怎么解决、事务失效的场景。其中事务失效是近年来的热点常见场景有方法非public、类内部调用this调用、异常被catch了、数据库引擎不支持事务。回答这类题如果能结合一次真实的Bug经历含金量远超背诵。4. 容易被问翻车的Java基础细节题那些面试官喜欢挖的坑有时候技术面难倒人的反而不是高深的并发和JVM而是最基础的Java细节。这类题看起来简单但越简单越能暴露一个开发者的功底。我总结几个被反复问到的坑题。4.1 值传递与引用传递一句话就能暴露基础这是Java面试最经典的送命题之一。很多人一上来就说基本类型是值传递对象是引用传递这句话并不完全对。Java只有值传递只是对象传递的是引用地址的值。看这段代码public static void change(String str) { str world; } public static void main(String[] args) { String str hello; change(str); System.out.println(str); // 输出 hello }这里String表面上被修改了实际上没变因为方法参数复制的是引用而重新赋值str world只是让方法内的引用指向了新的常量池对象外部的引用不受影响。如果是修改对象的字段比如Person对象里setName因为两个引用指向同一个对象外部就能看到变化。回答这道题的核心就一句话Java只有值传递引用类型的值也是值地址值。如果能举出String和Person对象的对比例子整道题就答得很圆满了。4.2 字符串与一道题引出JVM常量池再来看一道几乎必考的题String s1 hello; 和 String s2 new String(hello); 用比较结果是什么很多人知道答案是false但说不清为什么。原因在于字面量字符串会被放入JVM的字符串常量池s1直接指向常量池对象new String会强制在堆里创建新对象s2指向堆对象。两个引用指向不同对象所以结果是false。但s1.equals(s2)是true因为equals比较的是内容。接下来面试官还会追加如果把代码改成String s3 s1.intern();然后比较s3 s1答案是true因为intern()会把字符串对象提交到常量池如果常量池已有相同内容的字符串就返回该常量池对象的引用。如果能顺着这个思路讲到字符串常量池在JDK 7之后被移到了堆里面试官基本上就满意了。我面试时还遇到过一种变体String s4 he llo;与s1 s4比较结果也是true因为编译期常量折叠。换成String suffix llo; String s5 he suffix;那么s5 s1是false因为suffix是变量拼接发生在运行期。这种题不难但确实能区分背过八股和真懂原理的人。4.3 面向对象设计重载、重写与抽象类和接口的边界Java面向对象的基础题总喜欢从重载和重写切入。重载是同一个类中方法名相同、参数列表不同编译期决定调用哪个重写是子类重新实现父类方法方法签名必须一致运行期决定调用哪个。一个记巧重载看编译重写看运行。再往上延伸就是抽象类和接口怎么选。老生常谈但容易答偏。核心不是背区别表而是说清楚设计语义抽象类是is-a关系强调共性接口是can-do关系强调能力。Java 8之后接口可以有default方法所以两者在功能上越来越接近但单继承和多实现仍然是最本质的区别。我在面试中还遇到过这样的设计题如果要设计一个支付模块有微信、支付宝、银行卡你会用抽象类还是接口较好的回答是先定义一个Payment接口包含pay和refund方法再抽一个抽象类AbstractPayment公共方法如生成订单、记录日志写在里面不同支付方式继承抽象类并实现各自逻辑。这样既统一了入口又复用了公共代码。4.4 Java 8新特性Lambda、Stream 与函数式接口Java 8新特性在OD技术面里有时作为加分项有时作为你项目里有没有用过这些来问。最常见的考点是Stream的中间操作和终端操作以及Optional的用法。一个典型的例子从员工列表中筛选出工资大于8000的员工按工资降序排序只取前三个名字。ListString result employees.stream() .filter(e - e.getSalary() 8000) .sorted(Comparator.comparing(Employee::getSalary).reversed()) .limit(3) .map(Employee::getName) .collect(Collectors.toList());这个代码几乎可以应对所有Stream怎么用的问题。面试官如果追问filter和sorted哪个先执行高效要注意sorted之前先filter可以减少排序元素的数量所以filter先执行更优。还有一点collect(Collectors.toList())是终端操作流是惰性的没有终端操作不会真正执行。很多人容易忽略的是Optional的语义。使用Optional的重点是用map、orElse、orElseGet这类方法而不是直接调用get()否则就失去了防NPE的意义。如果你能在项目里举一个用Optional重构空指针判断的例子这道题就非常加分。5. 备考与面试过程中的实战经验时间规划、心态调整与复盘方法技术能力之外备考节奏和临场心态同样影响结果。我见过算法底子不错但因为疏于模拟而超时的人也见过项目经历很普通但准备充分、表达清晰从而拿到好评的人。这里分享几个实操性强的建议。5.1 机试备考的周期与刷题节奏如果平时工作比较忙我建议按四周规划太长容易拖沓太短不足以形成肌肉记忆。周期重点每日任务第一周字符串、数组、模拟题每天2~3道简单题强化输入输出处理第二周动态规划、DFS/BFS、双指针每天2道中等难度题按题型分类刷第三周栈/队列/哈希/贪心每天1道中等1道困难重点看题解思路第四周全真模拟每两天一次整套机试模拟严格限时第四周的全真模拟很关键。做模拟时我会刻意给自己加压如果一道题20分钟还没有完整思路果断跳过先做后面的题最后再回头补。机试的150分钟过起来很快前面时间分配不好后面连读题时间都不够。5.2 面试中遇到不会的题怎么办技术面最忌讳的不是不会而是沉默。遇到不会的题目最好的处理方式是先说这道题我首先想到的思路是XX但因为XX原因可能不是最优然后边说边写把部分思路展示出来。哪怕是暴力解法面试官也能看到你的思考路径。举个例子如果面试官让手写一个最长回文子串你一时想不起动态规划的状态转移方程没关系直接说我先用中心扩展法试试遍历每个字符作为回文中心向两边扩展这就是正确答案的常见替代方案。即便你没完全写对但思路清晰、边界处理得当也远比我不会要好。遇到八股题答不上来时别急着放弃可以用我项目中遇到的场景是……做一个过渡。比如面试官问AQS的实现原理你如果只记得CLH队列和state变量可以先从我在项目中用过ReentrantLock它的底层就是AQS切入至少把话题引到自己熟悉的角落。5.3 考后复盘把每场面试变成自己的知识库我习惯每场面试结束后立刻做一次复盘时间不超过半小时但收获很大。复盘模板大概是这样面试官问了哪些题哪些答得流畅哪些卡壳了卡壳的原因是知识点缺失还是紧张导致表达混乱把不会的题按基础语法 / 容器 / JVM / 并发 / 数据库 / Spring / 算法分类记录。三天后把这些题重新做一遍确认真的记住了而不是看一遍就过。这个方法看起来很朴素但坚持下来你会发现自己对Java知识体系的掌握会越来越系统。尤其是机试里的错题一定要重新手写一遍因为很多题看答案会了和自己AC之间差着十万八千里。最后再分享一点我个人的体会华为OD面试的整个周期可能拖得比较长从投递到拿offer有时候要一个月以上中间不要因为一轮表现不好就自我怀疑也不要因为拿到了口头offer就彻底放松。把每一次面试都当成一次项目检测哪里薄弱补哪里这个过程本身就很值钱。下一期我打算整理一下OD技术面里的项目深挖真题尤其是Spring Boot和微服务相关的追问套路到时候见。