java编译器如何解析未导入的名称
假设我在包java编译器如何解析未导入的名称,java,import,token-name-resolution,package-private,Java,Import,Token Name Resolution,Package Private,假设我在包foo.bar中的java编译单元中使用类型X,并且X未在编译单元本身中定义,也未直接导入。java编译器现在如何高效地解析X?X可能存在以下几种可能性: X可以通过星型导入a.b.* X可能与编译单元位于同一个包中 X可能是一种语言类型,即驻留在java.lang 我看到的问题尤其严重。由于X可能是包私有类型,因此甚至不要求X驻留在名为X.java的编译单元中。因此,编译器必须查看类路径的所有条目并搜索包foo.bar中的任何类,然后必须读取包foo.bar中的每个类,以检查是否包含
foo.bar
中的java编译单元中使用类型X
,并且X
未在编译单元本身中定义,也未直接导入。java编译器现在如何高效地解析X
?X
可能存在以下几种可能性:
X
可以通过星型导入a.b.*
X
可能与编译单元位于同一个包中X
可能是一种语言类型,即驻留在java.lang
X
可能是包私有类型,因此甚至不要求X
驻留在名为X.java
的编译单元中。因此,编译器必须查看类路径的所有条目并搜索包foo.bar
中的任何类,然后必须读取包foo.bar
中的每个类,以检查是否包含X
听起来很贵。特别是当我只编译一个文件时,编译器必须读取几十个类文件才能找到类型X
。如果我使用了大量的星型导入,那么对于许多类型,必须重复这个过程(当然,类文件不会被读取两次)
因此,建议也从同一个包中导入类型以加快编译过程吗?或者有没有更快的方法来解析我找不到的未变形类型X
因此,编译器必须查看类路径的所有条目,并在包foo.bar中搜索任何类
这只是Class.forName()
然后,它必须读取包foo.bar中的每个类,以检查是否包含X
我不知道这是什么意思
在通过class.forName()查找.class文件之后,
它必须在当前包的源路径中查找具有适当名称的文件,该文件就是新文件(…).exists()
等
我不相信它会在每个文件中查找该名称的非公共类:您必须尝试一下。如果是的话,这确实是一个昂贵的步骤,但我不相信它已经采取了
听起来很贵
如果编译器那样做的话,代价会很高
但实际上,它构建了一个内存中的数据结构,其中包含类路径、bootclasspath和sourcepath上的所有类名,并将其用于javac
运行中编译的所有类中的所有类名解析
因此,建议也从同一个包中导入类型以加快编译过程吗?或者有没有一种更快的方法来解决我找不到的未损坏的X型问题
不,不。这几乎没有什么区别。此外,如果您按照编译器的设计使用它,那么这不太可能成为一个重要的瓶颈
最好以提供最可读和最可靠代码的方式进行导入。您的计算机速度很快。找到类的引用不会花费很长时间。另外,可能会缓存Java库以缩短编译时间。不确定。当你说“当我只编译一个文件”时,你的意思是当我更改一个
.java
文件然后再编译时?我不敢相信这是一个在当今时代你需要担心的问题。如果这是一个纯粹的理论问题,我就不用担心了。如果你发现自己的表现很糟糕,那么再多告诉我们一点,也许我们可以做些什么来帮助你。@Duncan:嗯,大型项目的java构建恰好需要相当长的时间。如果为同一个包中的所有类添加导入可以减少编译时间20%,那么添加这些导入是值得的。因此,这个问题不是纯粹的理论问题。@gexicide也许你应该尝试一些实验?我仍然认为这不会有任何区别,而且您在大型项目上看到的大量编译时间是不相关的。您忽略了sourcepath的操作。证据将在编译器源代码中。但是您可以从forName
实际加载类字节码并链接它们这一事实推断出这一点。字节码编译器不需要这样做,这样做会浪费CPU和内存。我的理解是,编译器有自己的类文件读取器,它只读取编译器需要的符号表信息。