java语言的“编译期”其实是一段“不确定”的操作过程,可能是指一个前端编译器把.java变成.class的过程,也可能是指虚拟机的后端运行期编译器(JLT)把字节码转变成机器码的过程,也有可能是使用静态提前编译器(AOT)直接把.java文件直接编译成本地机器代码的过程。现在讨论的是第一种编译器。

Javac编译器

①javac的源码与测试

 

运行com.sun.tools.javac.Main的main()方法来执行编译,与命令行中使用javac的命令没什么区别.

编译过程可以分为3个过程:

1.解析与填充符号表过程

2.插入式注解处理器的注解处理过程

3.分析与字节码生成过程

②解析与填充符号表

解析步骤由parseFiles完成。解析步骤包括词法解析与语法解析两个过程

1.词法、语法解析:

词法解析是将字符流转变为标记集合,单个字符是程序编写过程中最小的元素,而标记是编译过程的最小元素,关键字、变量名、字面量、运算符都可以称为标记。

语法分析是根据标记构造抽象语法树的过程,抽象语法树的每一个节点都代表着代码中的一个语法结构,例如包,类型、修饰符、运算符、接口、返回值甚至代码注释等。经过这个步骤以后编译器基本上就不会对源文件进行操作了,后续的操作都建立在抽象语法树之上。

2.填充符号表

③注解处理器

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

④语义分析和字节码生成

语法分析以后,能保证得到一个结构正确的源程序的抽象,但无法保证是符合逻辑的。语义分析的主要任务是对结构上正确的源程序进行上下文有关性质的审查,如进行类型检查。

比如:

int a=;
boolean b=false;
char c=
----------------------------------------------------------------
int d=a+c; //编译通过
int d =b+c;//编译错误
char d=a+c//编译错误

三个操作都能形成正确的语法树,但是却无法通过编译。

 标注检查

语义分析分为标注检查以及数据及控制流分析两个步骤,分别对应attribute方法和flow()方法。

标注检查的内容包括诸如变量使用前是否已被声明、变量和赋值之间的数据类型是否能够匹配等。在标注检查步骤中,还有一个重要的动作称为常量折叠,如果在代码中定义了

int a=+

在语法树上仍然能看到1,2,+,但是经过常量折叠,这个插入式表达式的值已经在语法树上标注出来了。由于编译期间进行了常量折叠,所以在代码里面定义a=1+2和a=3没有什么区别。

数据及控制流分析

对程序上下文逻辑更进一步的验证,可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理了异常等问题。与类加载时期的数据及控制流分析基本上是一致的,但校检范围由锁区别

//方法1带有final修饰
public void foo(final int arg){ final int var=;
}
//方法2没有final修饰
public void foo(int arg){ int var=;
}

将局部变量在常量池中没有符号引用,也就没有访问标志的信息,因此将局部变量声明为final,对运行期是没有影响的,变量的不变性仅仅有编译器在编译期间保证。

③解语法糖

语法糖指在计算机语言中添加的某种语法,这种语法对语言的功能并没与影响,但是更方便程序员使用。

java中最常用的语法糖主要是泛型、变长参数、自动装箱/拆箱等,虚拟机运行时不支持这些语法,它们在编译阶段还原回简单的基础语法结构,这个过程称为解语法糖。

④字节码生成

字节码生成是javac编译过程的最后一个阶段。字节码生成阶段不仅仅把前面各个步骤所生成的信息转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。

实例构造器<init>()和类构造器<clinit>()方法就是在这个阶段添加到语法树之中的(这里的实例构造器不是指默认函数,如果用户代码中没有提供任何构造函数,那编译器将会添加一个午餐的构造函数,这个工作在填充符号表节段就已经完成了)。这两个构造器的产生过程实际上是一个代码收敛的过程。

<init>()收敛顺序(这里只讨论非静态变量和语句块)为: 
1. 父类变量初始化 
2. 父类语句块 
3. 父类构造函数 
4. 子类变量初始化 
5. 子类语句块 
6. 子类构造函数

<init>()是在new之后才使用的。

<clinit>()

收敛顺序为: 
1. 父类静态变量初始化 
2. 父类静态语句块 
3. 子类静态变量初始化 
4. 子类静态语句块

<clinit>()是类加载初始化中使用的。

