java开发面试-AI Coding速成

我会按这几个层次来讲:

  1. 面试官怎么出题

  2. 你第一反应该怎么说

  3. 你每一步怎么要求大模型

  4. 大模型可能怎么回答

  5. 你怎么人工纠偏

  6. 最后怎么把这个过程讲得让面试官满意

我用一个很典型、很适合 AI coding 的题:

实现一个工单处理系统

要求先按"面试现场 + 你用 AI 协作开发"的场景来模拟。


题目设定

面试官说:

> 现在有一个工单处理系统,支持创建工单、分配工单、更新工单状态、查询工单列表。

> 你可以用 AI 辅助你完成,但我更关注你的过程,不太关注你最后写得多完整。

> 你边做边讲你的思路。

这时候,面试官其实在看的是:

  • 你会不会先收需求

  • 你会不会把问题结构化

  • 你是不是让 AI 受控地工作

  • 你有没有验证意识

  • 你会不会纠偏


一、你第一句话怎么说

这个很重要,别一上来就开写。

你应该这样说:

> 我先不急着直接生成代码,我会先把需求和边界确认一下,再让模型先产出一个轻量设

> 计,再拆分任务逐步实现。这样更可控,也方便我边做边校验。

这句话很加分,因为它说明你有流程感。

然后你开始澄清需求。


二、第一步:需求澄清

你应该问什么

你可以问面试官:

> 我先确认几个边界:

>

> 1. 这是做成一个内存版核心类即可,还是要模拟完整后端接口?

> 2. 工单状态是否有固定流转,比如 CREATED -> ASSIGNED -> PROCESSING -> DONE ->

> CLOSED?

> 3. 分配工单时是否允许重复分配?

> 4. 查询列表是否只需要全部查询,还是需要按状态/处理人过滤?

> 5. 现场实现我先按单机内存版写,是否可以?

假设面试官回答:

> 可以按 Java 内存版写,不需要 controller 和数据库。

> 需要状态流转校验。

> 查询先支持全部列表和按状态过滤。

> 重点看你的抽象和流程。

这时候你就可以进入 AI 协作了。


三、第二步:你怎么给大模型下第一条指令

这里最关键的是:

先让 AI 出设计,不要先写代码

你对模型的 prompt

你可以这样写:

你现在是一个资深 Java 后端工程师。请先不要写代码,先帮我输出一个轻量设计文档

design.md

题目:

实现一个工单处理系统,支持:

  1. 创建工单

  2. 分配工单给处理人

  3. 更新工单状态

  4. 查询工单列表

  5. 支持按状态过滤查询

约束:

  • 使用 Java

  • 面试现场实现,先做内存版,不接数据库,不写 controller

  • 重点是核心领域建模和 service 设计

  • 状态流转需要校验

  • 代码要尽量简洁,避免过度设计

请输出:

  1. 核心类设计

  2. 数据结构

  3. 状态流转规则

  4. 核心方法设计

  5. 异常处理策略

  6. 测试点

不要输出代码。


四、大模型第一轮可能怎么回答

它大概率会给你这样的内容。

模型回答示例:design.md

design.md

1. 核心类设计

Ticket

表示工单实体,包含:

  • id: Long

  • title: String

  • description: String

  • assignee: String

  • status: TicketStatus

  • createdAt: LocalDateTime

TicketStatus

工单状态枚举:

  • CREATED

  • ASSIGNED

  • PROCESSING

  • DONE

  • CLOSED

TicketService

负责核心业务操作:

  • createTicket

  • assignTicket

  • updateStatus

  • listTickets

  • listTicketsByStatus

2. 数据结构

使用内存 Map<Long, Ticket> 存储工单:

  • key: 工单 id

  • value: Ticket 对象

使用一个自增 long 作为工单 id 生成器。

3. 状态流转规则

允许的状态流转:

  • CREATED -> ASSIGNED

  • ASSIGNED -> PROCESSING

  • ASSIGNED -> CLOSED

  • PROCESSING -> DONE

  • PROCESSING -> CLOSED

  • DONE -> CLOSED

不允许:

  • CLOSED -> 任意状态

  • DONE -> PROCESSING

  • CREATED -> DONE

4. 核心方法设计

createTicket(String title, String description)

创建工单,初始状态为 CREATED。

assignTicket(Long ticketId, String assignee)

给工单分配处理人,若当前状态不是 CREATED,则可根据规则决定是否允许重新分配。

