Javac编译过程「建议收藏」

Javac编译过程「建议收藏」Javac编译过程大致分为4个过程,分别是:词法分析语法分析语义分析代码生成词法分析  词法分析是将源代码的字符流转变为标记(Token)集合,单个字符是程序编写过程的最小元素,而标记则是编译过程的最小元素,关键字、变量名、字面量、运算符都可以成为编辑,如“inta+b=2”这句代码中包含了6个标记,分别是int、a、=、b、+、2,虽然关键字int由三个字符构成,但是

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


欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。
Javac编译过程「建议收藏」


欢迎跳转到本文的原文链接:https://honeypps.com/java/javac-compile-process/

  Javac编译过程大致分为4个过程,分别是:

  1. 词法分析
  2. 语法分析
  3. 语义分析
  4. 代码生成

##词法分析
  词法分析是将源代码的字符流转变为标记(Token)集合,单个字符是程序编写过程的最小元素,而标记则是编译过程的最小元素,关键字、变量名、字面量、运算符都可以成为编辑,如“int a+b=2”这句代码中包含了6个标记,分别是int、a、=、b、+、2,虽然关键字int由三个字符构成,但是它只是一个Token,不可再拆分。在Javac的源码中,词法分析过程由com.sun.tools.javac.parser.Scanner类来实现。


##语法分析

  词法分析器的作用是将Java源文件的字符流转变成对应的Token流。而语法分析器是将词法分析器分的Token流组件成更加结构化的语法树,也就是将一个个单词组装成一句话,一个完整的语句。哪些词语组合在一起是主语,哪些是谓语、哪些是宾语、哪些是定语等没要做进一步区分。
  语法分析是根据Token序列构造抽象语法树的过程,抽象语法树是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点都代表着程序代码中的一个语法结构,例如包、类型、修饰符、运算符、接口、返回值甚至代码注释等都可以是一个语法结构。语法分析过程由com.sun.tools.javac.parser.Parser类实现,这个阶段产出的抽象语法树由com.sun.tools.javc.tree.JCTree类表示,经过这个步骤之后,编译器就基本不会再对源码文件进行操作了,后续的操作都是建立在抽象语法树上。


##语义分析
  语法分析之后,编译器获得了程序代码的抽象语法树表示,语法树能表示一个结构正确的源程序的抽象,但无法保证源程序是符合逻辑的。语义分析是要在语法树的基础上再做一些处理,如给类添加默认的构造函数,检查变量在使用前是否已经初始化,将一些常量进行合并处理,检查操作变量类型是否匹配,检查所有的操作语句是否可达,检查checked exception是否正确处理。
  语义分析阶段分为:填充符号表、标注检查、数据及控制流分析。

填充符号表
  符号表是由一组符号地址和符号信息构成的表格,读者可以把它想象成哈希表K-V值对的形式。符号表中所登记的信息在编译的不同阶段都要用到。在语义分析中,符号表所登记的内容将用于语义检测和产生中间代码。在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据。在Javac源码中,填充符号表的过程由com.sun.tools.javac.comp.Enter类实现。
  一个类除了类本身会定义一些符号变量如类名称、变量名称和方法名称等,还有一些符号是引用其它类的,这些符号会调用其它类的方法或者变量等,还有一些类可能会继承或者实现超类和接口等。这些符号都是在其他类中定义的,那么就需要将这些类的符号也解析到符号表中。
  在Enter类解析这一步骤中,还有一个重要的步骤就是添加默认的构造函数。如果代码中没有提供任何构造函数,那么编译器将会添加一个没有参数、访问下与当前一致的默认构造函数。

标注检查
  检查的内容包括诸如变量的类型是否匹配、变量在使用前是否已经初始化、能够推导出泛型方法的参数类型、字符串常量的合并(常量折叠)。在标注检查步骤中一个重要的动作称为常量折叠,如果我们在代码中写了如下定义:

int a=1+2;

  那么在语法树上仍然能看到字面量1、2以及操作符+,但是在进过常量折叠之后,他们将会被折叠为字面量3.实现的类是com.sun.tools.javac.comp.Attr类和com.sun.tools.javac.comp.Check类。

数据流分析
  数据流主要完成如下工作:

  • 检查变量在使用前是否都已经被正确赋值。
  • 保证final修饰的变量不会被重复赋值。
  • 要确定方法的返回值类型。这里需要检查方法的返回值类型是否确定,并检查接受这个方法返回值的引用类型是否匹配,如果没有返回值,则不能有任何引用类型指向方法的这个返回值。
  • 所有的Checked Exception都要捕获或者向上抛出。
  • 所有的语句都要被执行到。这里会检查是否有语句出现在一个return方法的后面,因为在return方法后面的语句永远也不会被执行到。

控制流分析
  控制流主要完成如下工作:

  • 去掉无用的代码,比如永假的if代码块。
  • 变量的自动转换,比如自动装箱拆箱。
  • 去除语法糖。解语法糖的过程由desugar()方法触发,在com.sun.tools.javac.comp.TransTypes和com.sun.tools.javac.comp.Lower类中完成。
    数据流及控制流的分析入口是flow()方法,具体操作由com.sun.tools.javac.comp.Flow类来完成。

