Java虚拟机类加载机制

来源:互联网 发布:数据采集仪销售电话 编辑:程序博客网 时间:2024/06/06 10:42

一句话描述:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

类加载全过程:加载-验证-准备-解析-初始化

1、加载

    在加载过程中主要完成三件事:1、通过一个类的全限定名来获取定义此类的二进制字节流(由类加载器完成,可以自己定义类加载器加载非数组类,数组类由虚拟机直接创建)2、将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据结构的访问入口。

2、验证

   为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

   有四种验证:1、文件格式验证2、元数据验证3、字节码验证4、符号引用验证

3、准备

    在方法区中正式为类变量分配内存并设置类变量初始值的阶段。

4、解析

    虚拟机将常量池内的符号引用替换为直接引用的过程。

5、初始化

    初始化阶段是执行类构造器<clinit>()方法的过程。<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的,执行子类的<clinit>()方法之前会先执行父类的<clinit>()方法。

   虚拟机规定有五种情况为主动引用,虚拟机会立即对类进行初始化:1、遇到new、getstatic、putstatic、invokestatic这四个字节码指令 2、使用java.lang.reflect包的方法对类进行反射调用的时候3、初始化一个类,如果发现它的父类还没初始化,则需要出发分类的初始化4、当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类5、jdk1.7,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先初始化。  

   被动引用不会触发初始化,如:1、通过子类引用父类的静态字段,不会导致子类初始化2、通过数组定义来引用类,不会触发此类的初始化3、常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类(常量会存储到NotInitialization类的常量池中,引用的是NotInitialization类)。

类加载器:

对于任意一个类,都需要由加载它的类加载器和这个类本身一同确定其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。(即两个类相等,不仅仅是包名类名相同,还需要加载它的类加载器相同)

类加载器分类:

1、Bootstrap ClassLoader(启动类加载器):用c++实现,是虚拟机的一部分。负责加载<JAVA_HOME>\lib目录或被-Xbootclasspath参数所指定的路径中的类库。

2、Extension ClassLoader(扩展类加载器):负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。

3、Application ClassLoader(应用程序类加载器):是ClassLoader中的getSystemClassLoader的返回值。负责加载用户类路径(ClassPath)上所制定的类库,一般情况下这个就是程序中的默认的类加载器。

双亲委派模型:要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,这里的类加载器之间的父子关系一般不会以继承的关系来实现,而是通过组合的关系来复用父加载器的代码。(启动类加载器-扩展类加载器-应用程序加载器-自定义类加载器)

双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

双亲委派模型的好处:Java类随着它的类加载器一起具备了一种带有优先级的层次关系。如java.lang.Object类不管在哪都是最后由启动类加载器加载,保证了在各种类加载环境中Object类都是同一个类。

0 0
原创粉丝点击