2. 使用文件名编译

假设当前目录下有两个目录:src(存放Java源文件)和out(存放编译后的class文件)。我们先看一个简单场景:src目录中只有一个Java文件com/baeldung/MyClass.java

$ javac -d ./out/ ./src/com/baeldung/MyClass.java

这里-d选项指定class文件的输出目录。注意MyClass.java的具体代码内容不重要,只需确保语法正确即可。

当项目文件增多时,比如新增三个文件YourClass.javaHerClass.javaHisClass.java,我们可以手动列出所有文件:

$ javac -d ./out/ \
./src/com/baeldung/MyClass.java \
./src/com/baeldung/YourClass.java \
./src/com/baeldung/HerClass.java \
./src/com/baeldung/HisClass.java

如果存在一个主类(如Main.java)引用了其他类,只需编译主类即可:

$ javac -sourcepath ./src/ -d ./out/ ./src/com/baeldung/Main.java

此时javac会自动查找并编译依赖的类文件。若需禁用自动编译依赖类,可添加-implicit:none选项。-sourcepath选项告诉编译器源文件的位置,也可用-classpath-cp替代:

$ javac -cp ./src/ -d ./out/ ./src/com/baeldung/Main.java

但这种方法有局限:只编译被引用的类。例如新增一个ItsClass.java但未被Main.java引用,该文件就不会被编译。

适用场景

  1. 源文件数量极少时
  2. 存在递归引用所有类的主入口类时

3. 使用通配符编译

javac支持通配符*编译同目录下的多个文件:

$ javac -d ./out/ ./src/com/baeldung/*.java

当项目包含子包时(如新增springsummerautumnwinter四个子包),可分别指定通配符:

$ javac -d ./out/ \
./src/com/baeldung/*.java \
./src/com/baeldung/spring/*.java \
./src/com/baeldung/summer/*.java \
./src/com/baeldung/autumn/*.java \
./src/com/baeldung/winter/*.java

适用场景:包数量较少时(无论源文件多少)

4. 使用参数文件编译

当包数量较多时,参数文件(可包含选项和源文件名)是更优雅的解决方案。使用@前缀指定参数文件:

$ javac -d ./out/ @sources.txt

生成sources.txt的方法因操作系统而异:

  • Linux/macOS:使用find命令
    $ find ./src/ -type f -name "*.java" > sources.txt
    
  • Windows:使用dir命令
    > dir src /b /s *.java > sources.txt
    

注意:每次增删源文件后需重新生成sources.txt

5. 其他进阶方法

5.1 使用Globstar(Bash 4.0+)

Bash 4.0引入了globstar选项,使双通配符**能递归匹配多级目录。默认关闭,需手动启用:

# 查看当前状态
$ shopt globstar
globstar           off

# 启用globstar
$ shopt -s globstar

# 编译所有Java文件
$ javac -d ./out/ ./src/**/*.java

# 禁用globstar
$ shopt -u globstar

5.2 使用管道(Pipe)

通过管道组合命令实现编译:

  • xargs方式
    $ find ./src/ -type f -name "*.java" | xargs javac -cp ./src/ -d ./out/
    
  • find的-exec方式(性能优化):
    # 基础版(慢,每个文件启动一次javac)
    $ find ./src/ -type f -name "*.java" -exec javac -cp ./src/ -d ./out/ '{}' ';'
    
    # 优化版(快,批量执行)
    $ find ./src/ -type f -name "*.java" -exec javac -cp ./src/ -d ./out/ '{}' +
    

性能提示:将分号;替换为加号+可显著提升编译速度(减少javac启动次数)。

6. 总结

本文介绍了多种编译目录结构中Java源文件的方法:

  • 基础方法:文件名列表(适合少量文件)、通配符(适合少量包)
  • 高效方法:参数文件(需维护文件列表)、Globstar(Bash专属)、管道(跨平台)
  • 踩坑提示:手动指定文件名会遗漏未引用类;参数文件需动态更新;find -exec用分号执行效率低下

根据项目规模和操作系统特性选择合适方案,在没有构建工具的特殊场景下,这些技巧能帮你高效完成编译任务。


原始标题:Compile All Java Classes in Directory Structure with javac