一、什么是类加载器

  类加载器是一个用来加载类文件的类,Java源代码通过javac编译器编译成类文件,然后JVM来执行类文件中的字节码来执行程序。需要注意的是,只有被同一个类加载器加载的类才可能会相等。相同字节码被不同的类加载器加载的类不相等。

二、类加载器分类

  1.启动类加载器

    由C++实现,是虚拟机的一部分,用于加载javahome下的lib目录下的类;

   2.扩展类加载器

    加载javahome下/lib/ext目录中的类;

   3.应用程序类加载器

    加载用户类路径上的所指定的类库,也就是我们所用的类加载器;

三、自定义加载器

  在jvm中,除了以上三种类加载器外,我们还可以自定义加载器,自定义加载器的方法有三步

    1.定义一个类继承classloader

    2.重写loadClass方法

    3.实例化class对象

   我们看下面的例子: 

package com.example.demo;

import java.io.InputStream;

public class Test1 extends ClassLoader{

    @Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
//name的值为com.example.demo.Test1,他是类的绝对路径
//截取name后 fileName的值为Test1.class
//加上.class表示这是个class文件
String fileName=name.substring(name.lastIndexOf(".")+1)+".class";
//加载这个class文件
InputStream input=getClass().getResourceAsStream(fileName); //判断input是否为空
//为空就证明当前文件夹下没有这个文件
//如果为空就让父类加载器去加载它
if (input==null) {
return super.loadClass(name);
}
//如果不为空,就用当前的类加载器进行加载
try {
//简单的IO流操作,用创建一个byte数组,然后将输入流输入数组
byte [] buff=new byte[input.available()];
input.read(buff);
//方便测试,我们加上一行代码
System.out.println("自定义类加载器启动");
//当读取后,我们需要实例化class对象
//在这里我们使用java为我们提供的defineClass方法实例化对象
//defineClass的参数意思:要加载类的绝对路径,读取的数组,从第几位开始读,读到第几位结束
return defineClass(name, buff, 0, buff.length);
} catch (Exception e) {
throw new ClassNotFoundException();
}
} }

  上面我们已经完成了一个自定义类加载器,接下来使用一个方法来测试

package com.example.demo;

public class TestMain {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Test1 test1=new Test1();
//使用反射,用自定义类加载器加载并创建一个实例会对象
Object obj1=test1.loadClass("com.example.demo.TestMain").newInstance();
//使用反射,用系统默认的类加载器加载并创建一个实例会对象
Class<?> cls = Class.forName("com.example.demo.TestMain");
Object obj2=cls.newInstance();
System.out.println(obj1.getClass());
//判断obj1是否是TestMain类的实例
boolean b1=obj1 instanceof TestMain;
System.out.println("obj1是不是TestMain的实例:"+b1);
//判断obj2是否是TestMain类的实例
boolean b2=obj2 instanceof TestMain;
System.out.println("obj2是不是TestMain的实例:"+b2);
}
}

  测试的结果为:

  为什么obj1不是TestMain的实例?这就是回来我们一开始说道的,相同的字节码被不同的类加载器加载的类不相等。

 四、自定义加载器的优势

  1.高度的灵活性;

  2.通过自定义类加载器可以实现热部署

  3.代码加密 

 五、类加载器之间的协同工作--双亲委派模型

  在jvm中有的各种类加载器,他们之间是通过双亲委派模型的类加载机制进行协同工作,如图:

  

双亲委派模型的工作原理主要是:

  1)如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器完成。

  2)每一层的类加载器都把类加载请求委派给父类加载器,直到所有的类加载请求都应该传递给顶层的启动类加载器。

  3)如果顶层的启动类加载器无法完成加载请求,子类加载器尝试去加载,如果连最初发起类加载请求的类加载器也无法完成加载请求时,将会抛出classNotFoundException,而不再调用其子类加载器去进行类加载。

双亲委派模式的类加载机制的优点:

  java类它的类加载器一起具备了一种带优先级的层次关系,越是基础的类,越是被上层的类加载器进行加载,保证了java程序的稳定运行。

