Java 完全指南 / 03 - Hello World:编译运行、项目结构、JAR 打包
03 - Hello World:编译运行、项目结构、JAR 打包
手动编译运行
最简单的 Hello World
// 文件名: HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
# 编译:将 .java 编译为 .class 字节码
javac HelloWorld.java
# 运行:JVM 加载并执行字节码
java HelloWorld
# 输出:
# Hello, World!
⚠️ 类名必须与文件名完全一致(包括大小写)。
public class HelloWorld必须放在HelloWorld.java中。
main 方法签名解析
public static void main(String[] args)
│ │ │ │ │
│ │ │ │ └── 参数:字符串数组,接收命令行参数
│ │ │ └──────────── 方法名:固定为 main
│ │ └───────────────── 返回类型:void
│ └──────────────────────── static:无需创建对象即可调用
└─────────────────────────────── public:JVM 需要访问此方法
JDK 21 也支持简化写法(无需 public 类):
// JDK 21+ 通过 JEP 463 支持隐式类
void main() {
System.out.println("Hello from JDK 21!");
}
带命令行参数的版本
public class Greeter {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("用法: java Greeter <名字>");
return;
}
for (String arg : args) {
System.out.println("你好, " + arg + "!");
}
}
}
javac Greeter.java
java Greeter 张三 李四
# 输出:
# 你好, 张三!
# 你好, 李四!
Java 编译运行流程
源码 .java ──javac──▶ 字节码 .class ──java──▶ JVM 执行
│
▼
可打包为 .jar
(Java Archive)
编译器 javac 常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
-d <dir> | 指定输出目录 | javac -d out src/*.java |
-sourcepath <path> | 源码搜索路径 | javac -sourcepath src -d out Main.java |
-encoding UTF-8 | 指定编码 | javac -encoding UTF-8 *.java |
-version | 显示版本 | javac -version |
-Xlint:all | 启用所有警告 | javac -Xlint:all *.java |
@argfile | 从文件读取参数 | javac @sources.txt |
java 运行时常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
-cp <path> | 类路径 | java -cp out:lib/* Main |
-D<key>=<value> | 系统属性 | java -Dapp.env=prod Main |
-Xmx<mem> | 最大堆内存 | java -Xmx512m Main |
-XX:+PrintFlagsFinal | 打印 JVM 参数 | 诊断用 |
--enable-preview | 启用预览特性 | java --enable-preview Main |
标准项目结构
Maven 标准目录布局
my-project/
├── pom.xml # Maven 项目配置
├── src/
│ ├── main/
│ │ ├── java/ # 主代码
│ │ │ └── com/example/
│ │ │ └── App.java
│ │ ├── resources/ # 资源文件
│ │ │ └── application.properties
│ │ └── webapp/ # Web 资源(WAR 项目)
│ │ └── WEB-INF/
│ └── test/
│ ├── java/ # 测试代码
│ │ └── com/example/
│ │ └── AppTest.java
│ └── resources/ # 测试资源
├── target/ # 构建输出(自动生成)
│ ├── classes/
│ ├── test-classes/
│ └── my-project-1.0.0.jar
├── .gitignore
└── README.md
包(Package)机制
// src/main/java/com/example/demo/HelloApp.java
package com.example.demo; // 包声明,必须是第一条非注释语句
public class HelloApp {
public static void main(String[] args) {
System.out.println("包路径: " + HelloApp.class.getPackageName());
}
}
# 带包名编译
javac -d out src/main/java/com/example/demo/HelloApp.java
# 带包名运行(使用全限定类名)
java -cp out com.example.demo.HelloApp
💡 包名全部小写,使用倒序域名:
com.company.project.module。
JAR 文件打包
什么是 JAR?
JAR(Java ARchive) 是基于 ZIP 格式的归档文件,包含:
- 编译后的
.class文件 - 资源文件(配置、图片等)
META-INF/MANIFEST.MF(清单文件)
手动创建 JAR
# 1. 编译
javac -d out src/main/java/com/example/demo/HelloApp.java
# 2. 创建 MANIFEST.MF
echo 'Main-Class: com.example.demo.HelloApp
Class-Path: .
' > MANIFEST.MF
# 3. 打 JAR
jar cfm app.jar MANIFEST.MF -C out .
# 4. 运行
java -jar app.jar
使用 Maven 打包
pom.xml 中配置 maven-jar-plugin:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.demo.HelloApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
mvn clean package
java -jar target/my-app-1.0.0.jar
Fat JAR / Uber JAR
普通 JAR 不包含依赖,运行时需要手动指定 classpath。Fat JAR 将所有依赖打包到一个 JAR 中。
使用 Maven Shade Plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.demo.HelloApp</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
使用 Spring Boot Maven Plugin(Spring Boot 项目推荐):
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
JAR 常用命令
# 查看 JAR 内容
jar tf app.jar
# 解压 JAR
jar xf app.jar
# 运行 JAR
java -jar app.jar
# 查看 MANIFEST.MF
unzip -p app.jar META-INF/MANIFEST.MF
# 运行指定 class(不带 Main-Class)
java -cp app.jar com.example.SomeClass
完整项目示例
创建一个带包结构和多类的项目:
greeting/
├── src/
│ └── com/example/greeting/
│ ├── Main.java
│ ├── Greeter.java
│ └── StringUtils.java
└── out/ # 编译输出
// src/com/example/greeting/StringUtils.java
package com.example.greeting;
public class StringUtils {
public static boolean isEmpty(String s) {
return s == null || s.isBlank();
}
public static String capitalize(String s) {
if (isEmpty(s)) return s;
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
}
// src/com/example/greeting/Greeter.java
package com.example.greeting;
public class Greeter {
private final String prefix;
public Greeter(String prefix) {
this.prefix = prefix;
}
public String greet(String name) {
if (StringUtils.isEmpty(name)) {
return prefix + ", 匿名用户!";
}
return prefix + ", " + StringUtils.capitalize(name) + "!";
}
}
// src/com/example/greeting/Main.java
package com.example.greeting;
public class Main {
public static void main(String[] args) {
Greeter greeter = new Greeter("你好");
System.out.println(greeter.greet("java"));
System.out.println(greeter.greet(""));
System.out.println(greeter.greet(null));
}
}
# 编译(编译器会自动处理同包内类的依赖)
javac -d out src/com/example/greeting/*.java
# 运行
java -cp out com.example.greeting.Main
# 输出:
# 你好, Java!
# 你好, 匿名用户!
# 你好, 匿名用户!
⚠️ 注意事项
- 一个 .java 文件只能有一个 public 类 — 文件名必须与 public 类名一致,其他类只能是包级私有。
- 编码问题 — Windows 默认 GBK,编译含中文的
.java时加-encoding UTF-8。 - classpath 分隔符 — Linux/macOS 用
:,Windows 用;。 - 不要在 classpath 中遗漏
.—.表示当前目录,否则可能找不到类。
💡 技巧
直接运行单文件源码(JDK 11+)—— 无需手动 javac:
java HelloWorld.java # 自动编译并运行 java --source 21 HelloWorld.javaJDK 21+ 多文件直接运行:
# 自动编译所有依赖的 .java 文件 java src/com/example/greeting/Main.java查看反编译字节码:
javap -c -p HelloWorld.class # 反汇编 javap -verbose HelloWorld.class # 详细信息
🏢 业务场景
- 微服务部署: Spring Boot 应用打包为 Fat JAR,Docker 容器中直接
java -jar app.jar启动。 - CLI 工具: 使用
picocli库构建命令行工具,打包为 JAR 后通过java -jar tool.jar执行。 - 脚本化运行: JDK 21 支持单文件运行,可将简单 Java 程序当脚本使用,替代 Python 脚本。