您的位置:首页 > 编程语言 > Java开发

深入理解Java虚拟机----(六)类加载机制

2016-02-12 11:47 369 查看
    上一篇简单描述的类文件结构只是一种被编译器编译后的一个通用描述。在运行时,虚拟机需要将类文件加载到内存,校验、解析、初始化等一些列操作后,生成可使用的Java类。这一系列过程就是虚拟机的类加载机制。
    c++在运行前就有一个链接的过程,而java类型的加载、链接、初始化都是在运行期动态完成的,虽然会慢点,但是提高了灵活性。例如:接口在运行时才知道具体实现;可以运行时从远端下载一段代码运行。

类加载过程:
    加载在卸载的整个过程包括:加载、验证、准备、解析、初始化、使用、卸载。这些步骤除了初始化,其他都保证按这个顺序开始,但是可能上一个没结束下一个就已经开始了。

加载:
通过类的权限定名获得此类的二进制字节流
将二进制流代表的静态结构转换为方法区的运行时结构
内存中生成一个class对象,最为方法区内各种数据的访问入口。

          这个阶段比较自由,可以选择二进制字节流的来源,如果是类对象可以选择类加载器。如果是数组对象,不需要类加载器,直接由虚拟机创建。加载后,类信息就按照虚拟机需求,存在方法区内。然后会生成一个class对象,规范没规定放在哪,由于特殊,HotSport放在了方法区,而不是堆。作为类信息的访问入口。
验证:链接的第一步。为保证class文件字节流的信息可以被识别,并不会威胁到虚拟机的安全。
文件格式:魔数、版本号是否被当前虚拟机版本支持、引用指向的常量是否存在等等。这个阶段是针对字节流的,这个通过了才会进入方法区存储。
元数据验证:字节码的信息进行语义分析。是否有父类、父类是否继承了不该继承的类(fianl等)、抽象父类的方法是否被实现等等。这个阶段针对元数据验证。
字节码验证:最复杂的阶段。确定语义是合法、符合逻辑的。针对方法。
符号引用校验:校验符号引用是否能正常的被解析成直接引用。这个操作在解析阶段完成,这里为其保证可行。

准备:正式为类标量(static)在方法区分配内存并赋0值(验证阶段只赋0值,但如果是final的,直接赋值),实例变量将在对象创建才分配。
解析:将常量池中的符号引用转换为直接引用。
符号引用:描述所引用目标的字面量,虚拟机间通用,因为描述在class文件中。可以定位到目标即可,目标不需已经存在在内存中。
直接引用:可以是指向目标的指针、偏移量或间接的句柄。和虚拟机的内存布局有关,将符号引用翻译过来的直接引用,在各虚拟机中可能不同。翻译成直接饮用后,指向的目标必须已经存在在内存。会针对7中符号引用类型进行。

初始化:准备阶段已经赋初始化值,这个阶段是按照程序员的计划执行一些赋值或资源的初始化。就是执行类构造器<cinit>()的过程。
<cinit>()是编译器收集所有类变量(static)和静态语句块,合并产生的。顺序与定义顺序相同。

不需要调用父类的<cinit>(),虚拟机会保证在调用前,父类的一定执行完成了。所以Object类的<cinit>()一定最先执行。
执行接口的<cinit>()前不会保证父类的<cinit>()已经执行。只有父类中定义的类变量使用时,父接口才会初始化。

类加载器:
    通过类的权限定名获取此类的二进制字节流,这个行为放到了虚拟机外实现,实现这个功能的模块叫类加载器。对于一个类,需要加载它的的加载器和类本身确定唯一性。同一个类文件被不同加载器加载,也不相等(equals、instanceof等)。
    开发者角度看,有三种类加载器:

启动类加载器:c++实现,虚拟机一部分。负责加载java/lib下的类库。用户不能直接使用。
扩展类加载器:负责java/lin/ext中的类库。开发者可以使用。
应用程序类加载器:一般称为系统类加载器。负责用户classpath中的类库,用户可以使用。如果用户没指定,作为默认的加载器。
自定义类加载器:用户自定义

        


    上图是他们之间的关系图,这种模型被称为双亲委派模型。

双亲委派模型:
    当一个加载器接到一个加载请求时,不会处理,而是交给父加载器处理,层层上交,直到根的启动类加载器。父类不能加载时,才会让子类加载。好处是类随着加载器具有了优先级。比如自定义一个java.lang.Object类,加载时会先交到启动加载器,启动加载器会加载java中的Object,自定义的那个永远无法被加载。这就防止了重名导致的高优先级的类无法使用。
    实现很简单,检查加载没加载过,如果没有,就调用父加载器的加载。如果父加载器不能加载,抛出异常,在自己加载。自己不能加载,继续向下抛出异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: