JDK JDK 学习手册8 → 27 · JDK 专用学习站
QUICKREF · TOOLING · JEP 330 (JDK 11)

单文件源码启动:java Hello.java

JDK 11 · 速查主题 05 / 06 · 预计 16 分钟
基础16 分钟JEP 330
一句话JDK 11 允许直接用 java 命令运行一个 .java 源文件:编译器在内存中编译,不生成 .class。它降低了脚本、教学和小工具的门槛,但不是多文件项目或生产构建的替代品。

学完你要能自己回答

  1. 单文件源码模式怎么找到入口类?文件名必须和 public 类一致吗?
  2. 它会不会生成 .class?依赖怎么加?能不能运行多个源文件?
  3. 为什么生产构建仍应使用 javac / 构建工具?它的编译器和平台边界是什么?

最小用法:源码文件就是程序01

JDK 11 的 java 启动器支持源码文件模式:第一个非选项参数以 .java 结尾时,启动器调用内置编译器编译并运行,不写出 class 文件。

public class Hello {
    public static void main(String[] args) {
        System.out.println("hello " + (args.length == 0 ? "world" : args[0]));
    }
}
java Hello.java Java 11
hello Java

运行结束后目录里仍然只有 Hello.java,没有 Hello.class。如果需要给别的程序引用,仍然要用 javac 编译出 class 或 jar。

源码模式使用当前 JDK 自带的编译器(jdk.compiler 模块)。用 jlink 裁剪运行时,如果没有保留 jdk.compiler,java Hello.java 会失败;编译好的 class 不受影响。

入口类、文件名与多顶层类02

源码模式不要求文件名与 public 类名一致。启动器会执行源文件中第一个顶层类的 main 方法;文件里可以有多个顶层类作为辅助类。

public class First {
    public static void main(String[] args) {
        System.out.println("first " + Helper.value());
    }
}

class Helper {
    static String value() { return "helper"; }
}
java Multi.java
first helper
  • 第一个顶层类必须有 main(String[]);后面的类只作为辅助类参与编译。
  • 文件名不必与 public 类名一致;这与 javac 的规则不同。
  • 源文件可以带 package 声明,启动器仍能运行;不需要把文件放进与包名匹配的目录。
  • 只支持一个源文件。需要多个源文件互相引用时,用 javac 或构建工具。
  • JDK 11 不支持从标准输入读取源码,也不支持一次传入多个源文件。
package demo;

public class Packaged {
    public static void main(String[] args) {
        System.out.println("packaged");
    }
}
java Packaged.java
packaged

shebang 与 --source:把 Java 当脚本03

在 Unix 上,源码文件可以带 shebang 行,用 --source 指定语言版本,然后直接执行。启动器会跳过第一行 #!。

#!/usr/bin/java --source 11
public class Script {
    public static void main(String[] args) {
        System.out.println("script " + args.length);
    }
}
chmod +x script
./script a b

# Windows 上没有 shebang,但可以用 --source 运行无后缀文件
java --source 11 script a b
script 2

shebang 是 Unix 的能力,不是 Java 语言语法;在 Windows 上直接双击或执行无后缀文件不会生效,必须显式调用 java --source 11 script。

--source 11 只设置源码级别,不会像 --release 那样限制可用 API。脚本仍可能引用当前 JDK 的其他 API;跨版本运行时要注意。

依赖:用 --class-path 挂 classpath04

单文件源码可以依赖 classpath 上已编译的类。把依赖 jar 或 class 目录传给 --class-path,源文件本身仍只有一个。

public class Lib {
    public static String msg() { return "from lib"; }
}
javac -d lib Lib.java

cat > UseLib.java <<'EOF'
public class UseLib {
    public static void main(String[] args) {
        System.out.println(Lib.msg());
    }
}
EOF

java --class-path lib UseLib.java
from lib

这适合「一个脚本 + 几个已有 jar」的场景。依赖一多、需要模块化或需要可重复构建时,应该回到 Maven / Gradle / javac。

源码模式的 classpath 只影响编译和运行时的类型查找,不会把依赖打包进任何产物;分发时仍要带上依赖。

边界:它不是构建工具的替代品05

维度单文件源码模式javac / 构建工具
源文件数量一个任意
产物无 .class / jarclass、jar、模块
编译缓存每次启动重新编译增量编译
启动速度多一次内存编译直接加载 class
依赖管理手工 --class-pathMaven / Gradle
模块化不作为主要用法module-info、jlink
生产部署不推荐标准方式
  • JEP 330 在 JDK 11 引入;JDK 10 及更早没有这个能力。
  • 只支持单个源文件;多文件源码启动是 JDK 22 的 JEP 458,不要提前使用。
  • 不生成 class 文件,无法做传统的增量构建或产物校验。
  • 启动时多一次编译,短脚本无感,大型程序不适合。
  • 生产环境仍应使用 javac / 构建工具,把编译与运行分离。
单文件模式最适合教学、脚本、单文件工具和快速验证 API。它解决的是「不想先建工程」的问题,不是「不想构建」的问题。

版本边界BOUNDARY

这张表比 API 本身更值得记。写代码时先确认你的运行时版本。

特性 / API状态说明
单文件源码启动11 正式JEP 330;JDK 10 及更早不支持。
多文件源码启动22 正式JEP 458;JDK 11 一次只能传一个源文件。
输出 class 文件不支持内存编译;需要产物时用 javac。
shebangUnix 可用Windows 用 java --source 11 file。
jdk.compiler 依赖需要裁剪运行时若移除 jdk.compiler,源码模式不可用。
package 声明支持不要求目录与包名匹配。

费曼自检SELF CHECK

先合上页面,用自己的话回答,再展开对照。能讲出因果和反例,才算真正掌握。

01. 单文件源码模式怎么确定入口类?
执行源文件中第一个顶层类的 main 方法。文件名不必与 public 类名一致;第一个顶层类必须有 main(String[])。
02. java Hello.java 会生成 Hello.class 吗?
不会。编译器在内存中编译并直接运行,不写出 class 文件;需要 class 或 jar 时仍要用 javac。
03. 单文件模式能运行多个源文件吗?
JDK 11 不能。一次只支持一个源文件;多文件源码启动是 JDK 22 的 JEP 458。多个文件应使用 javac 或构建工具。
04. shebang 在 Windows 上能用吗?
不能直接使用。shebang 是 Unix 的机制;Windows 上可以用 java --source 11 script 运行无后缀源码文件。
学习进度 记录保存在本机浏览器 · 不上传

JDK 学习手册 · JDK / Java 专用学习站 · 纯静态 · 双击 index.html 即可使用

本站专注 JDK 版本演进与 Java 教学,非 Oracle / OpenJDK 官方站点。版本数据来自 OpenJDK 官方 Features 表;课程示例已在对应本机 JDK 实测。构建日期 2026-11-12。