技术干货程序员Java学习笔记

JAVA类加载机制

2017-07-09  本文已影响21人  Wen_Q_M

概述

虚拟机把描述类的数据从Class文件加载到内存中,并对数据进行验证,准备,解析,初始化的一个过程,最终是可以被虚拟机直接使用的java类型,这就是类加载的一个简单的过程。
Java中的类加载是在运行时加载,这样会比较的消耗性能,但是正是在运行时加载使得java拥有很好的灵活性和可扩展性。

类加载的时机

类从被加载到内存中开始,到卸载出内存为止。它的生命周期总共七个阶段:加载---->验证---->准备---->解析---->初始化---->使用---->卸载。其中解析这个过程是不确定的,它可能会在初始化后之后,这是为了使java支持运行时的绑定。

加载

加载是类加载中前面提到的其中的一个过程。类加载的基本过程:

加载分为数组类加载过程和非数组类的加载过程。java的数组类的加载过程其实是有虚拟机直接加载的但是数组中的类型需要类加载机制加载:

ps:数组类的可见性与它组件的可见性是相同的,如果组件类型不是引用类型的可见性一般设置为public。
类加载完成会有一个连接,可能在没完成加载就开始连接,虽然如此但是该顺序是一定的。

验证

验证的主要目的是保证加载进来的Class文件的字节流包含的信息符合虚拟机的当前的要求,不会有危害自身的数据存在。
Java是相对C++语言是安全的语言,例如它有C++不具有的数组越界的检查。这本身就是对自身安全的一一种保护。验证阶段是Java非常重要的一个阶段,它会直接的保证应用是否会被恶意入侵的一道重要的防线,越是严谨的验证机制越安全。验证的四个阶段文件格式验证-->元数据验证-->字节码验证-->符号引用验证。

虽然验证很重要但是并不是必须的阶段。当然大量重复的验证会相当的花费性能和时间的。
准备


准备阶段主要是类变量进行分配内存和数据的初始化阶段,所谓的初始化并不是你编码时所定义的变量值。例如:

public static int age = 20;

数据的初始化并不会将它初始化为20,而是初始化为0,系统有一套自己的初始化值。如下图:

数据类型 零值
int 0
long 0L
short 0
char '\u0000'
byte 0
boolean false
float 0.0f
double 0.0d
reference null

当然会有特殊的情况,如下面的代码:

public static final int value = 20;

这种情况是类的字段时存在ConstantValue属性所指定的字段。用final修饰后出现该属性,加初始化时会直接的使用ConstantValue的属性值,所以会初始化为20。
解析


解析是将常量池中的符号引用转化为直接引用的过程,还记得前面验证阶段时出现的符号引用验证吗?就是对该阶段的验证。

虚拟机可能会多次的进行解析。解析主要的对类,接口,字段,类方法,接口方法,方法类型,方法句柄和调用点限定符引用进行。这七种解析有细节上的不同,主要的思想是通过限定性类名找到解析的类型进行解析。主要的是会分为数组类型,非数组类型存在一个直接进行解析的过程。在过程还有从下上的匹配查找(主要出现在有继承,接口的情况下)。

初始化

初始化算是类加载过程的最后一个阶段,在这个阶段在是真正的开始有java代码主导。大家应该记得在准备阶段已经进行过一次赋值,但是只是系统的默认赋值(ConstantValue的例外情况)。初始化是执行<clinit>的过程。

public class A{
  static{
          s = 20;
          //system.out.printf(s); 
          上面注释的这句话时会出现错误的;
  }
  static int s = 10;
}  

类加载器

public Class<?> loadClass(String name)throws ClassNotFoundException {
            return loadClass(name, false);
    }
 
    protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {
            // 首先判断该类型是否已经被加载
            Class c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    //如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)
                        c = findBootstrapClass0(name);
                    }
                } catch (ClassNotFoundException e) {
                 // 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
上一篇下一篇

猜你喜欢

热点阅读