updateStatus(Long ticketId, TicketStatus newStatus)

更新工单状态,需要校验状态流转是否合法。

listTickets()

返回所有工单。

listTicketsByStatus(TicketStatus status)

按状态过滤工单。

5. 异常处理策略

  • 参数非法:IllegalArgumentException

  • 工单不存在:NoSuchElementException

  • 状态流转非法:IllegalStateException

6. 测试点

  • 正常创建工单

  • 正常分配工单

  • 合法状态流转

  • 非法状态流转

  • 查询全部工单

  • 按状态过滤查询

  • 查询不存在工单时异常


五、这时候你不能直接信,你要怎么 review

这一步是面试里最体现水平的地方。

你不能说"好,继续生成代码"。

你要先人工点评。

你应该怎么讲

你可以这样边看边说:

> 这个设计整体方向是对的,实体、枚举、service 的划分也比较适合现场题。

> 但我会做两个调整。

> 第一,description 不是题目强需求,如果时间有限我会先去掉,避免非核心字段分散注

> 意力。

> 第二,分配逻辑里提到"是否允许重新分配",这里需求没明确,我会先约束成只有

> CREATED 状态可以分配,这样规则更清晰。

这段非常像真实工程师。

然后你对模型补充约束。


六、第二轮:你怎么修设计

你给模型的第二条 prompt

请根据以下修正更新 design.md

  1. 为了适配面试现场,先去掉 description 字段,保留最小必要字段

  2. assignTicket 只允许在 CREATED 状态下执行

  3. 保持实现简洁,不引入 repository、controller 等额外层

请输出修订后的精简设计,不要输出代码。

模型可能返回

design.md(修订版)

核心类

Ticket

  • id: Long

  • title: String

  • assignee: String

  • status: TicketStatus

  • createdAt: LocalDateTime

TicketStatus

  • CREATED

  • ASSIGNED

  • PROCESSING

  • DONE

  • CLOSED

TicketService

  • createTicket(String title)

  • assignTicket(Long ticketId, String assignee)

  • updateStatus(Long ticketId, TicketStatus newStatus)

  • listTickets()

  • listTicketsByStatus(TicketStatus status)

状态规则

  • 创建后初始状态为 CREATED

  • 仅 CREATED 状态允许 assignTicket,分配后变为 ASSIGNED

  • ASSIGNED -> PROCESSING / CLOSED

  • PROCESSING -> DONE / CLOSED

  • DONE -> CLOSED

  • CLOSED 不允许再变更

存储

  • Map<Long, Ticket> tickets

  • long nextId 自增

异常

  • IllegalArgumentException

  • NoSuchElementException

  • IllegalStateException

测试点

  • createTicket

  • assignTicket

  • updateStatus

  • invalid transition

  • listTickets

  • listTicketsByStatus

这时设计就比较干净了。


七、第三步:让模型拆任务,不要一口气写代码

这是控制 AI 的核心手段。

你的 prompt

基于当前 design.md,请输出 task.md

要求:

  • 将实现拆分成最小可执行任务

  • 每个任务应尽量独立,便于逐步实现和验证

  • 按面试现场 coding 场景安排顺序

  • 不要输出代码

模型可能返回:task.md

task.md

  1. 定义 TicketStatus 枚举

  2. 定义 Ticket 类及其字段、构造函数、getter

  3. 在 Ticket 中实现 assignTo 方法

  4. 在 Ticket 中实现 updateStatus 方法及状态流转校验

  5. 定义 TicketService,初始化内存存储和 id 生成器

  6. 实现 createTicket

  7. 实现 assignTicket

  8. 实现 updateStatus

  9. 实现 listTickets

  10. 实现 listTicketsByStatus

  11. 编写简单测试样例或 main 方法验证流程


八、这时候你怎么对面试官解释

你别沉默。

你可以说:

> 我现在先让模型把实现拆成小任务,因为如果一次生成完整代码,面试中很难控制质量,

> 也不方便定位问题。拆小以后,我可以逐步验收。

这句话很加分。


九、第四步:开始让模型按模块生成代码

第一小步:先生成最基础的数据结构

你的 prompt

请只完成 task 1 和 task 2:

  1. 定义 TicketStatus 枚举

  2. 定义 Ticket 类及其字段、构造函数、getter

要求:

  • Java

  • 不要实现 service

  • 不要实现业务方法

  • 保持代码简洁,适合面试现场

模型可能返回

