IDEA 实战:第一个 Java 工程与编译运行全流程

bee2026-10-0843 分钟0 次阅读
从安装 IDEA 到跑通第一个工程:项目结构、SDK 配置、断点调试、Maven 同步与六大新手坑,一次全部理顺。
1 / 133
小节
〇、30 秒看懂
2 / 133

IDEA 不是「带高亮的记事本」。它是一个替你按顺序做完所有机械动作的机器:你保存文件,它编译;你改了依赖,它去仓库取货;你敲下 Run,它把 .java 变成 .class、拼好 classpath、启动 JVM、调用 main。这一篇讲三件事:怎么装并认路(界面与六个名词)、怎么跑起来(项目结构 / SDK / 运行配置)、怎么在它骗你的时候识破它(缓存、编码、红字、Run 按钮变灰)。

3 / 133
类比

不用 IDE 写 Java,就像用真笔写稿却指望印刷厂自动看懂你的手稿——你改了三页内容,印刷厂手里还是上一版铅字,印出来的报纸照旧。IDEA 干的就是「改稿后重新排版印刷」这一步:每次 Run 之前先增量重排(编译)改动过的那几页,再把成品交给读者(JVM)。理解了这一点,「代码明明改了、跑出来还是旧的」这类怪事就一眼见底。

4 / 133
架构图
图 · 从敲下 Run 到 main 执行
图 · 从敲下 Run 到 main 执行
5 / 133

学完这一篇,你应该能回答:

6 / 133
  • Project / Module / SDK / Artifact 分别是什么?谁决定我用哪个 JDK?
  • 我点了 Run,IDEA 到底先做了什么、再做了什么?产物写到哪个目录?
  • 为什么代码全红不一定是我的错?为什么 Run 按钮会突然变灰?
7 / 133
小节
一、先选对 IDEA:Community 还是 Ultimate
8 / 133

IntelliJ IDEA 是全球 Java 开发者使用率最高的 IDE。它有两个版本,选错会让后面的学习无故多绕几个弯:

9 / 133
对照表
对比项Community(社区版)Ultimate(旗舰版)
价格免费付费(有试用与教育授权)
纯 Java / Maven / Gradle支持支持
Spring / Spring Boot 支持无(需装插件)内置完整支持
数据库工具、HTTP Client无内置
Web(Servlet / JSP / Thymeleaf)无内置
适用人群学 Java 基础、写纯 Java 项目做 Spring 企业开发
10 / 133

结论很直接:本教程后面的内容涉及大量 Spring 开发,建议用 Ultimate;如果暂时只学 Java 语法,Community 完全够用。

11 / 133
小节
1.1 中文界面要不要切
12 / 133

IDEA 自带官方中文语言包(Chinese Language Pack)。切换方式:Settings → Plugins 搜索 Chinese 安装后重启。给个实在的建议:

13 / 133
  • 初学阶段可以切中文,能显著降低「找不到菜单」带来的挫败感
  • 但快捷键、报错信息、Stack Overflow 上的解决方案都是英文,长期看英文界面收益更大
  • 折中方案:界面上手用中文,遇到陌生概念立刻对照英文菜单名记下来
14 / 133
提示

无论中英文界面,命令面板都是 Ctrl+Shift+A(Mac 是 Cmd+Shift+A)。忘了功能在哪个菜单,直接输入英文名搜索,比翻菜单快十倍。

15 / 133
小节
二、项目结构扫盲:六个名词一次讲清
16 / 133

新手打开 IDEA 常常被 Project Structure 里的一堆名词绕晕。它们其实是「从大到小、从容器到产物」的一条链:

17 / 133
对照表
名词中文一句话解释生活类比
Project项目顶级容器,管理一组模块与配置一栋大楼
Module模块实际承载源码的单元,可有多个楼里的每一户
SDK软件开发工具包这里指项目使用的 JDK每户用的水电标准
Library库外部依赖的 jar 集合家里添置的电器
Facet框架支持标记模块属于哪种技术(如 Web)给房间标注用途
Artifact构建产物打包后的 jar/war 及其输出位置装修完拿到的成品
18 / 133

关系一句话概括:一个 Project 可以含多个 Module,每个 Module 绑定一个 SDK、引用若干 Library、可挂 Facet,最终产出 Artifact。

