深入了解java虚拟机(JVM) 第十二章 类加载器
一、什么是类加载器
类加载器是一个用来加载类文件的类,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) 第十二章 类加载器的更多相关文章
- 第十二章 类加载器&反射
12.1.类加载器 12.1.1.类加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载.类的连接.类的初始化这三个步骤来对类进行初始化.如果不出现意外情况,JVM将会连续完成 ...
- “全栈2019”Java多线程第三十二章:显式锁Lock等待唤醒机制详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java虚拟机学习(5):类加载器(ClassLoader
类加载器 类加载器(ClassLoader)用来加载 class字节码到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源文件在经过 Javac之后就被转换成 ...
- 《深入理解Java虚拟机》之(二、垃圾收集器与内存分配策略)
程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了,而java堆和方法区 ...
- 深入理解Java虚拟机学习笔记(二)-----垃圾收集器与内存分配策略
写在前面 本节常见面试题: 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何 ...
- JVM体系结构之二:类加载器
一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的加载 ...
- (转)《深入理解java虚拟机》学习笔记8——Tomcat类加载器体系结构
Tomcat 等主流Web服务器为了实现下面的基本功能,都实现了不止一个自定义的类加载器: (1).部署在同一个服务器上的两个web应用程序所使用的java类库可以相互隔离. (2).部署在同一个服务 ...
- java 面向对象编程 --第十二章 JDK常用类
1. 系统类 java.lang包 System类 sys.out;sys.exit;sys.gc; sys.currentTimeMillis();----得到从1970-01-01到当前时间 ...
- 读书笔记,《深入理解java虚拟机》,第三章 垃圾收集器与内存分配策略
要实现虚拟机,其实人们主要考虑完成三件事情: 第一,哪些内存需要回收: 第二,什么时候回收: 第三,如何回收. 第二节,对象已死吗 垃圾收集其实主要是针对java堆里面的数据来说的,传统的垃圾收 ...
随机推荐
- X264编码流程详解(转)
http://blog.csdn.net/xingyu19871124/article/details/7671634 对H.264编码标准一直停留在理解原理的基础上,对于一个实际投入使用的编码器是如 ...
- linux之badblocks命令
简介 该命令用来检测硬盘坏道.硬盘坏道问题,如忽视,会随着使用而扩大面积,严重损坏硬盘.一般采用检测坏道,进而屏蔽重分区的方式复用硬盘. 语法 badblock(选项)(参数) -b<区块大小& ...
- PHP中的各种POST或GET请求
1.表单<form> 2.fsockopen(); 3.jquery语法: $.post ($.ajax的简写) 示例代码: <!DOCTYPE html> <html& ...
- Django基础学习二
今天继续学习django的基础 学习用户提交url如何获得返回值 1.首先需要在工程的urls文件定义指定的urls要路由给哪个函数 在这个例子中,我们定义home的urls路由给views里的tes ...
- 4款APP原型设计工具助你搞定移动应用设计!
随着信息化社会的不断发展,不仅手机迭代更新的速度飞快,就连手机里的App 也层出不穷.作为一名UI/UX设计师或产品经理,如何才能设计一款出色的移动App?光有好的创意是不够的,你还需要一款正确的Ap ...
- jsoncpp学习
// MyJsonTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <fstream> #includ ...
- URL Scheme
[URL Scheme] 可以通过info.plist注册url types来实现程序自定义的协议,以供外部程序调起. NSURL *myURL = [NSURL URLWithString:@&qu ...
- Oracle ERP View - fnd_global.apps_initialize
在ORACLE APPLICATION FORM中已存储了数据,在客户端TOAD中查找其TABLE找到相关数据行,但当查找其VIEW时就无法找到数据. 原因ORACLE的权责及OU安全机制屏蔽问题. ...
- [编译,报错以及其他] 有关C/C++中int不能用-2147483648当最小值的问题
这个取决于今早看耗子叔的微博: 这里说到了int的取值范围的问题,int的取值是-2147483648 ~ 2147483647,但是如果直接在编译器(VS2013)中使用-2147483648会报错 ...
- Objective-C 学习笔记(一) 语言程序结构
Objective-C语言程序结构 “Hello World”简单示例 #import <Foundation/Foundation.h> //预处理命令,它告诉Objective-C语言 ...