深入了解java虚拟机(JVM) 第十二章 类加载器的更多相关文章

  1. 第十二章 类加载器&反射

    12.1.类加载器 12.1.1.类加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载.类的连接.类的初始化这三个步骤来对类进行初始化.如果不出现意外情况,JVM将会连续完成 ...

  2. “全栈2019”Java多线程第三十二章:显式锁Lock等待唤醒机制详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. Java虚拟机学习(5):类加载器(ClassLoader

    类加载器 类加载器(ClassLoader)用来加载 class字节码到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源文件在经过 Javac之后就被转换成 ...

  4. 《深入理解Java虚拟机》之(二、垃圾收集器与内存分配策略)

    程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了,而java堆和方法区 ...

  5. 深入理解Java虚拟机学习笔记(二)-----垃圾收集器与内存分配策略

    写在前面 本节常见面试题: 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何 ...

  6. JVM体系结构之二:类加载器

    一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的加载 ...

  7. (转)《深入理解java虚拟机》学习笔记8——Tomcat类加载器体系结构

    Tomcat 等主流Web服务器为了实现下面的基本功能,都实现了不止一个自定义的类加载器: (1).部署在同一个服务器上的两个web应用程序所使用的java类库可以相互隔离. (2).部署在同一个服务 ...

  8. java 面向对象编程 --第十二章 JDK常用类

    1.  系统类 java.lang包   System类 sys.out;sys.exit;sys.gc; sys.currentTimeMillis();----得到从1970-01-01到当前时间 ...

  9. 读书笔记,《深入理解java虚拟机》,第三章 垃圾收集器与内存分配策略

    要实现虚拟机,其实人们主要考虑完成三件事情: 第一,哪些内存需要回收: 第二,什么时候回收: 第三,如何回收. 第二节,对象已死吗    垃圾收集其实主要是针对java堆里面的数据来说的,传统的垃圾收 ...

随机推荐

  1. [jOOQ中文]3. 数据库版本管理工具Flyway

    https://segmentfault.com/a/1190000010526452 在执行数据库迁移时,我们推荐使用jOOQ与Flyway - 数据库迁移轻松. 在本章中,我们将简单的来使用这两个 ...

  2. BeanUtils.copyProperties不能copy复杂对象List的解决方式

    需要注意的就是把List拆分,遍历add,然后把list设置到返回对象中 package test.test; import java.util.ArrayList; import java.util ...

  3. 让 IE6支持max-height

    min-height min-height:100px; _height:100px max-height max-height:200px; overflow:auto;/*超出部分显示滚动条*/ ...

  4. 自定义annotation-----转载

    Java从JDK5.0开始便提供了四个meta-annotation用于自定义注解的时候使用,这四个注解为:@Target,@Retention,@Documented 和@Inherited. @T ...

  5. iOS对HTTPS证书链的验证原理

    今天看到所在的某个开发群问https原理,之前做HTTPS ,下面简单说下原理.希望能帮助你理解. HTTPS从最终的数据解析的角度,与HTTP相同.HTTPS将HTTP协议数据包放到SSL/TSL层 ...

  6. Golang之字符串操作(反转中英文字符串)

    //字符串反转package main import "fmt" func reverse(str string) string { var result string strLe ...

  7. 训练超参数, 出现 Cannot use GPU in CPU-only Caffe 错误?

    当我们用MNIST手写体数字数据库和LeNet CNN 模型训练超参数,运行 examples/mnist/train_lenet.sh是出现Cannot use GPU in CPU-only Ca ...

  8. SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)

    SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码) 摘自: https://blog.csdn.net/sjin_1314/article/det ...

  9. Java程序设计17——多线程-Part-B

    5 改变线程优先级 每个线程执行都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会. 每个线程默认的优先级都与创建它的父线程具有相同的优先级,在默认情况下,ma ...

  10. va泛型

    va泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的 ...