【问题标题】:How does javac automatically compile dependencies of a classjavac如何自动编译一个类的依赖
【发布时间】:2015-08-12 04:55:31
【问题描述】:

给定以下目录结构:

/top
   |--- wrk
          |--- pkg
                  |--- A.java
                  |--- B.java

假设A.javaB.java这两个文件分别包含以下代码:

// Filename: A.java
package pkg;
class A { B b; }

// Filename: B.java
package pkg;
class B {...}

假设当前目录为/top/wrk

为什么我们还没有编译B.java,命令javac -cp . pkg/A.java可以成功运行?

另外,如果当前目录是 /top/wrk/pkg,那么命令 javac A.java 有效。为何如此?

【问题讨论】:

  • 答案就在docs.oracle.com/javase/8/docs/technotes/tools/windows/…。没有时间在这里以答案的形式重现这一点,简而言之,粗略地说:它还在类路径中查找源文件。
  • 我无法重现这一点。它无法在我的机器上编译。你确定 B 从未被编译过吗?
  • 这是一个 Mac / Windows 的东西。有关更多详细信息,请参阅我已编辑且现在(希望)确定的答案。

标签: java import package javac


【解决方案1】:

为什么命令 javac -cp 。即使我们还没有编译 B.java,pkg/A.java 也能成功运行

当您编译@​​987654323@ 时,编译器也会编译B.java,因为A.javaB.java 在同一个包中。即使B.javaA.java 位于不同的包中(假设B 是公共的),只要这两个包都存在于wrk 目录中并且您从wrk 目录编译A.java .

Oracle documentationjavac

如果没有指定-sourcepath选项,也会在用户类路径中搜索源文件。

来自Oracle documentCLASSPATH

类路径的默认值为“.”

如果您没有设置CLASSPATH,它将默认为.。随后,sourcepath 也将是 .,因为默认的 sourcepathCLASSPATH 相同。您可以通过使用javac -verbose -g pkg\A.java 编译A.java 来确认默认源路径设置为.。请注意,编译器正在当前目录中查找 .java 文件:

[parsing started pkg\A.java] [parsing completed 29ms] [search path for source files: [.]]

要确认sourcepath 设置为CLASSPATH,您可以尝试使用-cp 选项更改CLASSPATH,方法是使用A.java 编译javac -cp C:\ -verbose -g pkg\A.javaA.java 这次不会编译,因为您已将 CLASSPATH 覆盖为 C:\,这也是 sourcepath 的默认值。这是输出:

[parsing started pkg\A.java] [parsing completed 26ms] [search path for source files: [C:\]] pkg\A.java:3: cannot find symbol symbol : class B

另外,如果当前目录是 /top/wrk/pkg 那么命令 javac A.java 有效。怎么样?

无论B.class 是否存在于pkg 中,这都不起作用

免责声明:我只能在 Windows 上确认这种行为,但我非常怀疑它在其他操作系统上应该有什么不同。

【讨论】:

  • 您能否提供指向指定此行为的 javac 文档的链接?除了指定 -sourcepath,我找不到任何东西。
  • @PhilAnderson 查看我的编辑。您可能在 CLASSPATH 中设置了一些值,因此您的 sourcepath 不默认为 .
  • 感谢 Chetan,但我在 CLASSPATH 中没有任何内容。
  • @PhilAnderson 你可以尝试使用javac -cp . pkg\A.java 编译A.java 吗?如果有效,则确认 sourcepath 默认为 CLASSPATH
  • 根据您的编辑...您说源路径将与类路径相同。你从哪里得到那个的?为什么默认是在与您的类文件相同的文件夹中查找源文件?
【解决方案2】:

编译器必须要么找到并成功编译 B 的源代码,要么找到 B 的 .class,即使它只是一个导入。与加载相反,加载是动态完成的。

查看您的输出目录,您会看到 B 也已编译。即使在不同的包中,它也会被编译,但您必须将其公开以从 A 引用它。

【讨论】:

    【解决方案3】:

    来自Oracle javac docs...

    如果您设置了 -sourcepath 选项,那么编译器会搜索 指示源文件的路径。否则,编译器会搜索 类文件和源文件的用户类路径。 在 Windows 上,-sourcepath 选项似乎是默认设置的,并且您的命令有效。

    但在我的 Mac 上,它失败并给出以下消息...

    A.java:5: error: cannot find symbol
        B b;
        ^
      symbol:   class B
      location: class A
    1 error
    

    要让它自动查找和编译依赖项的源文件,您需要使用 -sourcepath 选项。比如……

    javac -sourcepath ./* A.java

    【讨论】:

    • 看我的回答。我相信源路径默认为CLASSPATH,您的机器上可能设置了CLASSPATH
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 2011-11-17
    • 2020-02-14
    • 2014-06-28
    相关资源
    最近更新 更多