勿在流沙筑高台,出来混迟早要还的。

做一个积极的人

编码、改bug、提升自己

我有一个乐园,面向编程,春暖花开!

上一篇介绍虚拟机类加载机制,讲解了类加载机制中的三个阶段,分别是:加载、连接(验证、准备、解析)、初始化 ,知道了类加载的机制。下面我们就要知道类到底是通过什么方式加载到内存中的,也就是本文要介绍的类加载器,类加载器就是加载类的信息到内存中

本文地图 :

一、什么是类加载器(ClassLoader)

虚拟机设计团队把类加载阶段中的”通过一个类的全限定名来获取描述此类的二进制字节流“这个动作是放到Java虚拟机外部去实现的,以便让应用程序自己决定如何去获取所需的类,实现这个动作的代码模块称为”类加载器“。

说简单一点:类加载器可以把类加载到Java虚拟机中,我们可以使用Java虚拟机自带的类加载器,也可以自定义实现自己的类加载器(自定义类加载器会在后面文章进行讲解)。

类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用远不限于类加载阶段。对于任意的一个类,都需要由加载它的类加载器和这个类本身一同确立起在Java虚拟机中的唯一性。每个类加载器都拥有一个独立的类命名空间(命名空间下面单独会介绍)。

说简单一点:比较两个类是否”相等“,只有在这两个类是由同一个类加载器加载的前提在才有意义,否则,即使这两个类源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类必定不相等。这里所指的“相等”包括代表类的Class对象的equal方法、isAssignableFrom()、isInstance()方法及instance关键字返回的结果。

如上图,此时虽然是同一个Person.class ,但是被不同的类加载器加载到Java虚拟机,那么加载后的这两个 Person类是不”相等“,因为它们分别在两个不同的命名空间中。

注:如果上面两个类的是否”相等“比较你没看懂的话,后面自定义类加载器的时候我们会演示一下这个例子,进行简单说明。

二、类加载器分类

一张图看懂类加载器分类:

上图的类加载器主要分为四类:

  • Bootstrap ClassLoader : 启动类加载器
  • Extension ClassLoader : 扩展类加载器
  • Application ClassLoader :应用程序类加载器
  • User ClassLoader :自定义类加载器

从虚拟机角度分析,类加载器分为两类: 一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另一种是其他类加载器,这些类加载器是Java语言实现的,独立于虚拟机之外,都继承自抽象类java.lang.ClassLoader。

public class ClassLoaderDemo {

    public static void main(String[] args) {

        // ClassLoaderDemo 的类加载器
System.out.println(ClassLoaderDemo.class.getClassLoader()); // 打印每个 ClassLoader的父加载器
ClassLoader classLoader = ClassLoaderDemo.class.getClassLoader();
while (classLoader != null){
System.out.println(classLoader);
classLoader = classLoader.getParent();
}
System.out.println(classLoader);
}
}
--- 打印结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1540e19d
null

启动类加载器(根加载器)

主要负责加载存放在JAVA_HOME/jre/lib/rt.jar里面所有的class文件,或者被-Xbootclasspath参数所指定路径中以rt.jar命名的文件。启动类加载器无法被Java程序直接引用,如果在编写自定义类加载时,需要把加载的请求委派给启动类加载器,那么直接使用null代替即可。

例如:

MyClassLoader myClassLoader= new MyClassLoader(null); //父加载器使用启动类加载器
public MyClassLoader(ClassLoader parent){
super(parent);//指定该类加载器的父类加载器
}

扩展类加载器

这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载AVA_HOME/lib/ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。

应用程序类加载器

这个加载器由sun.misc.Launcher$AppClassLoader实现,它负责加载classpath对应的jar及目录。如果应用程序没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

自定义类加载器

用户定制自己的类加载器,继承ClassLoader,根据自己的需要进行设计和实现,比如需要从指定的路径下读取class文件进行加载等。

