深入理解Java虚拟机---类加载机制(简略版)

类加载机制

  谈起类加载机制,在这里说个题外话,当初本人在学了两三个月的Java后,只了解了一些皮毛知识,就屁颠屁颠得去附近学校的招聘会去蹭蹭面试经验,和HR聊了一会后开始了技术面试,前抛出了两个简单的小问题铺垫了一下,然后接下来的问题就是简单的说一下类加载机制,听到这个问题,我脑子里面想到这个问题我看过,在《深入理解Java虚拟机》这本书上看到过这个原理,但是只是很浅显的翻看了一下,并没有下功夫去了解其中的原理。然后就大脑一片空白,什么也想不到了,支支吾吾没有回答上来,这就gg了,当时羞愧得想着赶紧逃走。果然基础不牢,地动山摇啊,对于我这种半路出家的,还是要打好基础。

  每次看到类加载机制的问题,心里就会想起那次面试,都快成了阴影了,虽然现在能回答上来一些,在这里还是通过书来系统的理解一下。

  本博客内容大部分参考自《深入理解Java虚拟机》第二版 周志明 著

 

类加载过程

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

  类从被加载到虚拟机内存中开始,到卸载出内存,整个生命周期包括:加载(Loading),验证(Verification),准备(Preparation),解析(Resolution),初始化(Initialization),使用(Using),卸载(Unloading。其中验证、准备、解析这3个部分统称为连接。这7个阶段的发生顺序如图所示

加载

         加载时类加载的第一个阶段。在加载阶段,虚拟机完成的事情是:

         1、通过一个类的全限定名来获取定义此类的二进制字节流,获取.class文件的二进制流

    2、将类信息、静态变量、字节码、常量这些.class文件中的内容放入方法区中。

         3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

         加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,方法区中的数据存储格式由虚拟机实现自行定义,虚拟机规范未规定此区域的具体数据结构。然后再内存中实例化一个java.lang.Class类的对象(并没有明确规定是在Java堆中,对于HostSpot虚拟机而言,Class对象比较特殊,它虽然是对象,但是存放在方法区里面),这个对象将作为程序访问方法区中的这些类型数据的外部接口。

         加载阶段与连接阶段的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。

 

验证

  验证是连接阶段的第一步。这个阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

  Java语言是相对安全的语言,使用纯粹的Java代码无法做到诸如访问数组边界以外的数据、将一个对象转型为它并未实现的类型、跳转到不存在的代码之类的事情,如果这样做了,编译器将拒绝编译。但是Class文件并不一定要求用Java源码编译而来,可以使用任何途径产生,甚至包括十六进制编译器直接编写来产生Class文件。在字节码语言层面上,上述Java代码无法做到的事情都是可以实现的,至少语义上是可以表达出来的。虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有害的字节流而导致系统崩溃,所以验证是虚拟机对自身保护的一项重要工作。

  验证阶段大致上会玩完成下面4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符合引用验证。

 

准备

  准备阶段是正式为类变量分配内存并设置其初始值的阶段,这些变量所使用的内存都将在方法区中分配。

  1、这时候进行内存分配的仅包括类变量,而不包括实例变量,实例变量将在对象实例化时随着对象一起分配在Java堆中。

  2、这里说的初始值通常情况下是数据类型的零值。比如"public static int value = 123;",value在准备阶段过后是0而不是123,给value赋值为123的动作将在初始化阶段才进行;比如"public static final int value = 123;"就不一样了,在准备阶段,虚拟机就会给value赋值为123。

 

解析

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

 

初始化

  初始化是类加载过程的最后一步,初始化阶段是真正执行类中定义的Java程序代码的过程。

  在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源。初始化阶段就是给static变量赋予用户指定的值以及执行静态代码块。

 

  博主初入Java,对加载机制更深层的东西理解尚浅,想更深入的学习类初始化的知识可以阅读下面大神的博客

 

推荐博客

[1] 【深入Java虚拟机】之四:类加载机制

http://blog.csdn.net/ns_code/article/details/17881581

[2] JAVA类加载机制详解

http://www.cnblogs.com/dongguacai/p/5860241.html

[3] Java虚拟机类加载机制

http://www.importnew.com/18548.html

 

 

posted @ 2018-02-03 16:33  Mipha  阅读(148)  评论(0编辑  收藏  举报