import java.time.LocalDateTime;

enum TicketStatus {

CREATED,

ASSIGNED,

PROCESSING,

DONE,

CLOSED

}

class Ticket {

private final long id;

private final String title;

private String assignee;

private TicketStatus status;

private final LocalDateTime createdAt;

public Ticket(long id, String title) {

this.id = id;

this.title = title;

this.status = TicketStatus.CREATED;

this.createdAt = LocalDateTime.now();

}

public long getId() {

return id;

}

public String getTitle() {

return title;

}

public String getAssignee() {

return assignee;

}

public TicketStatus getStatus() {

return status;

}

public LocalDateTime getCreatedAt() {

return createdAt;

}

}


十、这时你要怎么 review

你要说出检查点。

你可以这样讲:

> 这一步我主要看领域对象是不是最小闭环。

> 现在字段基本够了,初始状态也设成了 CREATED。

> 但我会注意 title 是否需要判空,这里我可能会放到 service 层统一做输入校验,避免

> 实体构造器和 service 重复校验。

这就显得你不是被动接收。


十一、第二小步:生成业务方法

你的 prompt

请只完成 task 3 和 task 4:

  1. 在 Ticket 中实现 assignTo(String assignee)

  2. 在 Ticket 中实现 updateStatus(TicketStatus newStatus)

  3. 需要校验状态流转是否合法

  4. assignTo 只允许在 CREATED 状态下执行

要求:

  • 直接在现有 Ticket 类基础上补充

  • 使用 IllegalArgumentException 和 IllegalStateException

  • 保持实现清晰,不要过度抽象

模型可能返回

public void assignTo(String assignee) {

if (assignee == null || assignee.isBlank()) {

throw new IllegalArgumentException("assignee cannot be empty");

}

if (this.status != TicketStatus.CREATED) {

throw new IllegalStateException("ticket can only be assigned in CREATED

status");

}

this.assignee = assignee;

this.status = TicketStatus.ASSIGNED;

}

public void updateStatus(TicketStatus newStatus) {

if (newStatus == null) {

throw new IllegalArgumentException("newStatus cannot be null");

}

if (!isValidTransition(this.status, newStatus)) {

throw new IllegalStateException(

"invalid status transition: " + this.status + " -> " + newStatus

);

}

this.status = newStatus;

}

private boolean isValidTransition(TicketStatus from, TicketStatus to) {

return switch (from) {

case CREATED -> false;

case ASSIGNED -> to == TicketStatus.PROCESSING || to ==

TicketStatus.CLOSED;

case PROCESSING -> to == TicketStatus.DONE || to == TicketStatus.CLOSED;

case DONE -> to == TicketStatus.CLOSED;

case CLOSED -> false;

};

}


十二、这里出现了一个真实面试里很重要的点:AI 出错了

你看,CREATED -> false 这个实现其实没问题,因为分配不是走 updateStatus,而是走

assignTo。

但面试官可能会追问:

> 那 CREATED -> ASSIGNED 为什么不在状态流转函数里?

这时候你要能讲清楚。

你的回答方式

你可以说:

> 我这里是把"分配"当作一个显式业务动作,而不是纯状态修改,所以 CREATED ->

> ASSIGNED 不通过 updateStatus,而通过 assignTo 触发。

> 这样做的好处是把"赋值 assignee + 更新状态"绑定在一个业务动作里,避免直接调状态

> 更新时漏掉 assignee。

> 如果想做得更统一,也可以把 CREATED -> ASSIGNED 纳入状态机,但那样还要额外约

> 束"进入 ASSIGNED 必须有 assignee"。

这个解释非常好,面试官会觉得你对建模有理解。


十三、第三小步:生成 service

你的 prompt

请只完成 task 5 到 task 10,实现 TicketService。

要求:

  1. 使用 Map<Long, Ticket> 做内存存储

  2. 使用 long nextId 做自增 id

  3. 提供方法:

  • createTicket(String title)

  • assignTicket(Long ticketId, String assignee)

  • updateStatus(Long ticketId, TicketStatus newStatus)

  • listTickets()

  • listTicketsByStatus(TicketStatus status)

  1. 输入非法时抛 IllegalArgumentException

  2. 工单不存在时抛 NoSuchElementException

  3. 返回列表时避免暴露内部可变集合

  4. 不要写 controller,不要写数据库代码

模型可能返回

import java.util.*;

import java.util.stream.Collectors;

class TicketService {

private final Map<Long, Ticket> tickets = new HashMap<>();

private long nextId = 1L;

public Ticket createTicket(String title) {

if (title == null || title.isBlank()) {

throw new IllegalArgumentException("title cannot be empty");

}

Ticket ticket = new Ticket(nextId++, title);

tickets.put(ticket.getId(), ticket);

return ticket;

}

public void assignTicket(Long ticketId, String assignee) {

Ticket ticket = getRequiredTicket(ticketId);

ticket.assignTo(assignee);

}

public void updateStatus(Long ticketId, TicketStatus newStatus) {

Ticket ticket = getRequiredTicket(ticketId);

ticket.updateStatus(newStatus);

}

public List<Ticket> listTickets() {

return new ArrayList<>(tickets.values());

}

public List<Ticket> listTicketsByStatus(TicketStatus status) {

if (status == null) {

throw new IllegalArgumentException("status cannot be null");

}

return tickets.values()

.stream()

.filter(ticket -> ticket.getStatus() == status)

.collect(Collectors.toList());

}

private Ticket getRequiredTicket(Long ticketId) {

if (ticketId == null) {

throw new IllegalArgumentException("ticketId cannot be null");

}

Ticket ticket = tickets.get(ticketId);

if (ticket == null) {

throw new NoSuchElementException("ticket not found: " + ticketId);

}

return ticket;

}

}


十四、这里你还要继续 review,而不是直接结束

你要说:

> 这一步 service 已经形成主链路了。

> 我会再看两个点。

> 第一,listTicketsByStatus 返回的是新的列表,没直接暴露内部集合,这个是好的。

> 第二,目前返回的还是 Ticket 对象本身,如果是严格封装场景,可能还要考虑 DTO 或只

> 读视图,但面试现场这个程度足够了。

这个评价会显得你知道生产和面试之间的差别。


十五、第五步:补测试或演示代码

你的 prompt

请基于现有代码,补充一个简单的 main 方法演示以下流程:

  1. 创建两个工单

  2. 给其中一个工单分配处理人

  3. 将其状态更新为 PROCESSING 和 DONE

  4. 查询全部工单

  5. 查询 DONE 状态工单

  6. 演示一次非法状态流转并捕获异常

要求:

  • 代码尽量简洁

  • 便于面试现场展示功能正确性

模型可能返回

public class Main {

public static void main(String[] args) {

TicketService service = new TicketService();

Ticket t1 = service.createTicket("Fix login bug");

Ticket t2 = service.createTicket("Optimize search performance");

service.assignTicket(t1.getId(), "Alice");

service.updateStatus(t1.getId(), TicketStatus.PROCESSING);

service.updateStatus(t1.getId(), TicketStatus.DONE);

System.out.println("All tickets:");

for (Ticket ticket : service.listTickets()) {

System.out.println(ticket.getId() + " - " + ticket.getTitle() + " - "

  • ticket.getStatus());

}

System.out.println("DONE tickets:");

for (Ticket ticket : service.listTicketsByStatus(TicketStatus.DONE)) {

System.out.println(ticket.getId() + " - " + ticket.getTitle());

}

try {

service.updateStatus(t2.getId(), TicketStatus.DONE);

} catch (Exception e) {

System.out.println("Expected error: " + e.getMessage());

}

}

}


十六、这时候面试官可能怎么追问

这是最像真实场景的部分。


追问 1:如果 AI 生成错了你怎么办?

你可以答:

> 我会先判断问题在哪一层。

> 如果是实现偏差,我会直接约束模型重写局部。

> 如果是设计不合理,我会回到 design.md 修设计,而不是在代码层硬补丁。

> 我不会带着错误设计一路往下生成。

这句很好。


追问 2:如果题目变复杂,要接数据库怎么办?

你可以答:

> 我会保留当前的领域对象和 service 接口,把存储抽象成 repository。

> 面试现场我先做内存版,是为了优先把业务规则讲清楚。

> 如果扩展到生产,再把 repository、事务、索引、并发控制接进去。

这说明你有分层扩展意识。


追问 3:为什么不是一次让 AI 全写完?

你可以答:

> 一次性全写完的问题是不可控。

> 模型可能在设计、状态机、异常处理上某一步走偏,但如果代码量太大,我很难快速定

> 位。

> 分阶段做的好处是每一步都能小闭环验收,返工成本低。


追问 4:你怎么保证 AI 写的代码质量?

你可以答:

> 我一般做四层控制。

> 第一层是 prompt 约束,明确边界、不要过度设计。

> 第二层是设计先行,先看方案再写代码。

> 第三层是分步生成,每一步人工 review。

> 第四层是运行验证和边界测试。

> 本质上不是"信任模型",而是"管理模型输出"。

这句很强。


十七、这个场景里,真正高分的不是代码,是你体现出的 6 个能力

面试官满意的点通常是这些:

  • 你会先问需求

  • 你知道先设计再编码

  • 你会让 AI 分步做,而不是一把梭

  • 你会人工 review

  • 你能发现模型输出里的问题

  • 你能解释自己的建模取舍

所以你要记住:

AI coding 的高分,不是 prompt 花哨,而是流程可控。


十八、如果你在面试现场,完整表达可以怎么说

你可以这样讲,几乎可以直接背:

> 如果让我在面试现场做 AI coding,我一般不会直接把题目丢给模型生成最终代码。

> 我会先和面试官确认需求边界,比如实现范围、状态规则、是否需要数据库和接口层。

> 确认后,我会先让模型输出一个简短设计文档,包含领域对象、核心方法、状态流转和异

> 常处理策略。

> 设计确认没问题后,我再让模型拆成小任务,比如先写数据结构,再写核心 service,再

> 补测试。

> 每一步我都会人工 review,检查是否符合设计、是否漏边界、是否有过度设计。

> 如果发现问题,我会回到对应阶段修正,而不是继续带着错误往下生成。

> 对我来说,AI coding 不是让模型替我写代码,而是把模型纳入一个受控的软件开发流

> 程。

这版很适合阿里这类会看工程感的面试。


十九、我再给你一个更真实的"你-模型-面试官"三方短剧版

面试官: 你可以开始了。

你: 我先确认边界,这题我先按 Java 内存版实现,不写 controller 和数据库,重点放在

工单建模和状态流转,可以吗?

面试官: 可以。

你: 那我先让模型出一个设计,不直接写代码。

你对模型: "请先输出 design.md,不要写代码......"

模型: 输出 Ticket / TicketStatus / TicketService 等设计。

你: 这个设计基本合理,但我会去掉非核心字段,只保留最小闭环,assign 只允许在

CREATED 状态。

面试官: 为什么这么改?

你: 因为现场时间有限,我优先保证主链路和领域规则清晰,避免样板代码和非核心字段分

散注意力。

面试官: 如果后来要接数据库呢?

你: 我会保留当前领域模型和 service 接口,把内存存储替换成 repository,现场先聚焦

核心规则,生产再补持久化和事务。

这就是一个很完整的面试过程了。


二十、你现在最该练什么

建议你练 3 件事:

  1. 练"第一句话"

要先说流程,不要直接 code。

  1. 练"设计 review"

模型出设计后,你要能讲出:

  • 哪合理

  • 哪要删

  • 为什么这么改

  1. 练"解释取舍"

比如:

  • 为什么先做内存版

  • 为什么不一次全写

  • 为什么状态规则放实体里

  • 为什么分配是业务动作不是纯状态更新

这三件事,比你会不会写一个复杂 prompt 更重要。

相关推荐
laowangpython1 小时前
Gurobi求解器Matlab安装配置教程
开发语言·其他·matlab
wengqidaifeng2 小时前
python启航:1.基础语法知识
开发语言·python
观北海2 小时前
Windows 平台 Python 极简 ORB-SLAM3 Demo,从零实现实时视觉定位
开发语言·python·动态规划
wuqingshun3141592 小时前
说说mybatis的缓存机制
java·缓存·mybatis
空中海2 小时前
Kubernetes 生产实践、可观测性与扩展入门
java·贪心算法·kubernetes
Devin~Y3 小时前
大厂Java面试实录:Spring Boot/Cloud、Kafka、Redis、K8s 与 Spring AI(RAG/Agent)三轮连环问
java·spring boot·redis·mysql·spring cloud·kafka·kubernetes
bLEd RING3 小时前
SpringBoot3.3.0集成Knife4j4.5.0实战
java
小松加哲3 小时前
Spring MVC 核心原理全解析
java·spring·mvc
Ulyanov3 小时前
《PySide6 GUI开发指南:QML核心与实践》 第二篇:QML语法精要——构建声明式UI的基础
java·开发语言·javascript·python·ui·gui·雷达电子对抗系统仿真