知道上面这些内容,你就应该联想到为什么在学习Java的时候首先要配置Java环境变量了。这就是知其所以然的过程。

思考:这么多类加载器,那么如何保证一个类不被重复加载,只被加载一次呢?

从JDK1.2版本开始,类加载过程中采用了双亲委派模型(父亲委派机制),这种机制能更好的保证Java平台的安全,在此委托机制中,除了Java虚拟机自带的根类加载(根加载器最顶级,无父加载器)以外,其余的类加载器都有且只有一个父加载器。双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有父类加载器反馈自己无法完成这个加载请求(它搜索的范围中没有找打所需的类)时,子加载器才会尝试自己去加载。

如下示意图:

在说明一下: 加载一个类的时候。首先自定义类加载类器先会委派给应用程序类加载器(Application ClassLoader),应用程序类加载器会委派给扩展类加载器(Extension ClassLoader),扩展类加载器会委派给启动类加载器(Bootstrap ClassLoader)去加载,这时候如果启动类加载器加载成功,则加载结束。如果加载失败,则交给扩展类加载器去加载,如果扩展类加载器加载成功,则加载结束。如果加载失败,则交给应用程序类加载器,如果应用程序类加载器加载成功,则加载结束。如果加载失败,则交给自定义类加载器。如果自定义类加载器加载成功,则加载结束。否则加载失败,会报ClassNotFoundExecption异常,结束。

每个类加载器都有自己的管辖范围(命名空间),并在自己的管辖范围做好自己的事情。

双亲委派模型还有一个优点是能提供软件系统的安全性,在这个机制下,用户自定义的类加载器不可能加载应该由父类加载器加载的可靠类,从而防止不可靠甚至是恶意的代码代替父类加载器加载可靠代码。如 java.land.Object 类总是由启动类加载器进行加载,其他任何用户自定义的类加载器都不可能加载含有恶意代码的java.land.Object 类。(每一个看似简单的设计背后,都是大师们智慧的结晶)


tips: 类加载器命名空间

每个类加载器都有自己的命名空间,命名空间由该加载器及所有父类加载器所加载的类组成。在同一个命名空间中,不会出现两个全类名(包名+类名)完全一样的类;在不同的命名空间中,有可能出现全类名相同的两个类。

一定要注意是:有可能出现全类名一样的,就如 Loader1 中自定义类加载器可以加载如 com.aflyun.HelloJVM.java , Loader2 中自定义类加载器也可以加载如 com.aflyun.HelloJVM.java 的类,两个互不影响,并且比较两个类的话,是不”相等“的。并且不同命名空间中类加载器加载的类,不能访问其他类加载器包中的包可见(即默认访问级别)成员。

三、总结

本文主要介绍了什么是类加载器以及类加载器的分类 ,让大家对类加载器相关的知识有一个整体的认识,这样我们也知道了哪些类加载器加载什么地方的数据。为我们后面对类加载器源码和分析以及实现自定义类加载器做好铺垫。预告:下一篇文章讲一下类加载器的源码分析和设计模式,以及实现一个自定义类加载器!

四、参考资料

《深入理解Java虚拟机》

推荐阅读

Java的线程安全、单例模式、JVM内存结构等知识梳理
Java内存管理-程序运行过程(一)
Java内存管理-初始JVM和JVM启动流程(二)
Java内存管理-JVM内存模型以及JDK7和JDK内存模型对比总结(三)


谢谢你的阅读,如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你每天开心愉快!


不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页 : http://blog.csdn.net/u010648555

愿你我在人生的路上能都变成最好的自己,能够成为一个独挡一面的人

© 每天都在变得更好的阿飞云