早期(编译器)优化--javac编译器的更多相关文章

  1. 早期javac编译器优化

    学习<深入了解Java虚拟机>有一段时间了,大概理解了Java从源代码编译到执行出结果的过程,也能明确的知道Java是半解释性语言.在执行源代码时,先通过Javac编译器对源代码进行词法分 ...

  2. Javac编译器详解

    学习<深入了解Java虚拟机>有一段时间了,大概理解了Java从源代码编译到执行出结果的过程,也能明确的知道Java是半解释性语言.在执行源代码时,先通过Javac编译器对源代码进行词法分 ...

  3. C++中volatile及编译器优化

    首先看一下单词"volatile"的释义: volatile [ˈvɑlətl] adj.  易变的,不稳定的; (液体或油)易挥发的; 爆炸性的; 快活的,轻快的; 下边是&qu ...

  4. java编译器优化和运行期优化

    概述    最近在看jvm优化,总结一下学习的相关知识 (一)javac编译器 编译过程 1.解析与填充符号表过程 1).词法.语法分析    词法分析将源代码的字符流转变为标记集合,单个字符是程序编 ...

  5. 探索c#之尾递归编译器优化

    阅读目录: 递归运用 尾递归优化 编译器优化 递归运用 一个函数直接或间接的调用自身,这个函数即可叫做递归函数. 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果. 递归最重 ...

  6. VS编译器优化诱发一个的Bug

    VS编译器优化诱发一个的Bug Bug的背景 我正在把某个C++下的驱动程序移植到C下,前几天发生了一个比较诡异的问题. 驱动程序有一个bug,但是这个bug只能 Win32 Release 版本下的 ...

  7. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part6:Move语义和编译器优化

    本文为第六部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  8. Visual C++中的编译器优化

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:Visual C++中的编译器优化.

  9. gcc编译器优化给我们带来的麻烦???

    gcc编译器优化给我们带来的麻烦??? 今天看到一个很有趣的程序,如下: ? 1 2 3 4 5 6 7 8 9 int main() {     const int a = 1;     int * ...

随机推荐

  1. nodejs xpath

    var fs = require('fs');var xpath = require('xpath');var dom = require('xmldom').DOMParser; // Read t ...

  2. 017_mac格式化硬盘,mac如何格式化硬盘

    想做一个mac和windows都能识别的系统,推荐设置成什么格式 一.在mac下格式化 在Mac 下,打开右下角应用程序-实用工具-磁盘工具,里面选取你的移动硬盘,然后进行格式化,设置成EXFat格式 ...

  3. 006_netstat中state详解

    TCP三次握手的过程如下: 主动连接端发送一个SYN包给被动连接端: 被动连接端收到SYN包后,发送一个带ACK和SYN标志的包给主动连接端: 主动连接端发送一个带ACK标志的包给被动连接端,握手动作 ...

  4. urllib处理包的简单使用

    我们可以使用urllib.request.urlopen()这个接口函数就可以打开一个网站,读取打印信息 你可以现在终端使用python from urllib import request if _ ...

  5. 深入理解【缺页中断】及FIFO、LRU、OPT这三种置换算法

    缺页中断(英语:Page fault,又名硬错误.硬中断.分页错误.寻页缺失.缺页中断.页故障等)指的是当软件试图访问已映射在虚拟地址空间中,但是目前并未被加载在物理内存中的一个分页时,由中央处理器的 ...

  6. js实现页面重定向

    在现行的网站应用中URL重定向的应用有很多: 404页面处理.网址改变(t.sina转到weibo.com).多个网站地址(如:http://www.google.com/ .www.g.cn )等: ...

  7. process.cwd()与__dirname的区别

    process.cwd() 是当前执行node命令时候的文件夹地址 ——工作目录,保证了文件在不同的目录下执行时,路径始终不变__dirname 是被执行的js 文件的地址 ——文件所在目录 Node ...

  8. HDFS上创建文件、写入内容

    1.创建文件 hdfs dfs -touchz /aaa/aa.txt 2.写入内容 echo "<Text to append>" | hdfs dfs -appen ...

  9. ruby学习--条件控制

    条件控制 本人喜欢用程序demo记录的方式来记录某方法的使用,如times方法,仅作个人学习记录 #--------------if语句(相反是unless)而while相同于until------- ...

  10. Ext.js入门(二)

        ExtJs OOP基础 一:ExtJs中的面向对象 1.ExtJs中命名空间的定义        Ext中的命名空间类似于C#中的namespace和java中的包,用来对工程中的类进行更好的 ...