类加载器负责将.class文件加载到内存,并为其创建java.lang.Class对象,这个对象就代表这个类。

在Java中,通过包名+类名来唯一标识一个类,而在JVM中,要用 类加载器实例+包名+类名 来唯一标识一个类。 可见JVM中是不止一种类加载器的。

在JVM中,类加载器是成层次结构的, 这种层次结构自上而下分别是根类加载器(BootstrapLoader),扩展类加载器(extensionLoader)和系统类加载器(systemLoader)还有用户自定义类加载器

根类加载器(BootstrapLoader)

负责加载JAVA核心类(例如tr.jar)。 根类加载器是由JVM自身实现的(C/C++),而不是JAVA实现,更不是java.lang.ClassLoader的子类。

下面程序演示了根类加载器所加载的JAVA核心类库。

 package jvmTest;

 import java.net.URL;

 import sun.misc.Launcher;

 public class Boot {
public static void main(String[] args) {
/*
* 这里有可能报错 Access restriction: The type 'Launcher' is not API
* 只需要将 全局属性Project>preferences>java>Compiler>Errors/Warnings>
* 把右侧的【Deprecated and restricted API>Forbidden reference的Error】置为【Warning】.
*/
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for(int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
}
}

在我的环境中输入如下,

 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/bin/default/jclSC170/vm.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/se-service.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/math.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/jlm.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmorb.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmorbapi.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmcfw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmpkcs.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmcertpathfw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjgssfw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjssefw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmsaslfw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjcefw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjgssprovider.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjsseprovider2.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmcertpathprovider.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/xmldsigfw.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/xml.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/charsets.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/resources.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/rt.jar
file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmgpu.jar

可以看到rt.jar包含在其中, 正因为加载了这些类库,我们才可以在程序中直接使用 System, String这样的类

扩展类加载器(extensionLoader)

负责加载来自JRE的扩展目录(\jre\lib\ext\ 或者 java.ext.dirs 系统属性指定的目录)中JAR包中的类, 我们也可以将自己的类放在这个目录下作为扩展类加载。

系统类加载器(systemLoader)

也称为应用类加载器, 负责加载下面几种类,

  • JVM启动时加载来自 java命令的 -classpath选项的JAR包
  • java.lang.path系统属性
  • CLASSPATH环境变量

类的加载机制

  • 全盘负责

当一个类加载器加载一个Class时,该Class所依赖的其他Class也将由相同类加载器加载。

  • 父类委托

JVM加载一个Class时,会先使用其父类加载器来加载,所以一直迭代到最上层的加载器,一个类会最先由BootstrapLoader尝试加载,如果失败则由extensionLoader尝试加载,再失败则由systemLoader尝试加载,最后还失败则由自定义的类加载器来加载,如果依然失败,就会抛出错误。 父类委托机制可以防止类被重复加载,也更安全

所以常规加载顺序如下图 (图片引用自 http://blog.csdn.net/xyang81/article/details/7292380)

但是tomcat采用了完全相反的机制,先通过默认类加载器加载,如果失败,再找父类加载器加载。

这篇文章这样描述tomcat的加载过程(http://ifeve.com/classloader/)

下面例子演示了这种层次关系,

 package jvmTest;

 import java.net.URL;
import java.util.Enumeration; public class Loader {
public static void main(String[] args) throws Exception {
// 获取系统类加载器
ClassLoader scl = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器(systemLoader): "+ scl);
// 获取系统 类加载器 的路径,通常由环境变量CLASSPATH指定,如果操作系统未指定CLASSPATH,则取当前路径
// 在ClassLoader类中定义的方法, public Enumeration<URL> getResources(String name)
// Enumeration比较古老,比较少用到,多数情况下都已经被Iterator取代
Enumeration<URL> eml= scl.getResources("");
while(eml.hasMoreElements()) {
System.out.println("系统加载器路径: "+eml.nextElement());
}
// 获取系统加载器的父加载器,得到扩展类加载器
ClassLoader ecl = scl.getParent();
System.out.println("扩展加载器(extensionLoader): "+ ecl);
System.out.println("扩展加载器路径: "+ System.getProperty("java.ext.dirs"));
System.out.println("扩展加载器的parent: "+ ecl.getParent());
}
}

执行结果,

 系统类加载器(systemLoader): sun.misc.Launcher$AppClassLoader@4be822c2
系统加载器路径: file:/C:/Users/IBM_ADMIN/PROJECT/CrazyJAVA/PROJECT_JavaBasic/bin/
扩展加载器(extensionLoader): sun.misc.Launcher$ExtClassLoader@cb289176
扩展加载器路径: C:\Program Files (x86)\IBM\Java70\jre\lib\ext
扩展加载器的parent: null

执行结果可以看到扩展类加载器的parent从逻辑上来讲应该是根类加载器,但实际却是null,这是因为根类加载器是用C++实现的,JAVA无法直接访问。

  • 缓存机制

缓存机制保证加载过的Class被缓存起来,当加载新类时,先进缓存查询是否已经加载,只有缓存中没有的时候才进行加载,这样会显著提高性能。

reference

深入浅出ClassLoader

http://ifeve.com/classloader/

深入分析Java ClassLoader原理

http://blog.csdn.net/xyang81/article/details/7292380

JAVA基础知识之JVM-——类加载器的更多相关文章

  1. JAVA基础知识之JVM-——自定义类加载器

    JVM中除了根加载器之外其他加载器都是ClassLoader的子类实例, 可以通过扩展ClassLoader的子类,通过重写方法来实现自定义的类加载器. ClassLoader中有两个关键的方法如下, ...

  2. 【java虚拟机系列】JVM类加载器与ClassNotFoundException和NoClassDefFoundError

    在我们日常的项目开发中,会经常碰到ClassNotFoundException和NoClassDefFoundError这两种异常,对于经验足够的工程师而言,可能很轻松的就可以解决,但是却不一定明白为 ...

  3. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

  4. java 基础知识学习 JVM虚拟机参数配置

    1) 设置-Xms.-Xmx相等: 2) 设置NewSize.MaxNewSize相等: 3) 设置Heap size, PermGen space: Tomcat 的配置示例:修改%TOMCAT_H ...

  5. JAVA基础知识|java虚拟机(JVM)

    一.JVM简介 java语言是跨平台的,兼容各种操作系统.实现跨平台的基石就是虚拟机(JVM),虚拟机不是跨平台的,所以不同的操作系统需要安装不同的jdk版本(jre=jvm+类库:jdk=jre+开 ...

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

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

  7. 沉淀,再出发:Java基础知识汇总

    沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的 ...

  8. java基础知识一览(二)

    一.java基础知识 1.一个文件中只能有一个public的类,因为他的类名要求和文件名相同. 2.classpath变量可以设置其它目录下的类. 例如:类文件所在目录是:F:\Javajdk,那么没 ...

  9. 「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !

    本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指南」一份涵盖大 ...

  10. 从 1 开始学 JVM 系列 | JVM 类加载器(一)

    从 1 开始学 JVM 系列 类加载器,对于很多人来说并不陌生.我自己第一次听到这个概念时觉得有点"高大上",觉得只有深入 JDK 源码才会触碰到 ClassLoader,平时都是 ...

随机推荐

  1. Ways to access Oracle Database in PostgreSQL

    Today, organizations stores information(data) in different database systems. Each database system ha ...

  2. "数学口袋精灵"bug的发现及单元测试

    1.项目内容: 团队项目:二次开发 至此,我们有了初步的与人合作经验,接下来投入到更大的团队中去. 也具备了一定的个人能力,能将自己的代码进行测试.接下来尝试在别人已有的基础上进行开发. 上一界51冯 ...

  3. HDU 4031 Attack(离线+线段树)(The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4031 Problem Description Today is the 10th Annual of ...

  4. hdu5381 The sum of gcd

    莫队算法,预处理出每个数字往后的gcd情况,每个数字的gcd只可能是他的因子,因此后面最多只可能有logn种,可以先预处理出,然后套莫队算法,复杂度O(n*sqrt(n)*log(n)). 代码 #i ...

  5. PHP V5.2 中的新增功能,第 1 部分: 使用新的内存管理器

    PHP V5.2:开始 2006 年 11 月发布了 PHP V5.2,它包括许多新增功能和错误修正.它废止了 5.1 版并被推荐给所有 PHP V5 用户进行升级.我最喜欢的实验室环境 —— Win ...

  6. C#与js的各种交互

    今天遇到一个问题,查到不错的资料,放上来记录一下,以防忘记地址,算是我的笔记吧! 很多人都向在服务器端调用客户端的函数来操作,也就是在asp中调用javascript脚本中已经定义好的脚本函数.经过研 ...

  7. mysql设置时区方法

    set global time_zone = '+2:00'; ##修改mysql全局时区 set time_zone = '+2:00'; ##修改当前会话时区 flush privileges; ...

  8. SQL 中常见的系统存储过程

    -- 来源于网络 -- 更详细的介结参考联机帮助文档 xp_cmdshell --*执行DOS各种命令,结果以文本行返回. xp_fixeddrives --*查询各磁盘/分区可用空间 xp_logi ...

  9. SLC、MLC和TLC三者的区别

    SLC=Single-LevelCell,即1bit/cell,速度快寿命长,价格超贵(约MLC3倍以上的价格),约10万次擦写寿命 MLC=Multi-LevelCell,即2bit/cell,速度 ...

  10. php使用过滤器filter_var轻松验证邮箱url和ip地址等

    以前使用php的时候还不知道有过滤器filter这玩意,那时候判断邮箱.url和ip地址格式是否符合都是用正则表达式.后来随着使用的逐渐深入,才知道在php中也可以使用内置的函数库过滤器filter来 ...