一、类加载器的概念

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码到java虚拟机中并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。

二、类加载器的树状组织结构

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的

系统提供的类加载器主要有下面三个:

  • 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
  • 除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。除了引导类加载器之外,所有的类加载器都有一个父类加载器。系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。

每个 Java 类都维护着一个指向定义它的类加载器的引用,通过 getClassLoader()方法就可以获取到此引用。

 Java 虚拟机是如何判定两个 Java 类是相同的:Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。

三、加载类的过程

代理模式:类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。

真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用 defineClass来实现的;而启动类的加载过程是通过调用 loadClass来实现的。前者称为一个类的定义加载器(defining loader),后者称为初始加载器(initiating loader)。在 Java 虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。类加载器在成功加载某个类之后,会把得到的 java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。也就是说,对于一个类加载器实例来说,相同全名的类只加载一次,即 loadClass方法不会被重复调用。

四、类加载器与web容器

拿Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。

Java的类加载器的更多相关文章

  1. java自定义类加载器

    前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...

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

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

  3. 深入探讨java的类加载器

    类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Ja ...

  4. java 中类加载器

    jar 运行过程和类加载机制有关,而类加载机制又和我们自定义的类加载器有关,现在我们先来了解一下双亲委派模式. java 中类加载器分为三个: BootstrapClassLoader 负责加载 ${ ...

  5. java高新技术-类加载器

    1.类加载器及委托机制的深入分析 > 类加载器的作用:一个java文件中的出现的类,首先要把这个类的字节码加载到内存中,这个类的信息放在硬盘的classPath下的class文件中,  把cla ...

  6. 深入理解Java虚拟机 - 类加载器

    引子:       类加载器(classloader)是独立于虚拟机之外,可以独立实现的代码模块.     OSGi使用了类加载器的这一特点实现其热插拔的特性       Java同C++等语言不通, ...

  7. 分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码

    先回顾一下classpath classpath的作用: classpath的作用是指定查找类的路径:当使用java命令执行一个类(类中的main方法)时,会从classpath中进行查找这个类. 指 ...

  8. java面向对象--类加载器及Class对象

    类加载器 jvm 和 类的关系 当调用 java命令运行一个java程序时,会启动一个java虚拟机进程.同一个jvm的所有线程.所有变量都处于同一个进程里,都使用该jvm进程的内存区. jvm进程终 ...

  9. Java的类加载器种类(双亲委派)

    Java类加载器采用双亲委派模型: 1.启动类加载器:这个类加载器负责放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别 ...

随机推荐

  1. javascript基础进阶——执行环境及作用域链

    概念 执行环境 执行环境定义了变量或函数有权访问的其他函数,决定了他们各自的行为.每个执行环境都有一个与之关联的变量对象. 变量对象 环境中定义的所有变量和函数都保存在这个对象中. 全局执行环境 全局 ...

  2. grep Pocket Reference读记

    1 简介 grep的基本命令格式如下:           grep [options] [regexp] [filename]   如果regexp中含有空格,应该使用单引号或双引号括起来.单引号和 ...

  3. Servlet之文件的上传与下载

    文件上传和文件下载是我们学JAVA Web时必不可少的模块.今天我们探讨下这个问题 文件上传: request.setCharacterEncoding("utf-8");//设置 ...

  4. ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界

    HttpContext是ASP.NET中的核心对象,每一个请求都会创建一个对应的HttpContext对象,我们的应用程序便是通过HttpContext对象来获取请求信息,最终生成响应,写回到Http ...

  5. Javascript用数组实现栈和队列

    栈是遵循后进先出(LIFO)规则的一种有序集合,比如桌上的一叠书,我们只能从上面放或取. 队列是遵循先进先出(FIFO)规则的一种有序集合,比如排队,先排到的先离开. 数组也是一种有序的集合,它与上面 ...

  6. C# 实现AOP 的几种常见方式

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的中统一处理业务逻辑的一种技术,比较常见的场景是:日志记录,错误捕获 ...

  7. 使用nfs作为根文件系统启动,(3)

    通过设置u-boot的bootargs来更改开机自动进入nfs远端服务器,不需要mount指令,实现虚拟机编译程序后直接通过u-boot烧写程序 1  使用nfs作为根文件系统启动 1.1    pr ...

  8. NHibernate教程(7)--并发控制

    本节内容 什么是并发控制? 悲观并发控制(Pessimistic Concurrency) 乐观并发控制(Optimistic Concurrency) NHibernate支持乐观并发控制 实例分析 ...

  9. 【★】KMP算法完整教程

    KMP算法完整教程 全称:                               Knuth_Morris_Pratt Algorithm(KMP算法) 类型:                 ...

  10. Nginx做文件下载服务器

    这是最简单的一种办法,贴完代码就能用 server { listen 80; charset utf-8; server_name localhost; root /data/file/; autoi ...