##字节码生成
  由com.sun.tools.javac.jvm.Gen类来完成。字节码阶段不仅仅把前面各个步骤所生成的信息(语法树、符号表)转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。
实例构造器<init>方法和类构造器<clinit>方法就是在这个阶段添加到语法树中的。
  生成java字节码需要经过以下两个步骤:

  • 将java方法中的代码块转化成符合JVM语法的命令形式,JVM的操作都是基于栈的,所有的操作都必须经过出栈和进栈来完成。
  • 按照JVM的文件组织格式将字节码输出到以class为扩展名的文件中。

  在jdk1.5之后,java语言提供了对注解(Annotation)的支持,这些注解与普通的Java代码一样,是在运行期间发挥作用的。在Jdk1.6中提供了一组插入式注解处理器的标准API在编译期间对注解进行处理,我们可以把它看做是一组编译器的插件,在这些插件里面,可以读取、修改、添加抽象语法树中的任意元素。如果这些插件在处理注解期间对语法树进行了修改,编译器将回到解析及填充符号表的过程重新处理,直到所有插入式注解处理器都没有再对语法树进行修改为止。对注解的处理是在填充符号表之后及在标注注解之前发生的。


##参考

  1. 《深入理解Java虚拟机》周志明著。
  2. 《深入分析Java Web技术内幕》许令波著。

欢迎跳转到本文的原文链接:https://honeypps.com/java/javac-compile-process/

欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。
Javac编译过程「建议收藏」


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

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

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

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

(0)


相关推荐

  • 文件上传-文件名长度绕过白名单限制[通俗易懂]

    文件上传-文件名长度绕过白名单限制[通俗易懂]  在实际***中,当我们发现有文件上传的地方时,我们会尽可能地尝试所有的办法进行webshell的上传,只要能上传webshell,就说明本次***至少成功了一半,后续就看获得的webshell的权限情况进行下一步的操作。对于文件上传漏洞的防护来说,主要分为以下两类:白名单限制和黑名单限制,对于黑名单的限制,我们只需要寻找一些较为偏僻的可执行后缀、大小写混写以及相关操作系统的特性(如windo…

    2022年10月19日
  • C#QuotedStr方法实现,引号的处理

    C#QuotedStr方法实现,引号的处理在Delphi中处理引号有QuotedStr函数,但C#中却没有相应的处理!所以转换了Delphi的代码为C#中来处理。。以下为代码!protectedstringQuotedStr(stringS){stringvResult;vResult=S;for(inti

    2022年10月17日
  • 显示适配器virtual display device_电脑怎么设置虚拟显示器

    显示适配器virtual display device_电脑怎么设置虚拟显示器根据包括微软研究院在内的许多最新研究,多显示器系统以及更大的显示器可将用户工作效率提高10%至50%。然而,多显示器采用的增长以及大屏幕显示器受到以下几个因素的影响:虚拟显示管理器通过额外的虚拟显示器的便利性来补充您现有的单显示器或多显示器系统,这些虚拟显示器可以细分现有的物理屏幕,同时使用现有硬件以及单击按钮调用不同显示器配置的能力。VDM的虚拟显示技术提供了物理显示器的外观和感觉,并且需要对最终用户进行最少的重新培训。许可证区别虚拟显示管理器提供两个不同的许可证。CL–控制台许可证和MUL

  • spidermonkey php,javascript SpiderMonkey中的函数序列化如何进行_基础知识[通俗易懂]

    spidermonkey php,javascript SpiderMonkey中的函数序列化如何进行_基础知识[通俗易懂]在Javascript中,函数可以很容易的被序列化(字符串化),也就是得到函数的源码.但其实这个操作的内部实现(引擎实现)并不是你想象的那么简单.SpiderMonkey中一共使用过两种函数序列化的技术:一种是利用反编译器(decompiler)将函数编译后的字节码反编译成源码字符串,另一种是在将函数编译成字节码之前就把函数源码压缩并存储下来,用到的时候再解压还原.如何进行函数序列化在Spider…

    2022年10月10日
  • 公网ip远程访问nas_无公网ip访问家庭nas

    公网ip远程访问nas_无公网ip访问家庭nas2018-12-0113:45:00770点赞5996收藏566评论上次的那篇NAS的文章有着很不错的热度,首先是感谢观众老爷们的大力支持啦,那么这篇文章主要是回答一些评论中的问题,而且也为那些第一次接触NAS的小伙伴提供一个简单的参考,如果对这方面想有所了解的,请耐心阅读下面的内容,个人记忆力有限,有些东西记不起来了,如有遗漏或者错误,请斧正。废话不多说,我们开始。如何申请公网IP这个是大家问的最多的,而且许多问题的根本原因都是公网IP造成的,那么,首先我们要知道一点基础的…

  • height:100%失败

    height:100%失败

发表回复

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

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