Java内存管理-掌握虚拟机类加载器(五)的更多相关文章

  1. Java内存管理-掌握虚拟机类加载机制(四)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇介绍了整个JVM运行时的区域,以及简单对比了JDK7和JDK8中JVM运行时区域 ...

  2. Java内存管理-掌握自定义类加载器的实现(七)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇分析了ClassLoader的类加载相关的核心源码,也简单介绍了ClassLoa ...

  3. 详解Java内存区域?虚拟机类加载机制?

    一.Java运行时数据区域 1.程序计数器 “线程私有”的内存,是一个较小的内存空间,它可以看做当前线程所执行的字节码的行号指示器.Java虚拟机规范中唯一一个没有OutOfMemoryError情况 ...

  4. Java内存区域与虚拟机类加载机制

    一.Java运行时数据区域 1.程序计数器 “线程私有”的内存,是一个较小的内存空间,它可以看做当前线程所执行的字节码的行号指示器.Java虚拟机规范中唯一一个没有OutOfMemoryError情况 ...

  5. 【摘录】JAVA内存管理-自动选择垃圾收集器算法

    在J2SE 5.0,垃圾收集的默认值:垃圾收集器.堆大小以及JVM的类型(客户端还是服务器)都会根据应用运行的硬件平台和操作系统自动选择.相比之前设置命令行参数的方式,自动选择很好的匹配了不同类型的应 ...

  6. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  7. Java内存管理-一文掌握虚拟机创建对象的秘密(九)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! [福利]JVM系列学习资源无套路赠送 回顾一下: 本文是接着上一篇内容:Java内存管 ...

  8. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  9. java jvm虚拟机类加载器

    在Java中任意一个类都是由这个类本身和加载这个类的类加载器来确定这个类在JVM中的唯一性. 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到J ...

随机推荐

  1. netstat常见基本用法(转)

    netstat 简介 Netstat 是一款命令行工具,可用于列出系统上所有的网络套接字连接情况,包括 tcp, udp 以及 unix 套接字,另外它还能列出处于监听状态(即等待接入请求)的套接字. ...

  2. day11 函数的位置形参,位置实参,可变长位置形参,关键字形参

    今天内容 函数的参数详解 形参与实参 形参及形式参数,就是在定义函数是括号中指定的参数(本质就是一个名字) 实参及实际参数,指的是在调用函数是传入的参数)(本质就是一个值) 在调用函数是就会把形参和实 ...

  3. cf1110F 离线+树上操作+线段树区间更新

    自己搞的算法超时了..但是思路没什么问题:用线段树维护每个点到叶子节点的距离即可 /* 线段树维护区间最小值,每次向下访问,就把访问到的点对应的区间段减去边权 到另一颗子树访问时,向上回溯时加上减去的 ...

  4. 官方版sublime Text3汉化和激活注册码

    转载:https://www.cnblogs.com/chaonuanxi/p/9371837.html sublimeText3 很不错,前面几天下了vscore学习Node.js,感觉有点懵,今天 ...

  5. Linux之man命令详解及中文汉化

    使用方法 Linux man中的man就是manual的缩写,用来查看系统中自带的各种参考手册 使用方法: man command 示例: [root@VM_0_13_centos ~]# man l ...

  6. 论文阅读笔记二-ImageNet Classification with Deep Convolutional Neural Networks

    分类的数据大小:1.2million 张,包括1000个类别. 网络结构:60million个参数,650,000个神经元.网络由5层卷积层,其中由最大值池化层和三个1000输出的(与图片的类别数相同 ...

  7. IDEA中每次拷贝一个项目的时候必须标记一下配置文件resources,否则报错

  8. HDU 2588 GCD(欧拉函数)

    GCD Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  9. Spring MVC基础知识整理➣国际化和异常处理

    概述 Spring框架为WEB项目提供了国际化以及异常处理机制.所谓的国际化也就是不同国籍,显示不同国籍的语言与符号.异常处理,也就是能够捕获WEB项目下的所有异常信息,并能处理记录这些异常信息机制. ...

  10. 【回顾】html属性、标题、段落、文本格式化

    1.HTML 属性 HTML 元素可以设置属性 属性可以在元素中添加附加信息 属性一般描述于开始标签 属性总是以名称/值对的形式出现,比如:name="value". HTML 提 ...