参考 Oracle 文档,SCJP 书中的陈述可能过于简单化。 Oracle 文档明确区分了“Java Launcher”(java
) 和 Java 编译器javac
。事实上,过程有些不同。
我将尝试提取解释您所观察到的行为的相关部分:
(From How Classes are Found : How Javac and JavaDoc Find Classes http://docs.oracle.com/javase/7/docs/technotes/tools/findingclasses.html#srcfiles:)
如果在类文件和源文件中都定义了引用的类,[...] javac 将使用类文件,但会自动重新编译它确定为过时的任何类文件。自动重新编译的规则记录在 javac 文档中:Windows http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html or Solaris http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javac.html.
这些链接的文档包含相应的小节(在两种情况下都是相同的),我将再次在此引用:
(From javac - Java programming language compiler : SEARCHING FOR TYPES http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#searching:)
编译源文件时,编译器通常需要有关其定义未出现在命令行给出的源文件中的类型的信息。 [...]
当编译器需要类型信息时,它会查找定义类型的源文件或类文件。 [...]
成功的类型搜索可能会生成类文件、源文件或两者。如果两者都找到,您可以使用-Xprefer
指示编译器使用哪个选项。如果newer给出后,编译器将使用两个文件中较新的一个。如果source给出后,它将使用源文件。默认为newer.
如果类型搜索找到所需类型的源文件(无论是其本身还是作为设置的结果)-Xprefer
,编译器会读取源文件来获取它需要的信息。此外,它默认也会编译源文件。您可以使用-implicit
指定行为的选项。如果none给出后,不会为源文件生成任何类文件。如果class给出后,将为源文件生成类文件。
总结一下:javac
编译器会找到你的source归档java.util.HashSet
,以及class来自引导程序类的文件。但默认情况下,它会编译source file.
(有趣的是,似乎没有简单的方法可以说服他不要使用来源作为输入:-implicit
选项仅决定是否.class
文件是生成的,但即使-implicit:none
设置后,它仍然会use从源创建的类...)
您还可以使用-verbose
更详细地观看此过程的选项:
javac -verbose java/util/Lol.java
产生以下输出:
[parsing started RegularFileObject[java\util\Lol.java]]
[parsing completed 100ms]
[search path for source files: .]
[search path for class files: (A long list with rt.jar and related JARs)]
[loading RegularFileObject[.\java\util\HashSet.java]]
[parsing started RegularFileObject[.\java\util\HashSet.java]]
[parsing completed 0ms]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Object.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/String.class)]]
[checking java.util.Lol]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/AutoCloseable.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Byte.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Character.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Short.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Long.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Float.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Integer.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Double.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Boolean.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Void.class)]]
java\util\Lol.java:6: error: cannot find symbol
a.add("lol");
^
symbol: method add(String)
location: variable a of type HashSet
[checking java.util.HashSet]
[total 1072ms]
1 error
它甚至不try从引导 JAR 加载 HashSet` 类,而是直接引用源文件:
[loading RegularFileObject[.\java\util\HashSet.java]]
相反,当你省略自己的HashSet
类,您将看到预期的输出:
[parsing started RegularFileObject[java\util\Lol.java]]
[parsing completed 100ms]
[search path for source files: .]
[search path for class files: (A long list with rt.jar and related JARs) ]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/util/HashSet.class)]]
[loading ZipFileIndexFileObject[c:\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Object.class)]]
...
它在哪里获得HashSet
类来自rt.jar
.