JAVAC原理「建议收藏」

JAVAC原理「建议收藏」前言本文是对compilation-overview的翻译.如有翻译不对的地方,还望海涵.正文将一组源文件编译成相应的一组类文件的过程并不简单,但是通常可以分为三个阶段。源文件的不同部分可以在“按需”的基础上以不同的速率进行处理。这个过程是由JavaCompiler类来处理的:将命令行上指定的源文件进行读取,解析为语法树,然后将所有外部可见的定义都输入到编译器的…

大家好,又见面了,我是你们的朋友全栈君。

前言

本文是对 compilation-overview 的翻译. 如有翻译不对的地方,还望海涵.

正文

将一组源文件编译成相应的一组类文件的过程并不简单,但是通常可以分为三个阶段。源文件的不同部分可以在“按需”的基础上以不同的速率进行处理。

javac原理

这个过程是由JavaCompiler类来处理的:

  1. 将命令行上指定的源文件进行读取,解析为语法树,然后将所有外部可见的定义都输入到编译器的符号表中
  2. 在编译的过程中会调用适当的注解处理器.如果在调用过程中,生成了新的资源文件或者类文件,则重新进行编译,直到没有新文件创建为止
  3. 最后,对语法分析器生成的语法树进行分析,并将其转换为类文件。在分析过程中,可以找到对其他类的引用。编译器将检查这些类的源和类路径;如果在源路径上找到它们,那么这些文件也将被编译,尽管它们不会受到注释处理的影响。

解析和输入

源文件是被Scanner按照Unicode 编码来处理的同时转化为token流.

token流由解析器读取,使用TreeMaker创建语法树。语法树是从JCTree的子类型构建的,它实现了com.sun.source.Tree 和它的子类.

每一个树都被交给Enter类来进行处理,它会将所遇到的符号都输入到符号表中.这必须在分析树是否会引用这些符号前完成.这个阶段的输出是一个待办事项列表(TO DO list),包含需要分析并生成类文件的树.

输入由多个阶段组成;类通过队列从一个阶段迁移到下一个阶段.

Enter

  1. 在第一个阶段,所有类符号都被输入到它们的封闭范围(enclosing scope,也许可以翻译为定义域?)中,对于内部类,它们沿着树递归下降的输入到封闭范围。类符号被赋予一个成员对象作为完成符。
    此外,如果找到包含包注释的package-info.java文件,则该文件的顶级树节点也放在To Do列表中

  2. 在第二个阶段,类通过MemberEnter.complete()方法来进行处理(completed , 使类变得完整).使类变得完整可能是按需发生的,但是任何未以这种方式完成的类最终将通过处理未完成队列来完成.使一个类完成需要如下条件:

    1. 确定类的泛型参数,父类,接口
    2. 将该类的所有符号输入到它所对应的scope,当该类在第一点已经输入时会产生错误.

    第2点依赖于第一点已经完成了一个类及其所有的超类和外部类.这就是为什么在做(1)之后,我们把类放在一个半完成的队列中。只有当我们对一个类进行了(1)和它的所有超类和外部类时,我们才进行(2).

  3. 在输入所有符号之后,将对这些符号上遇到的任何注解进行分析和验证。

虽然第一阶段被组织成扫描所有编译的语法树,但第二阶段是按需进行的。类的成员是在第一次访问类的内容时输入的。这是通过在编译后的类的类符号中安装completer对象来实现的,编译后的类为对应的类树调用MemberEnter阶段。

注解处理

这部分是由JavacProcessingEnvironment 来进行处理的

从概念上讲,注释处理是编译前的一个准备步骤.这个准备步骤包括一系列循环,每个循环用于解析和输入源文件,然后确定和调用任何适当的注解处理器.在第一次循环之后,如果任何被调用的注解处理器生成任何需要成为最终编译一部分的新源文件或类文件,则将执行后续循环。最后,当完成所有必要的循环时,执行实际编译。

3

实际上,在解析要编译的文件并确定它们包含的声明之前,可能不知道需要调用哪个注解处理器。因此,为了避免在没有执行注释处理的情况下不必要地解析和输入源文件,JavacProcessingEnvironment与概念模型执行“不同步”,同时仍然满足注解处理作为一个整体在实际编译之前发生的概念要求。

4

JavacProcessingEnvironment在文件已经被解析并输入之后被调用。它决定是否需要加载任何注解处理器,并调用任何正在编译的文件.通常,如果在整个编译过程中出现任何错误,则在下一个convenient point停止该过程.但是,如果在Enter阶段检测到任何丢失的符号,则会发生异常,因为调用注解处理器可以生成这些符号的定义。

如果要运行注解处理器,则在单独的类加载器加载并运行它们.

在运行注解处理器时,JavacProcessingEnvironment确定是否需要另一轮注解处理.如果是,它创建一个新的JavaCompiler对象,读取需要解析的任何新生成的源文件,并重用任何以前解析过的语法树。所有这些树都被输入到这个新编译器实例的符号表中,并在必要时调用注解处理器。重复这一步骤,直到不再需要更多的注解处理。

