首页 > IT职业 > IT职场 > Java 源代码编译成 Class 文件的过程分析
原文链接:http://www.codeceo.com/article/compile-java-source-code-into-a-class-file.html
在上篇文章《Java三种编译方式:前端编译 JIT编译 AOT编译》中了解到了它们各有什么优点和缺点,以及前端编译+JIT编译方式的运作过程。
下面我们详细了解Java前端编译:Java源代码编译成Class文件的过程;我们从官方JDK提供的前端编译器javac入手,用javac编译一些测试程序,调试跟踪javac源码,看看javac整个编译过程是如何实现的。
调试编译文件,需要右键工程 -> Debug As -> Debug Configurations ->切换到Arguments选项卡,在Program arguments中输入我们要用javac编译的Java程序文件的路径即可;然后就可以打断点Debug运行调试了,如图:

Java最常用的有:
泛型、变长参数、自动装箱/拆箱、遍历循环、内部类、断言等;
JVM不支持这些语法;
在编译阶段还原回简单的基础语法结构,称为解语法糖;
2、源码分析
入口调用com.sun.tools.javac.main.JavaCompiler.desugar()完成;
主要由com.sun.tools.javac.comp.TransTypes类和com.sun.tools.javac.comp.Lower类实现;
3、泛型与类型擦除
拿泛型来说,泛型是JDK1.5的新增特性;
本质是参数化类型(Parametersized Type)的应用;
即所操作的数据类型被指定为一个参数;
可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法;
(A)、Java泛型与C#泛型
C#的泛型在程序、编译后、运行期都是存在的;
对于List
这种实现方法称为类型膨胀,基于这种方法实现的泛型称为真实泛型;
Java语言泛型在编译后的字节码文件中,就被替换为原来的原生类型(Raw Type);
并在相应地方插入强制转型代码;
对于ArrayList
这种实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型;
(B)、运行时识别(反射)泛型参数类型
对于泛型类型擦除后,需要在运行时识别(反射)泛型参数类型的问题:
JVM规范引入了Signature、LocalVariableTypeTable等Class属性;
Signature存储一个方法在字节码层面的特征签名,保存了参数化类型的信息;
这也是能通过反射手段取得参数化类型的根本依据;
相关Class属性会在后面文章介绍Class文件格式时再说明;
(C)、编译测试
测试程序JvmTest10_2.java,如下:
package com.jvmtest;
import java.util.HashMap;
import java.util.Map;
public class JvmTest10_2 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("hello", "java");
System.out.println(map.get("hello"));
}
}
泛型擦除调用关系及关键代码,如下:

测试程序中泛型经过编译类型被擦除,如下:

6、实时Java,第2部分: 比较编译技术–本地 Java 代码的静态编译和动态编译中的问题:www.ibm.com/developerworks/cn/java/j-rtj2/
7、很多文章都提到JVM对class文件的编译,那么编译后的文件是在内存里还是在哪?怎么查看?:https://www.zhihu.com/question/52487484/answer/130785455
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4484/viewspace-2802032/ ,如需转载,请注明出处,否则将追究法律责任。