双非本华为OD:1年开发+1年空窗,从测试岗到Java开发面经
个人情况
深圳大学计算机本科(双非),1年小公司Java后端开发经验(主要做电商平台订单模块),后因家庭原因空窗1年。2025年3月首次华为OD机考未通过,5月通过内部推荐开始系统备战。8月成功通过机考(Java开发岗),但技术面被刷,转岗测试。10月测试岗面试通过,部门急需Java开发,直接转岗,11月拿到Offer,12月初入职。整个流程历时9个月,比常规长,但最终达成目标。
资格面(10/18)
-
自我介绍
“我是深圳大学计算机专业,1年Java开发经验,专注电商平台订单系统。空窗期用于系统化学习,重点补足算法和分布式知识。这次面试希望能将积累落地到华为的业务中。” -
离职原因与空窗期
“离职因家庭事务需回老家处理,空窗期未放弃技术学习:每天2小时刷********、重学《Java并发编程实战》,并完成2个Spring Boot微服务项目(含Redis缓存、MySQL分库分表)。” -
为什么选择华为OD?
“华为的工程规范和技术深度吸引我,OD模式能快速接触真实业务,且部门对双非背景友好,符合我‘快速成长’的诉求。” -
技术栈与学习准备
“Java核心(集合、并发)、Spring Boot、MySQL优化、Redis缓存。学习路径:先刷《剑指Offer》算法,再重学JVM,最后实战项目。重点补了空窗期缺失的分布式知识。” -
反问
“部门目前主要技术栈是什么?是否有新人导师机制?”
技术一面(11/02)
测试相关
-
测试流程参与
“开发视角:需求评审时提出边界条件(如‘订单金额为0’);编码阶段写单元测试;联调时用Postman验证接口。测试视角:编写测试用例覆盖异常场景(如超时、重复提交),参与回归测试。” -
模块关联梳理
“通过画时序图和数据库ER图理清关联。例如,订单模块依赖库存模块,我主动和库存组确认了‘库存扣减逻辑’和‘超卖兜底方案’,避免后期联调阻塞。” -
接口测试方法
“用Postman+Newman跑自动化脚本,覆盖正例/反例;用Arthas监控接口响应时间;模拟高并发用JMeter(如500并发下单测试TPS)。” -
用户视角发现的问题
“项目中发现‘用户用优惠券下单后,退款时优惠券未回滚’。原需求只考虑了订单状态,未覆盖优惠券状态。我建议增加‘优惠券状态机’,并推动产品补充需求文档。” -
Linux命令
export PATH=$PATH:/opt/myapp(配置环境变量)df -h(查看磁盘空间)sed -i 's/old/new/g' file.txt(全局替换)find / -name "config.yml"(按文件名查找)
项目相关
-
核心模块
“订单中心:支付回调、库存扣减;用户中心:优惠券核销;数据同步:订单数据异步同步到ES(非实时,因实时同步会拖慢主流程,仅在促销期间用实时方案)。” -
实时同步场景
“实时同步:支付状态同步(需秒级响应);非实时:订单日志同步(可容忍5分钟延迟,用RabbitMQ队列异步处理)。”
手撕代码
题目: 找出数组中最大的子集,满足任意两数 a % b == 0 或 b % a == 0。
示例: 输入 [3,6,9,12] → 输出 [3,6,12](或 [3,9,12])。
思路:
- 排序数组(从小到大,确保小数能整除大数)
- 动态规划:
dp[i]表示以nums[i]结尾的最大子集长度 - 遍历
j < i,若nums[i] % nums[j] == 0,则dp[i] = max(dp[i], dp[j]+1)
代码(Java):
public List<Integer> largestDivisibleSubset(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
int[] dp = new int[n];
int[] prev = new int[n];
Arrays.fill(dp, 1);
Arrays.fill(prev, -1);
int maxIdx = 0;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] % nums[j] == 0 && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
prev[i] = j;
}
}
if (dp[i] > dp[maxIdx]) maxIdx = i;
}
List<Integer> result = new ArrayList<>();
while (maxIdx != -1) {
result.add(nums[maxIdx]);
maxIdx = prev[maxIdx];
}
Collections.reverse(result);
return result;
}
技术二面(11/06)
项目相关
-
项目难点
“高并发下单时库存超卖。解决方案:Redis+Lua原子扣减(DECR命令),并设置库存预警(低于阈值触发消息队列通知运维)。” -
并发与数据量
“日均订单10万,订单表2000万条。处理方案:按用户ID分库分表(ShardingSphere),查询用ES索引加速;并发用Redis分布式锁(Redisson的RLock)。”
手撕算法
题目: 统计用户输入的单词数(含续行符\)。
输入示例:
3
Hello,world\
this is a test.
!@#$%
输出: 4(单词:Hello, world, this, is)
思路:
- 逐行处理,用
StringBuilder合并续行(如Hello,world\→Hello,world) - 用正则
[a-zA-Z]+匹配单词
代码(Java):
import java.util.*;
import java.util.regex.*;
public class WordCounter {
public static int countWords(String[] lines) {
StringBuilder sb = new StringBuilder();
int count = 0;
Pattern pattern = Pattern.compile("[a-zA-Z]+");
for (String line : lines) {
if (line.endsWith("\\")) {
sb.append(line, 0, line.length() - 1); // 去掉续行符
} else {
sb.append(line);
Matcher matcher = pattern.matcher(sb.toString());
while (matcher.find()) count++;
sb.setLength(0); // 重置
}
}
return count;
}
}
测试相关
-
测试用例设计
- 边界:输入空行、仅
\、纯标点(如!@#) - 异常:
\独占一行(如line = "\\"→ 应忽略) - 正常:
Hello,world\→ 合并为Hello,world
- 边界:输入空行、仅
-
malloc接口测试- 边界:
size=0(应返回NULL) - 异常:
size=10^9(内存不足) - 功能:分配后写入数据,验证内容正确
- 边界:
Java八股
-
Java锁
synchronized(对象锁/类锁)、ReentrantLock(可中断、公平锁)、StampedLock(读写锁优化) -
线程等待方法
wait()(Object类)、join()(线程等待)、await()(Condition) -
sleepvswait
sleep不释放锁,wait释放锁并进入等待池
加面(11/10)
Java八股
-
Redis使用
“订单缓存(Redis String)、热点商品缓存(Redis Hash)、分布式锁(Redisson)。” -
缓存一致性
“先更新DB,再删除Redis(异步删除,防误删);双写一致性用MQ补偿(如RabbitMQ)。” -
SQL慢查询
“原因:全表扫描、索引失效。处理:EXPLAIN分析,加索引(避免重复索引、覆盖索引)。” -
索引注意事项
“字段选择性高、避免索引过多、覆盖索引优化查询。” -
ArrayListvsLinkedList
ArrayList随机访问快(数组),LinkedList插入删除快(链表) -
线程安全集合
HashMap不安全;Hashtable用synchronized;ConcurrentHashMap用分段锁(JDK8+ CAS+红黑树) -
单例模式
“双重检查锁(volatile保证可见性):private volatile static Singleton instance;”
工厂模式:在订单服务中用OrderFactory统一创建订单类型(如普通订单、优惠券订单) -
接口 vs 抽象类
接口:多继承、行为契约;抽象类:共性代码复用、状态维护 -
static方法区别
static方法不能访问非静态变量,不能重写 -
其他修饰符
final(不可变)、private(封装)、protected(继承访问)
手撕算法
题目: 设计租房系统RoomManager。
public class RoomManager {
// 用HashMap存房源(key: id, value: Room对象)
private Map<Integer, Room> rooms = new HashMap<>();
public boolean addRoom(int id, int area, int price, int rooms) {
if (rooms.containsKey(id)) {
rooms.get(id).update(area, price, rooms);
return false;
} else {
rooms.put(id, new Room(area, price, rooms));
return true;
}
}
public boolean deleteRoom(int id) {
return rooms.remove(id) != null;
}
public int[] queryRoom(int area, int price, int rooms) {
List<Room> list = rooms.values().stream()
.filter(r -> r.area >= area && r.price <= price && r.rooms == rooms)
.sorted(Comparator.comparingInt(Room::getPrice).thenComparingInt(r -> -r.area))
.collect(Collectors.toList());
return list.stream().mapToInt(r -> r.id).toArray();
}
static class Room {
int id, area, price, rooms;
Room(int area, int price, int rooms) {
this.area = area; this.price = price; this.rooms = rooms;
}
void update(int area, int price, int rooms) {
this.area = area; this.price = price; this.rooms = rooms;
}
}
}
主管面(11/11)
-
空窗期解释
“家庭原因需回老家处理,但未放弃学习:系统重学JVM、刷了200+算法题。现在更清楚职业方向,华为是首选。” -
开发工作细节
“在上家公司,我主导了订单模块重构:从单体拆微服务,用Spring Cloud,性能提升3倍。” -
印象深刻的Bug
“支付回调重复触发。原因是没做幂等校验,用Redis+UUID解决(ORDER_ID作为唯一键)。” -
学习方法
“每天1小时深度学习(如JVM源码),周末实战项目。面试准备3个月,重点补足分布式和算法。” -
学习项目
“用Spring Boot+Redis实现了一个简易秒杀系统(含库存扣减、防超卖),代码已开源到GitHub。” -
适应性
“入职后会先熟悉代码库,参与Code Review;用Git分支管理,每天同步进度到团队。” -
反问
“团队目前技术栈是Spring Cloud Alibaba吗?新人有定期技术分享吗?”
关键经验总结
- 空窗期不是劣势:用“系统性学习”和“实战项目”证明能力,避免模糊描述。
- 转岗核心逻辑:测试岗面试时强调“开发技能”,主动提“能快速转Java开发”。
- 算法准备:华为OD必考,重点练动态规划、字符串处理(如续行符)。
- Java八股:锁、集合、JVM是高频考点,必须手写代码(如单例模式)。
#华为OD##深圳##东莞##华为##gap#最后建议:面试前务必用********模拟手撕题,避免现场卡壳。华为看重“工程能力”,回答时多结合项目细节!
查看7道真题和解析