19 / 133
小节
2.1 .idea 目录的秘密
20 / 133

新建项目后,根目录会多出一个 .idea/ 文件夹和一个 *.iml 文件,里面存的是:

21 / 133
text
.idea/├── workspace.xml        # 窗口布局、最近打开的文件、运行临时状态├── modules.xml          # 模块清单├── misc.xml             # 项目级 JDK 配置(这个常常需要共享)└── *.iml                # 模块定义(JDK、依赖、输出目录)
22 / 133

它们该不该提交到 Git?没有统一答案,取决于内容:

23 / 133
  • workspace.xml 存的是个人窗口状态,必须排除,提交了会天天冲突
  • misc.xml / *.iml 里可能包含 JDK 版本、模块依赖,团队统一时可以提交
  • 更省心的做法:.gitignore 排除整个 .idea/,让每个人都由 Maven 的 pom.xml 重新生成
24 / 133
要点

想「提交一部分、忽略一部分」,就在 .gitignore 里写 .idea/* 再用 !.idea/misc.xml 单独放行——忽略整个目录、单独白名单,比逐条排除更好维护。

25 / 133

这些名词和动作 IDEA 从不解释,但每一个都对应一件具体的事。玩一局配对:左边是你在菜单里点的东西,右边是它真正做的事——配错会当场告诉你差在哪:

26 / 133
配对闯关
闯关菜单里那个动作,到底改了什么已配对 0/6 · 配错 0
六组都是「动作 ↔ 真实效果」的硬映射。别靠位置猜,两列都打乱了
先点左边一个
27 / 133
小节
三、创建并跑起第一个工程
28 / 133
原理动画
动图 · 五分钟跑起第一个工程
动图 · 五分钟跑起第一个工程
29 / 133

按向导走一遍:File → New → Project,语言选 Java,构建系统选 IntelliJ(先不上 Maven,减少变量),在 JDK 下拉框里选 17 或 21——如果下拉框是空的,说明还没装 JDK,点 Add SDK → Download JDK 让 IDEA 帮你下载。

30 / 133

创建完成后,在 src 目录上右键,依次 New → Package(填 com.example.demo)、在包上 New → Java Class(填 Hello),然后写入:

31 / 133
java
package com.example.demo;public class Hello {    public static void main(String[] args) {        // psvm 是 IDEA 的实时模板:输入 psvm 回车即生成这一行        String name = "Spring";        int year = 2024;        System.out.println("Hello, " + name + "!");        System.out.printf("Spring Framework 诞生于 %d 年%n", 2003);        System.out.println("当前学习年份:" + year);    }}
32 / 133

写完后,代码行号左侧会出现绿色小三角,点击它选 Run 'Hello.main()',或者直接按 Shift+F10。下方的 Run 窗口会打印出结果。

33 / 133
小节
3.1 Run/Debug Configuration 讲清楚
34 / 133

点第一次 Run 时,IDEA 自动替你创建了一个「运行配置」(Run/Debug Configuration),它记录了「怎么跑这个类」。打开 Run → Edit Configurations 能看到这些关键项:

35 / 133
对照表
配置项作用新手常见误用
Main class从哪个类的 main 启动选错类导致「找不到 main」
Program arguments传给 String[] args 的参数与 VM options 填反
VM options传给 JVM 的参数,如 -Xmx512m把 -D 系统属性写进 args
Working directory程序的工作目录读相对路径文件时找不到文件
Use classpath of module用哪个模块的 classpath多模块下选错模块
36 / 133
说明

Program arguments 给的是你的程序,VM options 给的是JVM。两者填反是高频事故:把 --spring.profiles.active=dev 填进 VM options 会导致它被当成 JVM 参数而启动失败。

37 / 133
小节
四、敲下 Run 之后:编译与运行到底发生了什么
38 / 133

很多新手以为「Run 就是运行 Java」,其实 IDEA 在背后先干完了「编译」这步。完整链路是:

39 / 133
  1. 增量编译:IDEA 只重编你改动过的那些 .java 文件,而不是全量重来,所以第二次运行总是很快
  2. 落地字节码:编译产物写进输出目录,非 Maven 项目是 out/,Maven 项目是 target/classes
  3. 类加载:启动 JVM,由 ClassLoader 读入主类字节码
  4. 执行 main:JVM 调用入口方法,程序开始运行
40 / 133
类比

改稿后要重新印刷。你手里的稿纸(.java)改了,但读者拿到的报纸(.class)还是上一版铅字印的——不在同一张桌上比版本,你永远看不出问题。IDEA 的增量编译就是「只重排改动过的那几页」,所以快;而 Rebuild Project 是全部重新排版,怀疑铅字箱本身脏了才用。这条类比同时解释了第七节那两个坑:「改了代码不生效」和「删了 out 目录后类找不到」。

41 / 133
小节
4.1 out/ 和 target/ 的区别
42 / 133

这是最容易被混淆的一对目录,一定要分清:

43 / 133
对照表
对比项out/(IntelliJ 构建)target/(Maven 构建)
谁生成IDEA 自带的构建器Maven 插件
触发方式Build Project / Runmvn compile / mvn package
目录结构out/production/<模块名>/target/classes/
是否可删可删,重启即重建可删,mvn clean 清空
常见坑删了 out 却没重编 → 类找不到改了代码没 clean → 跑的是旧的
44 / 133
小节
4.2 两个构建器、两份字节码
45 / 133

上面那张表的第六行「跑的是旧的」最难自己发现。这段动画把两份字节码怎么并存演了一遍——注意第 5 帧:Run 和 java 命令读的可以不是同一份:

46 / 133
原理动画
动图 · 两个构建器、两份字节码:out/ 与 target/
动图 · 两个构建器、两份字节码:out/ 与 target/
47 / 133

构建这件事在 IDEA 里还藏着一个真数字:它自己的构建器跑在独立进程里,默认只给 700 MiB。项目一大、注解处理器一多,构建输出里就会出现那行 java.lang.OutOfMemoryError: Java heap space——注意它崩在构建阶段,你的程序本身跑得好好的。把这个数字拖一遍:

48 / 133
参数调节台
调节台IDEA 的构建进程给多少内存
默认值 700 MiB 就是图里那个数字。先停在 700 看小项目的表现,再按模块数量往右拖;改完要 Build → Rebuild 才看得出差别
Settings → Build → Compiler → Shared build process heap size
700MiB当前 256 – 8192
默认 700 MiB:单模块练习工程够用
  • 课堂示例、一两个模块的项目碰不到上限
  • 撞上限时的症状在构建输出里:java.lang.OutOfMemoryError: Java heap space
  • 崩的是构建,不是运行时——Run 起来的程序一切正常,所以很容易怀疑错方向
  • 别急着重启电脑,这个数字就是为这一格准备的
构建内存压力35%
构建用时70%
判断顺序是:先看崩在构建还是运行,再按模块数加一档——够用就好,堆不是越大越快。
49 / 133
小节
4.3 增量与全量:两个构建按钮
50 / 133

Build Project 与 Rebuild 的区别同样值得记住:

51 / 133
  • Build Project(Ctrl+F9):增量构建,只编译有变化的文件——平时用这个
  • Rebuild Project:先清空所有输出再全量重编——怀疑「缓存不一致」时才用,慢但干净
52 / 133
坑

明明改了代码,运行结果却还是旧的,九成是增量构建的缓存没更新。此时 Build → Rebuild Project 一次就能解决,别急着重启电脑。

53 / 133

把本节开头那四步链路摊开成一次单步执行。左边是按下 Run 之后依次发生的六件事,右边同步刷新「此刻的变量」和「谁在调用谁」——重点看第 2 步和第 4 步,第十一节那个灰色按钮和第十二节那条 程序包不存在,一个出在第 2 步,一个出在第 4 步:

54 / 133
单步调试台
单步台跟着走一遍:点下 Run 到 main 打印之间发生了什么1 / 6
六拍走完。第 3 步决定你跑的是新字节码还是旧的,第 4 步决定 import 红不红
被调试的代码
1点击绿色三角 Run # 先取 Run/Debug Configuration
2IDEA 校验:SDK / 模块 / 有没有 main # 任一项不合格,按钮就是灰的
3增量编译改动过的 .java # 写进 out/production 或 target/classes
4拼 classpath:模块依赖 + 库 jar # Use classpath of module 决定内容
5fork 一个新 JVM:java -cp ... Hello # IDEA 到这里就退场了
6类加载 → 调用 Hello.main(String[]) # 你的代码终于开始跑
此刻的变量
配置来自Run → Edit Configurations
已有配置Hello.main()
第一次点时会怎样自动新建一份
调用栈
1点击 Run
1第一次点 Run 时 IDEA 顺手替你建了一份运行配置。它不是一个「按钮状态」,而是一条可以导出、可以复制到命令行原样执行的命令——后面所有诡异行为都能在这条命令上找到解释。
55 / 133
小节
五、断点调试实战:一学就会的六个动作
56 / 133

调试(Debug)才是 IDEA 真正的生产力引擎。按 Shift+F9 以 Debug 模式启动,效果和 Run 一样,只是会在断点处停下来。

57 / 133

先在想要观察的那一行行号左侧单击,出现红色圆点就是断点打好了。然后记住下面这组操作:

58 / 133
代码对照
代码java
public static int sum(int[] nums) {    int total = 0;    for (int i = 0; i < nums.length; i++) {        total += nums[i];      // ← 在这行打条件断点:i == 3    }    return total;}
解读
  • 条件断点:在断点上右键,Condition 填 i == 3,只在满足条件时停下——循环第一千次时尤其救命
  • Step Over(F8):执行当前行,遇到方法调用不进去
  • Step Into(F7):进入被调用的方法内部
  • Step Out(Shift+F8):从当前方法里跳回调用它的那一层
  • Evaluate Expression(Alt+F8):弹出式计算器,实时算任意表达式,如 nums.length
  • Watches:把变量加进监视列表,每次停下都能看到它的最新值
59 / 133

还有一招很少人用却极其好用:停下时可以直接在 Variables 面板里双击变量、回车改值,然后继续走(Resume)。想验证「如果这个参数是空会怎样」,不必改代码重跑,改一下值即可。

60 / 133
提示

调试多线程时别用 Step Over 硬跟——线程会乱跳。改用断点上的 Suspend: Thread 设置,并给断点加个日志输出(Breakpoint → More → Evaluate and log),既不阻塞线程又能打印轨迹。

61 / 133
小节
六、Maven 工程在 IDEA 里怎么用
62 / 133

真实项目几乎都是 Maven 工程。打开方式:File → Open 直接选 pom.xml 所在的目录,IDEA 会自动识别为 Maven 项目并开始导入。

63 / 133

导入后,右侧会出现 Maven 工具窗口。几个高频动作要牢记:

64 / 133
  • 依赖自动同步:pom.xml 一改,右上角弹出小图标提示 Reload,点一下就把新依赖拉下来
  • Reload All Maven Projects:Maven 面板左上角的刷新按钮,等价于重读全部 pom 重新解析依赖
  • 黄标提示:依赖名下面画黄色波浪线,通常表示「这个 artifact 不在本地仓库」或「版本被 dependencyManagement 覆盖」,鼠标悬停有说明
65 / 133
代码对照
代码xml
<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId>    <!-- 黄标常见原因:父 POM 已用 dependencyManagement 管理版本,这里无需再写 version --></dependency>
解读

坑:IDEA 里代码全红、但 mvn clean package 明明能成功,多半是 IDEA 的 Maven 索引坏了。执行 Maven 面板 → Reload All Maven Projects;还不行就 File → Invalidate Caches → Invalidate and Restart。永远以命令行的构建结果为准,IDEA 的红只是它自己的视图。

66 / 133

反过来也要会看:File → New → Project 向导里勾的那些复选框,最后都会变成 pom 里的 <dependency>。勾一遍再对照生成物,你就知道 IDEA 到底替你写了什么——下次它不替你写的时候,你能自己补上:

67 / 133
生成器
生成器IDEA 向导里勾的那几项,落到 pom 上是这样pom.xml2 / 7
先勾 Web 与 Test 建立基准,再加 DevTools 和 Lombok:注意生成物里 devtools 带着 optional、lombok 带着 provided——这两个细节 IDEA 的向导从不解释
产物
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version> <!-- 版本由 BOM 统管,子依赖不写 version -->
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>demo-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
勾了这些,代价与理由在这里
parent继承 3.3.4 的 starter-parent 之后,所有 spring-boot-starter-* 都不用写版本号;一旦有人手写给某个 starter 加 version,就以那条为准——这是依赖版本漂移最常见的原因。
Web做接口就绕不开它: DispatcherServlet、内嵌 Tomcat、JSON 序列化全在这个 starter 里。
Testscope=test;@SpringBootTest、MockMvc、AssertJ 都在里面,漏了就找不到 @Test。
68 / 133
小节
七、六大新手坑,提前绕开
69 / 133
对照表
现象根因解决
所有 Java 类报红、无法运行项目 SDK 未配置File → Project Structure → SDK 选一个 JDK
输出中文全是乱码 锟斤拷文件编码为 GBK,与 UTF-8 不一致Settings → File Encodings 全部设为 UTF-8
package xxx does not correspond to the file path包名与目录路径不一致右键 Source Root 设为 src,或修正包名
改了代码死活不生效旧缓存 / 旧输出Invalidate Caches and Restart 或 Rebuild
Lombok 的 @Data 编译不报错但取不到 getter没装 Lombok 插件Plugins 里搜 Lombok 安装并开启注解处理
启动报 Port 8080 was already in use上一个进程没退干净结束占用进程,或改端口
70 / 133

定位「端口占用」的最快方式,是一条命令:

71 / 133
代码对照
代码bash
# Windows:看看是谁占用了 8080netstat -ano | findstr :8080# macOS / Linuxlsof -i :8080
解读
  • 输出最后那列的数字就是进程 PID,再用任务管理器或 taskkill /PID <pid> /F 结束它
  • 别急着重启电脑——那样只是掩盖问题,下次还会遇到

警告:Settings → File Encodings 只改当前项目,建议同时把 Project Encoding、Default encoding for properties files 都设为 UTF-8,并勾选 Transparent native-to-ascii conversion,否则 application.properties 里的中文注释仍会乱码。

72 / 133
小节
八、常用快捷键速查
73 / 133
对照表
功能WindowsmacOS
运行 / 调试Shift+F10 / Shift+F9Ctrl+R / Ctrl+D
构建项目Ctrl+F9Cmd+F9
任意搜索(命令面板)Ctrl+Shift+ACmd+Shift+A
全局搜索文件 / 类Ctrl+Shift+NCmd+Shift+O
生成代码(getter、构造器)Alt+InsertCmd+N
重命名(安全重构)Shift+F6Shift+F6
格式化代码Ctrl+Alt+LCmd+Opt+L
查看定义 / 实现Ctrl+B / Ctrl+Alt+BCmd+B / Cmd+Opt+B
单步调试F8 / F7F8 / F7
万能 Alt 键(多光标、列选择)按住 Alt 拖动按住 Opt 拖动
74 / 133
提示

不要一次背完。先把「运行、调试、命令面板、全局搜索、生成代码」这五个练成肌肉记忆,日常效率就能翻倍,其余用到再查。

75 / 133
坑

Windows 上 Shift+F10 最常见的冲突对象是 NVIDIA 显卡驱动的全局热键(打开控制面板),其次是输入法与截图工具。症状很有辨识度:按下去弹的不是 IDEA 的 Run 窗口,而是别的东西,甚至什么都不弹。两种修法任选其一:Settings → Keymap 搜 Run… 改成 Ctrl+Shift+F10;或到显卡控制面板里关掉那条热键。判断是不是快捷键问题,先用鼠标点行号旁的绿三角——能跑就说明配置本身没坏。

76 / 133
小节
九、决策卡:团队该统一到什么程度
77 / 133
决策
决策团队里每个人的 IDEA 窗口布局、字体、缩进都不一样,新人入职经常因为「代码格式不一致」在代码评审里被反复打回。团队最应该统一到什么程度?
78 / 133
小节
十、动手实验:把 IDEA 背后那几步摊开看
79 / 133

第一个实验就是第四节的动画版:保存之后到进程启动之间,IDEA 一共插了几步。切「编译产物」看 target/classes 怎么被填;切「热重载」看改一行文案为什么不用重启;切「断点调试」看第五节那些动作在进程里对应什么:

80 / 133
内核实验
TeaVMIDEA 从保存到运行:四步拆开看未启动
按 build → run → reload → debug 的顺序点,注意每一步谁在动磁盘、谁在动内存
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
81 / 133

第二个实验回答一个更根本的问题:JVM 是怎么把你的类拿进内存的。「类加载」这一步会显示它按全限定名(com.example.demo.Hello)去找文件——这就是第十二节那条 Package ... does not correspond to the file path 报错的真正由来:包名不是装饰,它是路径的一部分。

82 / 133
内核实验
TeaVM类加载:全限定名如何变成磁盘上的路径未启动
对照第十二节的包名报错,看 JVM 期望的文件长什么样
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
83 / 133

第三个实验专治「代码没写错却报找不到类」。选「ClassNotFoundException」,你会看到它在 classpath 上逐个目录翻找;只要 target/classes 是空的或过期,任何一句 java 命令都会走到这条死路:

84 / 133
内核实验
TeaVM为什么 target/classes 没编译就必崩未启动
看完再回第七节那张表,理解「IDE 能跑命令行不能跑」的路径差异
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
85 / 133

第四个实验是给下一篇铺路的:Spring Boot 应用的启动序列比裸 main 多了好几步。Runner 是 Boot 留给你的「启动后要做点什么」的接口(CommandLineRunner / ApplicationRunner),最后一个实验则演示启动失败时控制台那一大坨该怎么从上往下读:

86 / 133
内核实验
TeaVMSpringApplication.run() 八步主线与 Runner未启动
先看 full 建立整体印象,再切 runners 看你的代码在哪一步被调用
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
87 / 133
内核实验
TeaVM启动失败怎么读:从 Caused by 往上找第一行未启动
重点看异常链最底下那句 caused by——它才是根因
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
88 / 133

第五个实验治的是本篇最窝囊的一类问题:「IDE 里能跑,命令行不能跑」——两边用的根本不是同一个 JDK。切「谁说了算」看终端怎么按 PATH 顺序挑,切「装了好几个版本」看 IDEA 的 Project SDK 和终端的 java 怎么各奔东西:

89 / 133
内核实验
TeaVMIDEA 的那个 JDK 和终端的那个 JDK,可能不是同一个未启动
先点「谁说了算」,再切「装了好几个版本」,对照本篇第十二节最后一行
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
90 / 133
内核实验
TeaVM改完怎么验证:mvn -v 那行才是构建用的未启动
这一档解释为什么以命令行构建结果为准,而不是以 IDEA 的红为准
场景参数
点「运行演示」,在浏览器内真实执行 Java 编译出的内核算法,逐步看它怎么跑。
91 / 133

实验做到这里,可以换成自己敲。下面这台控制台连着浏览器里的同一个内核,回显全部由内核算出来——先敲 lab idebuild build,再按顺序往下:

92 / 133
内核控制台
93 / 133
提示

lab idebuild run 和 lab idebuild debug 连着敲最省话——两条输出只差一个 JVM 参数。第五节那六个调试动作之所以能停下来,全在那一条参数上。

94 / 133

顺手记住这张对照图。左边六个动作是新手每天都在做的,右边是同一件事的正确姿势——差别不在效率,而在你会不会被工具骗:

95 / 133
架构图
图 · IDEA 里的对错习惯
图 · IDEA 里的对错习惯
96 / 133
小节
十一、沙盘:Run 按钮变灰了,是谁的问题
97 / 133

Run 按钮(绿色三角)变灰从来不是「IDEA 坏了」,而是它判定「现在按下必然失败」。左边选模块状态,右边选 JDK 状态,面板直接给出该点哪里恢复:

98 / 133
架构图
图 · Run 按钮变灰前,IDEA 查了哪五件事
图 · Run 按钮变灰前,IDEA 查了哪五件事
99 / 133
原理动画
动图 · Run 与 Debug 差在哪一步
动图 · Run 与 Debug 差在哪一步
100 / 133
沙盘
沙盘Run 按钮为什么是灰的
运行结果
无匹配结果
101 / 133
说明

沙盘里 no-main 那一格最容易被忽略——IDEA 只给「它认得的入口」画绿三角。main 的签名是硬性约定:public、static、void、参数 String[],四个条件少一个都不行。

102 / 133
小节
十二、常见报错速查
103 / 133
对照表
报错原文(片段)真实原因30 秒自救深挖看第几篇
Class 'Hello' is public, should be declared in a file named 'Hello.java'公共类名与文件名不一致(大小写也算不一致)改文件名,别改类名;两者必须逐字符相同#1 第四节
Package com.example.demo does not correspond to the file path 'com/example/hello' / does not match its package目录大小写与包名不符,或 src 没标成 Sources Root右键该目录 → Mark Directory as → Sources Root,再核对包名层级本篇第二节 · 上方沙盘
Exception in thread "main" java.lang.ClassNotFoundException: com.example.demo.Hello(命令行里报,IDEA 里正常)target/classes 根本没编译过,或你手敲的 -cp 不含输出目录先 mvn compile(或 IDEA Ctrl+F9),再 java -cp target/classes com.example.demo.Hello#2 Maven 生命周期
java: 程序包 xxx 不存在 / Cannot resolve symbol 'springframework'pom 改了但没 Reload,依赖没进模块 classpathMaven 面板 → Reload All Maven Projects;仍不行 File → Invalidate Caches本篇第六节
Run / Debug 按钮灰色不可点没配 Project SDK、认不出 main、或模块未标 Sources Root按第十一节沙盘三选一排查;最常见是 Project Structure → SDK本篇第十一节
Shift+F10 触发的是系统全局快捷键而不是 IDEA 的运行与其他软件抢键(输入法、显卡驱动、截图工具最常见)Settings → Keymap 搜 Run 重新指定;或先用鼠标点绿三角确认配置本身没问题本篇第八节的抢键说明
控制台中文乱码 锟斤拷 / ??????源文件编码、编译器 -encoding、控制台字符集三者不一致Settings → File Encodings 全设 UTF-8;运行时加 -Dfile.encoding=UTF-8#35 日志体系
Port 8080 was already in use上一次启动的进程还活着,占着端口`netstat -ano \findstr :8080 取 PID,taskkill /PID <pid> /F`本篇第七节
104 / 133
坑

ClassNotFoundException 在 IDEA 里几乎见不到、在命令行里天天见——因为 IDEA 用的是自己的构建输出(可能是 out/production/...),而你手敲的命令默认指向 target/classes。两套目录不同步是这类「同一个类有时找得到有时找不到」的根源。

105 / 133

这条坑值得用一段真堆栈收尾。注意凶手不在最上面那行,也不在 Exception in thread 那句里——点给你看:

106 / 133
报错急救
报错急救ClassNotFoundException: com.example.demo.Hello
IDEA 里跑得好,终端里 java 却说找不到这个类

你在 IDEA 里 Ctrl+F9 编过、Run 也正常;照上表最后一条敲 java -cp target/classes com.example.demo.Hello,直接抛异常。

Exception in thread "main" java.lang.ClassNotFoundException: com.example.demo.Hello
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:592)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:534)
at sun.launcher.LauncherHelper.loadMainClass(LauncherHelper.java:802)
点你认为的「凶手行」(可反复试)
不会也没关系:先猜异常名,再猜哪一行在做决定。
107 / 133
小节
十三、随堂自测
108 / 133
随堂自测
随堂自测你在 IDEA 里改了 Hello.java 的一行打印内容,点了 Run,控制台输出的还是旧文案。最不可能的原因是?
先自己选一个,选中立刻告诉你对不对
109 / 133
随堂自测
随堂自测一个类的开头写着 `package com.example.demo;`,但文件放在 `src/Hello.java`(src 没有被标记为 Sources Root)。IDEA 会怎样?
先自己选一个,选中立刻告诉你对不对
110 / 133
小节
十四、动手练习
111 / 133
小节
第一档 · 照做
112 / 133

目标:亲手制造并修好本篇最常见的三个「IDE 骗你」现场。

113 / 133
java
package com.example.demo;public class DebugLab {    public static int sum(int[] nums) {        int total = 0;        for (int i = 0; i < nums.length; i++) {            total += nums[i];          // ← 在这里打断点,条件设 i == 3        }        return total;    }    public static void main(String[] args) {        int[] data = {1, 2, 3, 4, 5, 6};        int result = sum(data);        System.out.println("sum = " + result);   // ← 在这行打断点,停下时把 result 改成 0        System.out.println("result * 2 = " + (result * 2));    }}
114 / 133

按顺序做完这三件事,并各写一句话记录现象:

115 / 133
  1. 在第 8 行打条件断点 i == 3,用 Shift+F9 启动,确认只在第四次循环停住。
  2. 停在第 15 行时,在 Variables 面板双击 result 改成 0,再 Resume。预期输出:第二行打印 result * 2 = 0——证明改变量真的改变了执行结果。
  3. 用 Evaluate Expression(Alt+F8)在不改代码的前提下算出 data.length + result,然后把 nums[0] 输入进去,观察它抛出的异常类型。
116 / 133

验收清单:你能说出「条件断点为什么比 println 快」,以及「改变量值和改代码重跑的本质区别」。

117 / 133
小节
第二档 · 变体
118 / 133

三个小改动,各自复现一类高频故障,练的是「一眼看出根目录在哪」:

119 / 133
  1. 把 package com.example.demo; 留着,但把文件移动到 src 根下。你会观察到 IDEA 报包名与路径不符,且第十节那个类加载实验里「全限定名 → 磁盘路径」的映射当场断裂。
  2. 删掉整个 out 或 target 目录,然后不要 Build,直接从终端跑 java -cp target/classes com.example.demo.DebugLab。你会观察到 ClassNotFoundException;补一次 mvn compile 或 Ctrl+F9 立刻恢复正常。
  3. 把 Settings → Appearance & Behavior → System Settings 里的自动保存关掉,改一行打印但不按 Ctrl+S 就点 Run。你会观察到 IDEA 弹出的那条提示,以及它为什么会先把改动同步到磁盘再编译。
120 / 133

提示:做完第 3 条,你就理解了「保存 ≠ 编译 ≠ 运行」是三件独立的事。

121 / 133
小节
第三档 · 造一个
122 / 133

做一个 双模块 Maven 工程,把本篇和 #2 的知识串起来:

123 / 133
text
lab-ide/                 ← 父 pom,packaging=pom├── lab-core/            ← 放 SumUtil 与一个自定义异常└── lab-app/             ← 依赖 lab-core,含 main 与一个 CommandLineRunner
124 / 133

要求:① 用 File → Open 打开父目录导入(不要 New Project),确认 Maven 面板出现两个模块;② lab-app 的 main 里故意留一处空指针,用异常断点(Run → View Breakpoints → Java Exception Breakpoints)让 IDEA 在抛出那一刻自动停住,而不是等你逐行找;③ 配一个 CommandLineRunner,在启动后打印一行统计信息;④ 分别用 Run 和 Debug 各跑一次,写下两者的三条差异;⑤ 最后从终端用 java -cp 手动跑一次,体会 IDEA 替你拼了什么。

125 / 133

验收清单:mvn clean install 全绿;IDEA 里 Debug 能在异常发生处停住;终端手动 java -cp 也能跑通——这说明你真的知道 classpath 是怎么拼出来的。

126 / 133
小节
十五、要点自查
127 / 133
自检

Project / Module / SDK / Artifact 四个词,哪个决定「用哪个 JDK」,哪个决定「打包成什么」?

128 / 133
自检

out/production/<模块> 和 target/classes 谁生成的?为什么它们会不同步?

129 / 133
自检

Run 与 Debug 走的链条只差哪一步?这一步带来了什么能力、什么代价?

130 / 133
自检

Program arguments 和 VM options 分别交给谁?把 --spring.profiles.active=dev 填错格子会怎样?

131 / 133
自检

IDEA 里代码全红而 mvn clean package 成功,该信谁?为什么?

132 / 133
口诀

保存归磁盘、编译归字节码、运行归 classpath、调试归断点——四件事各有各的开关,出问题先问自己在哪一层。

133 / 133
总结

这一节把 IDEA 的三条主线理顺了——结构(Project / Module / SDK 的分层关系)、运行(增量编译写进 out/ 或 target/,JVM 加载再执行 main)、调试(断点、单步、求值、改变量值)。再加上绕开六个新手坑,你的开发环境从此稳定可用,可以专心写代码了。