最后,JavacProcessingEnvironment返回用于编译其余部分的JavaCompiler对象。这将是用于解析和输入初始文件集的原始实例,或者它将是用于开始最后一轮编译JavacProcessingEnvironment创建的最新实例.

分析和生成

一旦命令行上指定的所有文件都被解析并输入到编译器的符号表中,并且注解处理完之后,JavaCompiler就可以继续分析被解析的语法树,以便生成相应的类文件.

在分析树时,可以找到对成功编译所需的类(但未明确指定用于编译的类)的引用。根据编译选项,将根据搜索源路径和类路径来搜索这些类的定义.如果定义在类文件中找到,则读取类文件以确定该类中的定义;如果定义在源文件中找到,则源文件将自动解析、输入并放到“待办事项”列表中。这是通过注册JavaCompiler作为Attr.SourceCompleter的一个实现来完成的。

分析树和生成类文件的工作是由一系列visitor 执行的,这些访问者处理编译器的To Do列表上的条目。唯一的要求是,To Do列表中的每个条目最终都应该由这些visitor来处理,除非由于错误而提前终止编译。

Attr(属性标记)

顶层类认为是"属性标记过的",当使用Attr,将语法树中的名称、表达式和其他元素被解析并与相应的类型和符号相关联.许多语义错误可以在这里被检测,无论是通过Attr,还是通过检查。

Flow(数据流分析)

如果到目前为止还没有错误,则使用数据流分析对类进行分析。数据流分析用于检查变量的确定分配和不可到达的语句,这可能导致额外的错误 

TransTypes

使用TransTypes将泛型类型的代码转换为没有泛型类型的代码,

Lower(强度削弱)

“语法糖”是使用Lower进行处理的,它重写语法树以通过替换等价的、简单的树来消除特定类型的子树。这需要处理嵌套和内部类、类中的字面量、断言、Frach循环等等。对于处理的每个类,Lower返回已转换的类及其所有已转换的嵌套类和内部类的树列表

虽然Lower通常处理顶级类,但它也将处理顶级的package-info.java。对于这样的树,Lower将创建一个合成类来包含包的任何注解

Gen(字节码生成)

方法的代码由Gen生成,它创建包含JVM执行方法所需的字节码的Code属性。如果这一步成功了,则这个类是由ClassWriter写出来的

一旦类被写成一个类文件,就不再需要它的语法树和生成的字节码。为了节省内存,对树和符号的这些部分的引用将被取消,以允许垃圾收集器恢复内存。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/140324.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 周鸿祎博客:谷歌Chrome不是浏览器 说的不错

    周鸿祎博客:谷歌Chrome不是浏览器 说的不错http://blog.sina.com.cn/s/blog_49f9228d0100aj4o.html?tj=1

  • java+sm4+加密算法_SM4加密算法实现Java和C#相互加密解密

    java+sm4+加密算法_SM4加密算法实现Java和C#相互加密解密SM4加密算法实现Java和C#相互加密解密近期由于项目需要使用SM4对数据进行加密,然后传给Java后台,Java后台使用的也是SM4的加密算法但是就是解密不正确,经过一步步调试发现Java中好多数据类型与C#的相同的数据类型是存在不同的比如:byte在Java中范围是-127~128,而C#中的范围是0~255,这就导致使用C#的加密的明文产生的密文到Java中解密不正确。再一次偶尔的上网中看…

  • C#中write和writeline的区别「建议收藏」

    writeLine:将要输出的字符串与换行控制字符一起输出,当次语句执行完毕时候,光标会移到目前输出字符串的下一行。例如:write:光标会停在输出字符串的最后一个字符,不会移动到下一行。writeLine实例运行效果如下图:write实例运行效果如下图:…

  • #2006 – MySQL server has gone away 问题解决方法

    #2006 – MySQL server has gone away 问题解决方法

    2021年11月23日
  • 10个JS常见算法题目

    10个JS常见算法题目1、冒泡排序调优(从小到大排序)2、输出九九乘法表3、输出水仙花数4、1–10的阶乘和5、输出1900年至2100年中的所有闰年6、输出10–100之间的所有素数7、1,2,3,4四个数字,能组合成多少种互不相同且没有重复的三位数8、取出四位数中的各个位上的数字9、猴子吃桃问题10、用星号输出菱形。源码如下:js算法题目练习&…

  • cookie登录知乎「建议收藏」

    用cookie登录个人知乎主页步骤:1、用自己账号登录知乎,然后复制下来自己的cookie信息。2、用request.get(url,headers=headers)把cookie传入get请求中3、用BeautifulSoup匹配内容一、用自己账号登录知乎,获取自己的cookie信息。二、构造请求函数,并把cookie信息加入…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号