如何强制 Java 编译器只编译我指定的源文件?

How Do To Force Java Compiler to ONLY compile the source file I specify?

java 12.0.1 编译器(我这里的测试都是 运行 在 MS Windows 中)在使用 -sourcepath 参数时有一些非常奇怪的行为,关于什么它决定编译。解释这一点的最简单方法是提供两个示例并引用行为差异。

例1:

源文件"A.java"

public class A {
    public static void main(String[] args) {
        System.out.println("Hello World");
        B.myMethod();
    }
}

源文件"B.java"

public class B {
    public static void myMethod() {
        System.out.println("Goodbye!");
    }
}

要编译示例 1,我们只需使用以下内容:

javac -sourcepath . A.java

这将编译 A.java 和 B.java 并创建 A.class 和 B.class。我们希望它也能编译 B.java 因为 A 依赖于它。现在等一下,不修改任何一个“.java”源文件,只需重新运行上面的编译命令。你会发现它重新编译了 A.java 并创建了一个新的 A.class(带有更新的时间戳),但是 B.class 没有被重新编译。好的,这几乎是人们所期望的。现在让我们将其与下面的下一个示例进行比较。

例二:

源文件"example2/A.java"

package example2;
public class A {
    public static void main(String[] args) {
        System.out.println("Hello World");
        B.myMethod();
    }
}

源文件"example2/B.java"

package example2;
public class B {
    public static void myMethod() {
        System.out.println("Goodbye!");
    }
}

源文件是一样的,除了所有的东西都被移动到一个包中。我们想要编译当前位于 "example2" 文件夹中的两个源文件。所以我们使用以下命令:

javac -sourcepath .. A.java

这将再次编译 A.java 和 B.java 并创建 A.class 和 B.class。这里没有问题,和以前一样。请注意,-sourcepath 现在是“..”,因为那是 "root" 源文件夹,现在所有内容都在一个包中。现在等一下,不修改任何一个源文件,只需重新运行上面的编译命令。您会发现它会重新编译 A.java 和 B.java 并创建一个新的 A.class 和 B.class 文件(具有更新的时间戳)。

请注意 javac 命令第二次为 运行 时编译行为的差异。当 -sourcefile 为“.”时并且文件不在包中,第二个 "javac" 命令只编译命令行指定的源文件。但是当 -sourcefile 是“..”并且 classes 在一个包中时,第二个 "javac" 命令总是编译所有依赖的源文件,无论是否需要重新编译未指定的源文件.

问题是为什么?如果 class 文件的时间戳比源文件更新,我可以将哪些参数传递给 javac 命令行以阻止示例 2 无条件地重新编译所有相关源文件?

编辑:我已经删除了我认为这是一个错误的建议,因为我接受了另一个答案作为最佳解释。

顺便说一句,似乎没有明智的方法将此作为错误报告给 OpenJDK。我在 OpenJDK 网站上用谷歌搜索,似乎 bugs.openjdk.java.net 仅适用于受信任的开发人员。我想我可以把它扔到 OpenJDK 邮件列表中,但这似乎是一个 hack。所以我什至不确定在哪里报告这个错误,遗憾的是。

出现此问题是因为 javac 比较 .java 文件和 .class 文件之间的时间戳。它使用 -sourcepath 查找源文件,使用 -classpath 查找 class 文件。因此,您的问题可以通过指定 classpath:

来解决
javac -sourcepath .. -classpath .. A.java

这似乎与 .. 有关。如果你去源码根目录,默认包:

cd ..
javac -sourcepath . ex/A.java

一切正常(在我这里):没有重新编译 B.java。

这也可能是由于 -classpath 造成的,但我宁愿考虑一些与包路径有关的深奥问题。