虚拟机类加载机制

来源:互联网 发布:淘宝要怎么重新注册 编辑:程序博客网 时间:2024/05/17 04:25

1、在java语言里面,类型的加载和连接过程都是在程序运行期间完成的,这样会在类加载时增加一些性能开销,但是却可以为java应用程序提供高度的灵活性,java种天生可以动态扩展的语言特性就是依赖运行期动态加载和动态链接这个特点实现的。
动态加载:运行时动态加载所需要的资源(API或者第三方的java类库)
动态链接:就是要把程序运行时所需要的资源API以及资源文件,都重新进行组织生成可以单独运行的程序
2.类加载的时机
类从被加载到jvm内存中到卸载出内存,整个生命周期如下图所示,验证准备和解析阶段统称为连接。解析阶段可以在初始化阶段之后再开始,这种情况是为了支持java的动态绑定。什么是动态绑定?

这里写图片描述

3.类什么时候需要初始化?
有且只有以下四种情形会触发类的初始化,除此之外所有引用类的方式都不会触发类的初始化,称为被动引用。
1.使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已经在编译期间把结果放入常量池的结果除外)的时候,以及调用一个类的静态方法的时候
2.使用反射方法对类进行反射调用的时候,如果该类没有进行过初始化,则需要出发其父类的初始化。
3.初始化一个类的时候,如果该类的父类还没有初始化,则需要先触发其父类的初始化
4.虚拟机启动时,先触发主类(包含main方法的)的初始化。

public class SSClass{    static    {        System.out.println("SSClass");    }}    public class SuperClass extends SSClass{    static    {        System.out.println("SuperClass init!");    }    public static int value = 123;    public SuperClass()    {        System.out.println("init SuperClass");    }}public class SubClass extends SuperClass{    static     {        System.out.println("SubClass init");    }    static int a;    public SubClass()    {        System.out.println("init SubClass");    }}public class NotInitialization{    public static void main(String[] args)    {        System.out.println(SubClass.value);//static修饰的方法是类方法不需对象就可以通过类名直接访问    }}//运行结果//SSClass//SuperClass init!//123//对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。

4.虚拟机类加载的过程
(1)加载
1.通过一个类的全限定名来获取此类的二进制字节流
二进制字节流需要在哪里获取呢?
压缩包中:JAR/WAR/EAR
网络中:Applet
运行时计算生成:动态代理
其他文件生成:jsp应用
2.将这个字节流代表的静态存储结构(编译时分配的固定的存储空间)转化为方法区的运行时数据结构
3.在java堆中实例化一个代表这个类的Class对象,作为方法区这些数据的访问入口
(2)验证
验证的目的是为了确保Class字节流文件中的内容包含的信息符合当前虚拟机的要求,不会危害虚拟机的自身安全
(3)准备
准备阶段,为类变量(被static修饰的变量)分配内存并设置初始值(数据类型的0值)
(4)解析
虚拟机将常量池中的符号引用(任何字面量,可以定位到目标即可、引用的目标不一定加载到了内存)替换为直接引用(直接指向目标的指针,引用目标必定在内存中存在)
(5)初始化
初始化才开始真正的执行字节码,准备阶段变量赋值过一次初始值。初始化阶段,则是根据程序员的要求进行初始化变量或者其他资源。
以上程序完成后就可以对一个类进行使用了

参考书籍:深入理解jvm