类加载过程

原创 2015年11月20日 16:02:51

Class文件中的各种信息都必须加载到虚拟机中之后才能运行和使用,虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。与那些在编译时需要进行连接工作的语言不通,在Java语言里面,类型的加载、连接、初始化过程都是在程序运行期间完成的,这种策略会是类加载时增加一些性能开销,但会为java程序提供高度的灵活性,Java可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。

类从被加载到内存中开始,到卸载出内存,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载这七个阶段,其中验证、准备和解析这三个部分统称为连接。加载、验证、准备、初始化、卸载这五个阶段的顺序是确定的,类加载过程必须按照这种顺序按部就班的开始。对于解析阶段则不一定,它在某些情况下可以在初始化之后再开始,这是为了支持Java语言的运行时绑定。对于类加载过程的第一个阶段加载可以有虚拟机的具体实现来决定什么时候加载,而对于初始化阶段,虚拟机规划则严格规定了有且只有五种情况必须立刻进行初始化:

(1)遇到new、getstatic 、putstatic、invokestatic这四条字节码指令时,如果类没有进行初始化就需要先触发其初始化。生成这四条指令常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰,已在编译期把结果放入常量池的静态字段除外)以及调用一个类的静态方法时。

(2)使用reflect包的方法对类进行反射调用的时候,如果类没有初始化,则先需触发其初始化。

(3)当初始化一个类的时候,如果发现其父类还没有初始化,则需先触发其父类初始化

(4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main())方法的那个类,虚拟机会先初始化这个类

(5)当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic 、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

--------好了,说了这么多,下面说说类加载的过程------------

类加载过程分为三个阶段,分别为加载、连接、初始化。其中连接又分为三个阶段,分别是验证、准备、解析。

(1)加载是类加载过程的第一个阶段,这个阶段虚拟机需要完成三件事:

a:通过一个类的全限定名来获取定义类的二进制字节流

b:将这个字节流所代表的静态存储结构转发为方法区的运行数据结构

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

(2)验证是类加载过程的第二个阶段,也是连接的第一个阶段,这个阶段的主要作用是确保Class文件的字节流包含的信息服务当前虚拟机的要求,并且不会危害虚拟机自身的安全。

(3)准备阶段是类加载过程的第三个阶段,也是连接的第二个阶段,这个阶段的主要作用是为类变量分配内存并设置类变量的初始值,这些变量所使用的内存都将在方法区分配。这里注意两点:第一是进行内存分配的是类变量(被static修饰)而不是实例变量,实例变量会在对象初始化时随对象一起分配在Java堆中。第二这里所说的初始值指的是数据类型的零值,而不是我们设置的初始值,我们自己设置的初始值在初始化阶段赋值。

(4)解析阶段是类加载过程的第四个阶段,也是连接的第三个阶段。这个阶段的主要作用是将常量池中的符号引用替换为直接引用的过程。符号引用:以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能构无歧义的定位到目标即可。直接引用:可以直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。

(5)初始化阶段是类加载过程的最后一个阶段。其主要作用是将类变量初始化。在前面的类加载过程中,除了在加载阶段用户引用程序可以通过自定义的类加载器参与外,其余动作完全有虚拟机主导实现,到了初始化阶段,才是真正执行类中定义的程序代码。初始化阶段是执行类构造器<clinit>()方法的过程。

a:<clinit>()方法是由编译器自动收集所有的类变量赋值动作和静态语句块中的语句合并而成,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量只可以赋值,不能访问。

b:<clinit>()方法与类的构造方法不同,它不需要显示的调用父类构造器,虚拟机保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法执行完毕。

c:<clinit>()方法对类或接口并不是必须的。如果类中没有类变量赋值操作也没有静态语句块,那么编译器可以不为这个类生成<clinit>()方法

d:接口中没有静态语句块,但是有变量初始化的赋值操作,因此接口也会生成<clinit>()方法。但接口与类不同的是,执行接口的<clinit>()方法方法不需要先执行父接口的<clinit>()方法,只有当父接口中定义的变量使用时,父接口才会初始化,另外,接口的实现类在初始化的时候也不执行接口的<clinit>()方法。

e:虚拟机保证一个类的<clinit>()方法在多线程中被正确的加锁、同步。如果多个线程同时去初始化一个类,那么只会有一个类去执行这个类的<clinit>()方法,其他的线程都阻塞等待。


JAVA中类的加载过程

java中类的加载过程
  • sinat_19650093
  • sinat_19650093
  • 2016年03月20日 21:56
  • 3881

JVM(三):类加载机制(类加载过程和类加载器)

使用java编译器可以把java代码编译为存储字节码的Class文件,使用其他语言的编译器一样可以把程序代码翻译成Class文件,java虚拟机不关心Class的来源是何种语言。如图所示: 在Cla...
  • boyupeng
  • boyupeng
  • 2015年08月25日 15:38
  • 17161

Java类的加载过程

编译:即javac的过程,即把.java文件编译成.class文件,即编译成字节码文件,同时做一些类型以及格式的检查。      类只有在要运行的时候才会被加载进JVM,即编译后只有需要到这...
  • zcxwww
  • zcxwww
  • 2016年05月06日 12:50
  • 3851

Objective - C基础: 第四天 - 7.类的加载过程

在前面, 我们知道了类的本质其实也是一个对象, 是Class类型, 那么类的加载过程是如何的呢?? 其实类的加载过程非常简单, 先加载父类然后再加载子类, 而且每一个类就只会加载一次, 下面让我们来...
  • qq350116542
  • qq350116542
  • 2015年01月24日 14:08
  • 697

Java虚拟机 类加载的过程

转载请标明出处:http://blog.csdn.net/xuefeng0707/article/details/9132339 类加载的全过程分为五个阶段:加载、验证、准备、解析、初始化。 ...
  • xuefeng0707
  • xuefeng0707
  • 2013年06月30日 12:22
  • 4879

java类加载过程

转载请注明出处:http://blog.csdn.net/ns_code/article/details/17881581 类加载过程     类从被加载到虚拟机内存中开始,到...
  • haluoluo211
  • haluoluo211
  • 2015年11月18日 16:00
  • 1782

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

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。 其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这...
  • mmc_maodun
  • mmc_maodun
  • 2014年01月08日 00:09
  • 40801

Java中类加载过程和对象创建过程

类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在。如果有,就直接使用;如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加...
  • u014338577
  • u014338577
  • 2015年11月21日 21:47
  • 5048

类加载和对象的初始化过程

类的初始化和对象初始化是两个不同的概念。类的初始化是发生在类加载过程,是类加载过程的一个阶段,该阶段并不调用类的构造器。而对象的初始化是在类加载完成后为对象分配内存,实例变量的初始化,实例变量的赋值及...
  • zjl477595675
  • zjl477595675
  • 2015年08月30日 08:34
  • 6301

JAVA 类加载过程详细讲解 -jvm加载类机制CLass Loading

jvm加载类机制CLass Loading
  • tangdong3415
  • tangdong3415
  • 2016年12月20日 20:02
  • 4049
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:类加载过程
举报原因:
原因补充:

(最多只允许输入30个字)