类加载的执行过程

前言一个Java文件从编码完成到最终执行,通常主要包括两个过程java

编译安全

运行网络

编译,即把咱们写好的java文件,经过javac命令编译成字节码,也就是咱们常说的.class文件。编码

运行,则是把编译声称的.class文件交给Java虚拟机(JVM)执行。加密

而咱们所说的类加载过程便是指JVM虚拟机把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程。代理

举个通俗点的例子来讲,JVM在执行某段代码时,遇到了class A, 然而此时内存中并无class A的相关信息,因而JVM就会到相应的class文件中去寻找class A的类信息,并加载进内存中,这就是咱们所说的类加载过程。指针

因而可知,JVM不是一开始就把全部的类都加载进内存中,而是只有第一次遇到某个须要运行的类时才会加载,且只加载一次。对象

类加载
类加载的过程主要分为三个部分:继承

加载内存

连接

初始化

而连接又能够细分为三个小部分:

验证

准备

解析

加载

简单来讲,加载指的是把class字节码文件从各个来源经过类加载器装载入内存中。

这里有两个重点:

字节码来源。通常的加载来源包括从本地路径下编译生成的.class文件,从jar包中的.class文件,从远程网络,以及动态代理实时编译

类加载器。通常包括启动类加载器,扩展类加载器,应用类加载器,以及用户的自定义类加载器。

注:为何会有自定义类加载器?

一方面是因为java代码很容易被反编译,若是须要对本身的代码加密的话,能够对编译后的代码进行加密,而后再经过实现本身的自定义类加载器进行解密,最后再加载。

另外一方面也有可能从非标准的来源加载代码,好比从网络来源,那就须要本身实现一个类加载器,从指定源进行加载。

验证
主要是为了保证加载进来的字节流符合虚拟机规范,不会形成安全错误。

包括对于文件格式的验证,好比常量中是否有不被支持的常量?文件中是否有不规范的或者附加的其余信息?

对于元数据的验证,好比该类是否继承了被final修饰的类?类中的字段,方法是否与父类冲突?是否出现了不合理的重载?

对于字节码的验证,保证程序语义的合理性,好比要保证类型转换的合理性。

对于符号引用的验证,好比校验符号引用中经过全限定名是否可以找到对应的类?校验符号引用中的访问性(private,public等)是否可被当前类访问?

准备
主要是为类变量(注意,不是实例变量)分配内存,而且赋予初值。

特别须要注意,初值,不是代码中具体写的初始化的值,而是Java虚拟机根据不一样变量类型的默认初始值。

好比8种基本类型的初值,默认为0;引用类型的初值则为null;常量的初值即为代码中设置的值,final static tmp = 456, 那么该阶段tmp的初值就是456

解析
将常量池内的符号引用替换为直接引用的过程。

两个重点:

符号引用。即一个字符串,可是这个字符串给出了一些可以惟一性识别一个方法,一个变量,一个类的相关信息。

直接引用。能够理解为一个内存地址,或者一个偏移量。好比类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量

举个例子来讲,如今调用方法hello(),这个方法的地址是1234567,那么hello就是符号引用,1234567就是直接引用。

在解析阶段,虚拟机会把全部的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。

初始化
这个阶段主要是对类变量初始化,是执行类构造器的过程。

换句话说,只对static修饰的变量或语句进行初始化。

若是初始化一个类的时候,其父类还没有初始化,则优先初始化其父类。

若是同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。

相关文章
相关标签/搜索