jvm类加载机制学习基础

一. 类加载机制概述

(1)概述
 java语言的特性中有一条这样说:Java与C/C++相比更加具有动态性,它能够适应不断发展的环境,库中可以自由地添加新方法和实例变量,而对客户端没有任何影响。再有,当需要将某些代码添加到正在运行的程序中时,动态性将会是一个非常重要的特性。比如:从Internet上下载代码,然后在浏览器上运行。这样的实现技术都是需要凭借Java系统中的类加载机制。
 类加载是指将Class的二进制字节流加载到虚拟机内存中的过程。
 (2)类加载器:
 凭借一个类的全限定名来获取一个类的二进制字节流,完成这样的工作的代码模块称之为类加载器
 (3)类缓存:
 标准的JavaSE类加载器可以按要求查找类,并且某个类加载到内存中后将维持一段时间,JVM垃圾收集器可以回收这些Class对象。
 (4)加载类的常见途径:
  a. 从本地系统直接加载
  b. 通过网络下载.class文件
  c. 从zip,jar等归档文件中加载.class文件
  d. 从数据库中提取.class文件


二.什么情况下会触发类的加载?

有且仅有五种对类的主动引用会出发类的加载

1.运行4种字节码指令时

  • (1)new: 使用new实例化对对象;
  • (2)getstatic: 读取一个类的静态字段(不包括被final修饰、编译器已经放入常量池的静态字段不算);
  • (3)putstatic: 对一个静态字段进行写入值;
  • (3)invokestatic: 调用一个类的静态方法时。

2.使用java.lang.reflect包中的方法对类进行反射调用时

3.初始化一个类时,其父类还未被初始化

4.虚拟机启动时先初始化好包含main()方法的main class

5.jdk1.7,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,这个方法对应的类还未初始化则会进行初始化。


三.类加载会经历哪些阶段?

将class文件中的二进制数据读入到内存中,并将静态数据转换成方法区中的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.class对象,用来封装在方法区类的对象。类加载子系统示意图如下:

 
Class文件加载子系统结构图

四. 类加载时类成员的加载顺序

java中的类由静态成员和非静态成员组成,在一个类进行加载-初始化的时候顺序是怎么样的呢?
(静态变量、静态初始化块)–>(变量、初始化块)–> 构造器;
如果有父类,则顺序是:父类static方法 –> 子类static方法 –> 父类构造方法- -> 子类构造方法


五. 类加载器的双亲委派模型

1.Java的类加载器结构

类加载器双亲委派模型(Parents Delegation Model)

注:类加载器的树形继承结构是通过组合的方式实现,而非简单的直接继承实现。

(1)Bootstrap ClassLoader(启动类加载器):负责将存放在JAVA_HOME\jre\lib\rt.jar下的类库加载到虚拟机内存中。启动类加载器是由c,c++实现的,不能被Java代码直接引用。查看路径:System.getProperty(“sun.boot.class.path”)

(2)Extension ClassLoader(扩展类加载器):由sun.misc.Launcher$ExtClassLoader实现,负责加载JAVA_HOME\bin\ext*.jar目录下,或者被java.ext.dirs系统变量指定的路径中的所有类库。可以直接使用扩展类加载器。
查看路径:System.getProperty("java.ext.dirs")

(3)Application ClassLoader(系统类加载SystemClassLoader/AppClassLoader,应用程序类加载器):由sun.misc.Launcher$AppClassLoader实现。负责加载用户类路径(classpath)上所指定的类库。是应用程序中默认的类加载。查看路径:System.getProperty("java.class.path")

获得各层级ClassLoader实例的代码:

ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();//AppClassLoader
ClassLoader extClassLoader = appClassLoader.getParent();//ExtClassLoader
ClassLoader systemClassLoader = extClassLoader.getParent();//SystemClassLoader
//验证:打印引用如下
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@14ae5a5
null

2.Android的类加载器结构

Android系统中的类加载器结构.

Anddroid系统的类加载器结构

PathClassLoader : 从本地文件系统加载系统类和应用层类,不能从网络加载class字节码
DexClassLoader : 从包含classes.dex文件的.jar或.apk文件中加载class字节码

3.双亲委派模型的工作过程

如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把请求委派给父类加载器去完成,每一个层次的类加载器都是这样工作,因此所有的类加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈无法完成类加载请求时,子类加载器才会尝试自己去加载。
ClassLoader进行类加载的方法在代码中的实现:

// loadClass:先检查是否已经被加载过,若没有则调用父类加载器的loadClass()方法,
// 若父加载器为空则默认使用启动类加载器作为父加载器。如果父加载器加载失败,则抛出
// ClasNotFoundExceptionyichang,再调用自己的findClass()方法加载
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 先检查要加载的类是否已经被加载,这里说明同一个类只会被加载一次
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {//先判断父类加载器是否为空,不为空则用父类加载器加载
                        c = parent.loadClass(name, false);
                    } else {//如果父类加载器也为空则用启动类加载器加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    //当父类加载器无法加载时,调用自定义的ClassLoader本身的findClass
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

注:同一个类加载器在加载同一个类时不会重复加载,认为是同一个类;不同的类加载器加载同一个类不会认为是同一个类,会重复加载。
可以从代码中看出,只要父类加载能够完成类的加载任务,类加载的工作就会是由父类加载器完成。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • JVM类加载机制 概述 类加载过程 加载 通过类的全限定名获取类的二进制流 将静态存储结构转化为方法区的运行时数据...
    东溪95阅读 2,961评论 0 15
  • 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,确实编译语言发展的一大步。 虚拟机把描述类的数据从...
    胡二囧阅读 893评论 0 0
  • 1、什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内...
    Java_Explorer阅读 301评论 0 2
  • 编译原理请查看之前内容,.java文件编译过程和执行过程分析以及计算机简单认识 需要了解更多Java原创资料,请加...
    坑王老薛阅读 2,136评论 0 5
  • 很期待上映的“变形金刚5——最后的骑士”,看电影前,还把已经遗忘的”变形金刚4“从看了一遍,看得惊心动魄,特别...
    不爱叫的猫阅读 422评论 0 0