字节码文件的跨平台性
- Java语言:跨平台的语言(write once ,run anywhere)I
- 当Java源代码 成功编译成字节码后,如果想在不同的平台上面运行,则无须再次编译
- 这个优势不再那么吸引人了。Python、 PHP、Perl、Ruby、Lisp等有强大的解释器。
- 跨平台似乎已经快成为一门语言必选的特性。
-
Java虚拟机:跨语言的平台
Java虚拟机不和包括Java在内的任何语言绑定,它只与“Class文件”这种特定的二进制文件格式所关联。无论使用何种语言进行软件开发,只要能将源文件编译为正确的Class文件,那么这种语言就可以在Java虚拟机上执行。可以说,统一而强大的Class文件结构,就是Java虚拟机的基石、 桥梁。 -
想要让一个Java程序正确地运行在JVM中, Java源码就必须要被编译为符合JVM规范的字节码。
-
前端编译器的主要任务就是负责将符合Java语法规范的Java代码转换为符合JVM规范的字节码文件。
-
javac是种能够将Java源码编译为字节码的前端编译器。
-
Javac编译器在将Java源码编译为一个有效的字节码文件过程中经历了4个步骤,分别是词法解析、语法解析、语义解析以及生成字节码。
Oracle的JDK软件包括两部分内容:
- 一部分是将Java源代码编译成Java虛拟机的指令集的编译器
- 另一部分是用于实现Java虚拟机的运行时环境。
Java的前端编译器
前端编译器 VS 后端编译器
Java源代码的编译结果是字书码,那么肯定需要有种编译器能够将Java源码编译为字节码,承担这个重要责任的就是配置在path环境变量中的javac编译器。javac是一种能够将Java源码编译为字节码的前端编译器。
HotSpotVM并没有强制要求前端编译器只能使用javac来编译字节码,其实只要编译结果符合JVM规范都可以被JVM所识别即可。
在Java的前端编译器领域,除了javac之外,还有一种被大家经常用到的前端编译器,那就是内置在Eclipse中的**ECI (Eclipse Compiler for Java)**编译器。和Javac的全量式编译不同,ECI是一 种增量式编译器。
- 在Eclipse中,当开发人员编写完代码后,使用“Ctrl+S”快捷键时,ECJ编 译器所采取的编译方案是把未编译部分的源码逐行进行编译,而非每次都全量编译。因此ECJ的编译效率会比javac更加迅速和高效,当然编译质量和javac相比大致还是一样的。
- ECJ不仅是Eclipse的默认内置前端编译器,在Tomcat中 同样也是使用ECJ编译器来编译jsp文件。由于ECJ编译器是采用GPLv2的开源协议进行源代码公开,所以,大家可以登录eclipse官网下载ECI编译器的源码进行二次开发。
- 默认情况下,IntelliJ IDEA 使用javac 编译器。(还可以自己设置为AspectJ编译器 ajc)
前端编译器并不会直接涉及编译优化等方面的技术,而是将这些具体优化细节移交给HotSpot的JIT编译器负责。
AOT(静态提前编译器,Ahead Of Time Compiler)【直接将java文件变异成机器指令,但是仅支持linux64位操作系统,并缺失了java的多平台性】
透过字节码指令看代码细节
- BAT面试题
- 类文件结构有几个部分?
- 知道字节码吗?字节码都有哪些? Integer x = 5;int y = 5;比较x == y都经过哪些步骤?
案例一
案例二
案例三
成员变量的赋值过程:1. 默认初始化;2. 显示初始化 / 代码块中初始化;3. 构造其中初始化
-
先把main方法的new Son()改为 new Father()
- 再把main方法的new Father()改回 new Son()
总结(案例三):
- new Son()
- 先执行Father的构造器Father()
- 调用this.print(),但是此时因为实例化的Son对象已经重写了print(),所以调用的是Son类的print方法,此时Son中的x仅经过了默认初始化,所以为0
- 调用x=20;将father的x赋值为20;
- father构造器完毕后,调用son的构造器,调用print方法,此时son中的x为30(经过了显示初始化)
- 调用x=40,将son的x赋值为40
- main方法调用f.x,调用的是father中的属性x,为20
注意:变量没有重写之说,如果子类声明了跟父类一样的变量,那意谓着子类中将有两个相同名称的变量