主题
界面
主题
在 《JDK 与 Java 版本》 里,我们在命令行里编译运行了单个 .java 文件。真实项目不是单文件:有几十个类、有第三方依赖、有统一的目录规范、还需要断点调试。本节把这套工程化的基础设施一次搭好。
学完本节,你会有:一个 IDEA、一个能跑的 Maven 项目、一套国内可用的依赖下载镜像、以及第一次真正的断点调试体验。
完成本节后,你应该能够:
src/main/java 与 src/test/java 的用途;java -version 看到版本号?(《JDK 与 Java 版本》 的掌握标准)JAVA_HOME 指向哪里吗?javac --release 21 能编译成功吗?任意一项做不到,先回到 《JDK 与 Java 版本》。
问题一:命令行太慢。改一行代码要敲三条命令,还要 cd 到正确目录。IDE 把编译、运行、调试压成一次点击。
问题二:没有统一结构。你自己随手建的目录,别人看不懂,构建工具也认不出来。Maven 规定了标准目录结构,任何 Java 从业者都能一眼看懂。
问题三:不会调试就只能靠 System.out.println。打印大法在复杂逻辑下会失控,而断点调试能让你"看到"程序的每一步。
| 版本 | 价格 | 能做什么 |
|---|---|---|
| Community(社区版) | 免费 | Java 基础开发、Maven、JUnit、Debug——本知识库够用 |
| Ultimate(旗舰版) | 收费 | 额外支持 Spring、数据库工具、前端框架 |
结论:先装社区版。学 Spring 时如果需要,再考虑旗舰版(学生可申请免费授权)。
my-project/
├── pom.xml # 项目描述文件:坐标、依赖、编译器版本、插件
└── src/
├── main/
│ ├── java/ # 主代码,包名对应子目录
│ └── resources/ # 配置文件(application.yml、SQL 脚本等)
└── test/
└── java/ # 测试代码,结构与 main 对称目录固定是 Maven 的约定。约定优于配置:只要照这个结构放,Maven 就知道去哪找源码、去哪找测试。
初学者最容易混淆的三个词:
pom.xml;一个常见困惑:"我明明装了 JDK,IDEA 却报找不到 SDK。" —— 因为 IDEA 的 SDK 列表和系统 JAVA_HOME 是两回事,需要在 IDEA 里手动添加一次。
pom.xml 里的 groupId、artifactId、version 合起来唯一标识一个构件:
<groupId>cn.kb.learn</groupId> <!-- 组织/包名反写 -->
<artifactId>hello-maven</artifactId> <!-- 项目名 -->
<version>1.0.0</version> <!-- 版本 -->以后引入任何依赖,都是写这三个坐标 + <scope>。
Maven 默认从国外中央仓库下载依赖,国内速度极慢。打开用户目录下的 settings.xml(路径:C:\Users\<用户名>\.m2\settings.xml,没有就新建),写入:
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
<localRepository>D:/maven-repo</localRepository>
</settings>两个关键点:<mirror> 把中央仓库指向阿里云;<localRepository> 把本地仓库放到非系统盘(默认在 C 盘的 .m2/repository,长期会把系统盘撑大)。
IDEA 中:File → New → Project → Maven,填写:
hello-mavencn.kb.learnpom.xml 里限制为 21)创建完成后,先在 Settings → Build Tools → Maven 里确认 User settings file 指向刚才改的 settings.xml。
Settings → Editor → File Encodings,把三处都设为 UTF-8:
中文乱码九成来自这里。
文件:labs/start/pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.kb.learn</groupId>
<artifactId>start</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
</properties>
</project>文件:src/main/java/cn/kb/learn/Main.java
package cn.kb.learn;
public class Main {
public static void main(String[] args) {
System.out.println("项目已跑通,JDK 目标版本 = " + Runtime.version().feature());
}
}运行方式:在 IDEA 中点击 main 方法左侧的绿色三角,选择 Run。
预期输出:
项目已跑通,JDK 目标版本 = 25为什么是 25
Runtime.version().feature() 返回的是运行时 JVM 的版本(本机 25),而 maven.compiler.release=21 限制的是编译目标。两者都正确:用 25 的 JVM 跑 21 的字节码。
用下面这段代码练第一次断点调试:
package cn.kb.learn;
public class DebugDemo {
public static void main(String[] args) {
int[] data = {3, 7, 2, 9, 5};
int sum = 0;
for (int i = 0; i < data.length; i++) {
sum += data[i];
System.out.println("第 " + (i + 1) + " 次累加后 sum = " + sum);
}
System.out.println("总和 = " + sum);
}
}操作:
sum += data[i]; 这一行左侧点一下,出现红点(断点);i = 0、data = {3,7,2,9,5}、sum = 0;sum 变成 3;i 与 sum 同步变化,直到循环结束;要观察的三件事:循环变量 i 如何递增、data[i] 如何取值、sum 如何累加。这就是"看见程序执行"的感觉。
锟斤拷 或 ?????) 原因:源码文件编码与编译时的编码不一致。
修复:pom.xml 里必须有 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>,IDEA 的 File Encodings 全部设为 UTF-8。Windows 控制台如仍乱码,可执行 chcp 65001 切换代码页。
原因:还在从国外仓库下载,或 settings.xml 没被 IDEA 采用。
修复:确认镜像配置;在 Settings → Build Tools → Maven 里把 User settings file 指向你的 settings.xml,并勾选 Override;已下载一半的损坏文件可到本地仓库目录删除后重试。
Project SDK is not defined 原因:IDEA 里没登记 JDK。
修复:File → Project Structure → SDKs → Add SDK → JDK,选择 C:\Program Files\Microsoft\jdk-25.0.2.10-hotspot 这类 JDK 根目录,然后在 Modules 里指定语言级别与 SDK。
目标:从零建一个 Maven 项目,跑通并完成一次断点调试。
步骤:
hello-maven 项目;pom.xml,加上 UTF-8 与 maven.compiler.release=21;cn.kb.learn.Main,运行成功;cn.kb.learn.DebugDemo,按第 8 节完成一次断点调试;i、sum、data.length 各是多少。验收方式:能解释"断点停下时那一行代码执行了没有"。
扩展任务:把断点改成条件断点(右键断点 → Condition 填 i == 3),观察程序是否只在 i 等于 3 时停下。
基础题
src/main/java 与 src/test/java 分别放什么?groupId、artifactId、version 三个坐标的作用是什么?代码阅读题
<properties>
<maven.compiler.release>21</maven.compiler.release>
</properties>编程题
SumCalculator,包含方法 int sum(int[] numbers) 返回数组元素之和(空数组返回 0)。在 main 里调用它并打印结果,然后用断点观察方法调用前后的变量。综合任务
SumCalculator 拆成两个类:SumCalculator(计算)和 Main(调用),分别放在 cn.kb.learn.calc 和 cn.kb.learn 两个包里,跑通并说明包名与目录的对应关系。提示 1(方向):第 5 题的 sum 方法用一个循环累加即可,注意 numbers == null 或长度为 0 的处理。
提示 2(关键点):第 6 题的包名必须和目录结构一致——cn.kb.learn.calc 对应 src/main/java/cn/kb/learn/calc/。
提示 3(接近答案):Main 里要用 import cn.kb.learn.calc.SumCalculator; 才能使用另一个包的类。
src/main/java 放主代码(会被打包进产物);src/test/java 放测试代码(只在测试时编译运行,不进入发布产物)。删掉后编译器会退回 JDK 默认的语言级别(通常是本机 JDK 版本)。风险是:你在本机(JDK 25)写出的代码可能使用了 22 之后的新 API,换到 JDK 21 环境就编译失败。显式声明 release 可以让代码在任何环境都表现一致,也便于团队统一。
package cn.kb.learn;
public class SumCalculator {
public int sum(int[] numbers) {
if (numbers == null || numbers.length == 0) {
return 0;
}
int total = 0;
for (int number : numbers) {
total += number;
}
return total;
}
public static void main(String[] args) {
SumCalculator calculator = new SumCalculator();
System.out.println(calculator.sum(new int[]{3, 7, 2, 9, 5}));
System.out.println(calculator.sum(new int[]{}));
}
}预期输出:
26
0// 文件:src/main/java/cn/kb/learn/calc/SumCalculator.java
package cn.kb.learn.calc;
public class SumCalculator {
public int sum(int[] numbers) {
if (numbers == null || numbers.length == 0) {
return 0;
}
int total = 0;
for (int number : numbers) {
total += number;
}
return total;
}
}// 文件:src/main/java/cn/kb/learn/Main.java
package cn.kb.learn;
import cn.kb.learn.calc.SumCalculator;
public class Main {
public static void main(String[] args) {
SumCalculator calculator = new SumCalculator();
System.out.println("结果 = " + calculator.sum(new int[]{1, 2, 3, 4}));
}
}包与目录的对应关系:package cn.kb.learn.calc; 要求文件位于 src/main/java/cn/kb/learn/calc/ 下。包名不是装饰,它是类的全限定名的一部分,编译产物会按包名生成目录。
《Java 程序的运行与调试》 会把调试技巧系统化(条件断点、调用栈、Watch)。之后进入 S1 编程语言基础,开始语言本体。