java是半编译半解释的语言,.java首先编译为.class。通过一些二进制阅读软件,你可以去了解.class文件的内部构成。《深入理解java虚拟机》一书有专门章节讲这个,我觉得比较麻烦,不多说。
虚拟机类加载机制(java是半编译半解释的语言,.java文件首先编译为.class文件,由于编译是面向jvm的,所以这与C++的编译思路有些不同。只要编译为jvm能理解的就可以了,而非像C++那样编译为计算机可以执行的机器码。java的jvm才负责与真正的计算机交流,java程序则只需jvm能解读就可以了。所以这种半编译半解释的特性提供了很多C++所无法企及的灵活性。):
上图是java的加载机制。我们首先需要了解的是java类初始化(图中的Initialization)的时机:
1,new
2,反射
3,初始化一个类时,若父类还未被初始化,先初始化其父类
而类的加载时机,则是最迟不晚于类的初始化时机。
类加载要做的事首先是通过类名(包括包),找到此类的.class二进制字节流。将该类信息加载到方法区(大抵仍是很原始的.class内容)。然后再内存中实例化一个java.lang.Class类对象(每一个类的信息在java中也是对象,这是很有哲学意味的一个概念)。这个java.lang.Class对象却并不是java堆中(虽然是对象),是存在方法区里。这个对象是程序访问方法区中类的对外接口。
在图中的的准备(Preparation)阶段,是对加载阶段的延续--同样是在方法区做事:初始化static变量。只分配内存空间,此时都是0值。
例如一个类中写到public static int value = 123; 则在准备阶段,publi static int value = 0;在初始化阶段才public static int value = 123;
但若为public static final int value = 123;则在准备阶段 便public static final int value = 123;
解析阶段是将常量池(《深入理解虚拟机》第六章介绍)内的符号引用(.class文件内的数据结构)转化为直接引用(真正对应虚拟机内存布局)
可以看出在初始化过程前,都是对类信息的加载、连接,也都是在方法区进行的。而从初始化阶段开始,真正涉及java执行引擎。
大致为下面这样的代码的话:
public class C { public static int a; public method1(){……} }