Notes:从Java编译器的角度看类加载过程

本文参考链接:http://blog.csdn.net/ns_code/article/details/18009455


传统的编译器过程:




词义、词法分析(识别token, 如int等标识,分析源代码)  ---> 生成符号表(变量名、函数名等,在这一份编译器会为没有自定义构造函数的类添加默认构造函数) ---> 语义分析(检查变量是否先声明后赋值、类型是否匹配,异常是否得到处理,数组是否越界等) ---> 生成抽象语法树(编译器从此脱离源码) ---> 字节码(字节码生成阶段不仅仅是把前面各个步骤所生成的信息转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。 实例构造器<init>()方法和类构造器<clinit>()方法就是在这个阶段添加到语法树之中的,这里指的是自定义的构造器)


接下来根据不同的语言编译器有不同的做法:


C++/ C的编译器,如VC和GCC就会把生成的字节码,继续编译成被机器直接执行的机器码

字节码 --> 优化器(可选) --> 中间代码 (可选) --> 生成器 --> 机器代码(指令)


可从下图概括上述过程:




其中,Pre-Processor做的是到抽象语法树的步骤,进行语义分析生成语法抽象树和补充方法等;Compiler 编译后得到是汇编语言文件(编译器中可带有优化选项,如gcc -o,可见gcc是带有优化器的,然后生成的中间代码是汇编语言)。之后由生成器(Assembler)生成目标机器代码(二进制的机器码)。Linker则是把当前的机器代码和其它调用的函数编译出来的机器代码链接在一起,以运行。


JavaScript呢,则会直接把每个字节码放进解释器,直接解释执行,而不继续编译成机器代码


字节码 --> 指令流(可选) ---> 解释器  ---> 执行


而Java的做法呢?两者兼顾(以最常见的Hotspots为例):


一开始的时候,直接解释执行,使得程序的启动十分快。同时,进行热点探测。对于多次回探的循环和执行多次的代码,鉴别为热点,并进行编译成机器码版本。在编译完成后,再执行热点代码的时候,便直接执行机器码。其实,这种方法也称之为惰性评估 (lazy evaluation)。




javac编译器完成前半部分,编译出来了字节码,产生了.class文件。剩下的部分由JIT(Hotspot JVM中的)完成。


引用参考文章说法:


在Java中提到“编译”,自然很容易想到Javac编译器将*.java文件编译成为*.class文件的过程,这里的Javac编译器称为前端编译器,其他的前端编译器还有诸如Eclipse JDT中的增量式编译器ECJ等。相对应的还有后端编译器,它在程序运行期间将字节码转变成机器码(现在的Java程序在运行时基本都是解释执行加编译执行),如HotSpot虚拟机自带的JIT(Just In Time Compiler)编译器(分Client端和Server端)。另外,有时候还有可能会碰到静态提前编译器(AOT,Ahead Of Time Compiler)直接把*.java文件编译成本地机器代码,如GCJ、Excelsior JET等,这类编译器我们应该比较少遇到。


需要注意的一点是,Javac的前端编译器会把一个java文件的所有类(不仅仅是public的类)生成class文件。当你想运行某一个不是public类的main函数时,可以直接利用java 类名,去继续解释执行某个class文件。并不是只能运行public类的main函数。












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值