类加载器与对象的初始化流程

类加载器(ClassLoader):

当编译器编译Java源文件之后,会产生一个相应的字节码文件(.class文件),当程序开始运行之前,必须将这个文件载入内存中,生成一个与之匹配的Class对象。这个过程我们称之为类加载。要弄清楚类加载的机制,首先我们必须要清楚了解类加载器的相关知识,它是完成整个类加载的重要工具。简单的说,当一个class文件载入内存之后,并创建成一个Class对象的过程,就成称之为类加载。


(补充说明:任何一个class文件当加载到jvm之后都会为其创建一个唯一的Class对象(元对象),在后续的实例化过程中,都是通过这个Class对象来创建类的实例。所以Class对象是反射的基石。)

 

在Java中,类加载器可以分为三类:
1. 启动类加载器(BootStrap ClassLoader)
启动类加载器是负责加载JDK核心包下的类文件,对应的目录就是
“JDK安装目录/jre/lib”。其中最重要的一个jar文件就是rt.jar。
注意:这个类加载器我们是没有办法去操作的。因为它本身使用C++语言实现。

 

2. 扩展类加载器(Extension ClassLoader)
这个类加载器,是由启动类加载器来加载的。扩展类加载器是用Java语言实现。
它主要负责加载JDK里面的扩展的jar文件。对应的目录是"JDK安装目录/jre/lib/ext"。

 

3. 应用程序类加载器(Application ClassLoader)
这个类加载器也是使用Java语言实现,它同样由启动类加载器所加载。它主要负责加载
我们开发人员说编写的Java类,通常对应的目录就是环境变量下的ClassPath路径。

 

双亲委托模型:
JVM的类加载时是基于双亲委托模型的。也就是当我们编写任意一个类的时候,本身并不是由应用程序类加载器立即加载,而是先委托给父加载器去加载,当父加载器在自己所加载的范围内找不到相应的class文件时,最后才会将加载权交回给子加载器去加载。这样做的目的是为了保证jvm的安全加载机制。

 

对象的初始化流程

例如:  Test t = new  Test ();  

   先检查该类的父类是否已经被加载,如果没有,执行对父类的类加载操作,父类的类加载操作和子类是一样的,会按照2)和3)的步骤进行加载初始化

   在方法区中检察是否已经加载过Test的Class 的实例,如果没有加载,那么将勿略类加载的流程  执行步骤3

   

1) 先在方法区中检察是否经加载过Test的Class 对象信息,如果已经加载过,那么将忽略类加载的流程,直接使用Class 对象来构建Test的实例。

  如果没有加载,执行步骤2)

 

2)在Classpath 路径下查找名为Test.Class 的字节码文件,通过I/O流将其读入内存,接着执行类加载的各个阶段(加载,验证,准备,解析,初始化)。

     最终在JVM创建该类的一个Class实例保存在堆中。(注意:在准备阶段,会先在方法区中对静态成员的第一次初始化,也就是对静态变量域默认值,

     然后在初始化阶段对静态变量进行第二次赋值,也就是类中字面量声明的值,而第二次赋值是由JVM在动态生成的static代码块中进行赋值操作)

 

3)通过new 关键字创建具体的实例,JVM会在堆中划分空间,保存Test的实例对象,实例变量并跟随着对象保存在堆中。接着初始化实例变量。

   (注意:实例变量也是分两阶段进行初始化的,第一阶段就是在划分空间之后立即赋默认值,第二阶段是在构造方法中赋字面声明的值)

 

4)执行构造方法,早构造方法中对实例变量的在次赋值操作。所以,一个类的构造方法在对象的整个初始化阶段中是最后执行的。

 

初始化原则:

加载父类----》初始化父类的静态成员----》加载子类------》初始化子类的静态成员------》初始化父类的实例变量(默认值)

---》构造方法(在构造方法对实例变量二次赋值)---》子类的实例变量初始化(默认值)

----》子类的构造方法(在构造方法对子类实例变量二次赋值)

 

posted @ 2017-11-29 14:24  曾祥财  阅读(754)  评论(0编辑  收藏  举报