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. DataTables 1.10.x与1.9.x参数名对照表

    Datatables 1.10.x在命名上与1.9.x的有区别,新版的使用的是驼峰的命名规则,而之前的是采用匈牙利命名规则 当然,这些变化都是向下兼容的,你可以继续使用旧版本的api方法的参数和名称. ...

  2. JS排序算法之快速排序

    const Arr = [85, 24, 63, 45, 17, 31, 96, 50]; function quickSort(arr) { 80 if (arr.length <= 1) { ...

  3. Office系列版本安装包下载

    链接:http://pan.baidu.com/s/1i4UFZOp  密码:f9y8 链接:http://pan.baidu.com/s/1i4YJN4D 密码:743q 链接:http://pan ...

  4. Windows不能在本地计算机启动MongoDB,错误代码 100

    今天在计算机上面启动MongoDB时,直接给我报错,Windows不能在本地计算机启动MongoDB,服务错误代码 100. 这种问题解决方法是: 找到data文件夹db下面的mongod.lock文 ...

  5. 使用JSONP实现跨域通信

    引语 Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索.Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索.由于受到浏览器的限制,该方法不允许 ...

  6. Route pattern cannot reference variable name more than once

    在用 Laravel Backpack 写一个定制化的 CRUD 页面.例如,一个指定店铺所拥有的商品的 CRUD 页面. 起初路由我是这样写的 CRUD::resource('products-of ...

  7. CF 449D 题解(状压+容斥)

    状压妙啊... 本题的主体思路:状压+容斥原理(或状压+数位dp) 记g[i]表示按位与后结果所有位上至少有i个1的方案数 那么根据容斥原理,ans=g[0]-g[1]+g[2]-g[3]+g[4]. ...

  8. pytest八:skip 跳过用例

    这是一个快速指南,介绍如何在不同情况下跳过模块中的测试1.无条件地跳过模块中的所有测试:pytestmark = pytest.mark.skip("all tests still WIP& ...

  9. 内联外联CSS和JS

    内联CSS 代码示例: <p style="color:red;font-size:18px">这里文字是红色.</p> 内联CSS也可称为行内CSS或者行 ...

  10. websocket+Django+python+paramiko实现web页面执行命令并实时输出

    一.概述 WebSocket WebSocket的工作流程:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 T ...