Java 理解类加载过程 -- 自定义加载器
类加载器可以看下我的收藏:
https://www.cnblogs.com/dongguacai/p/5879931.html
现在准备一个字节码文件:
自定义加载器:
package com.xzlf.test; import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; /**
* 自定义类加载器
*
* @author xzlf
*
*/
public class MyClassLoader extends ClassLoader {
// 类加载器查找的根目录
private String rootDir; public MyClassLoader(String rootDir) {
super();
this.rootDir = rootDir;
} @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 查看 c 是否已经被加载
Class<?> c = findLoadedClass(name);
if(c != null) {
// 已经加载直接返回
return c;
}else {
// 没有被加载,先委派给父类加载器, 最终会委派到引导类加载器
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name);
} catch (ClassNotFoundException e) {
//e.printStackTrace();
}
// 如果父类加载器已加载则直接返回,如果没有加载则使用自定加载器加载类的字节码文件
if(c != null) {
return c;
}else {
// 获取字节码文件
byte[] classDatas = getClassData(name);
if(classDatas == null) {
throw new ClassNotFoundException();
}else {
//Converts an array of bytes into an instance of class
c = defineClass(name, classDatas, 0, classDatas.length);
}
}
}
return c;
} // 获取字节码文件
private byte[] getClassData(String name) {
//com.test.A --> f:/mycode/ com/test/A.class
String path = rootDir + "/" + name.replace('.', '/') + ".class"; // IO 操作 返回字节码
InputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
byte[] flush = new byte[1024];
int len;
while((len = is.read(flush)) != -1) {
bos.write(flush, 0, len);
}
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
测试代码:
package com.xzlf.test; public class TestClassLoader {
public static void main(String[] args) throws Exception {
MyClassLoader loader1 = new MyClassLoader("f:/mycode");
MyClassLoader loader2 = new MyClassLoader("f:/mycode"); Class<?> c1 = loader1.loadClass("com.test.Welcome");
Class<?> c2 = loader1.loadClass("com.test.Welcome");
Class<?> c3 = loader2.loadClass("com.test.Welcome"); Class<?> c4 = loader2.loadClass("java.lang.String");
Class<?> c5 = loader2.loadClass("com.xzlf.test.MyClassLoader"); // 自定义加载器
System.out.println("c1-->" + c1.hashCode() + "-->" + c1.getClassLoader());
System.out.println("c2-->" + c2.hashCode() + "-->" + c2.getClassLoader()); // 同一个类,被不同的加载器加载,JVM认为也是不相同的类
System.out.println("c3-->" + c3.hashCode() + "-->" + c3.getClassLoader()); // 引导加载器
System.out.println("c4-->" + c4.hashCode() + "-->" + c4.getClassLoader()); // 应用加载器
System.out.println("c5-->" + c5.hashCode() + "-->" + c5.getClassLoader());
}
}
运行测试:
Java 理解类加载过程 -- 自定义加载器的更多相关文章
- Java类加载机制及自定义加载器
转载:https://www.cnblogs.com/gdpuzxs/p/7044963.html Java类加载机制及自定义加载器 一:ClassLoader类加载器,主要的作用是将class文件加 ...
- xLua自定义加载器
xLua入门基础 环境配置 github下载xLua文件: xLua是腾讯开发,据说比较先进: 下载下来后将Plugins和XLua文件夹考进项目: Plugins多平台权限:XLua和C#交互: t ...
- java中三个类别加载器的关系以及各自加载的类的范围
Java在需要使用类别的时候,才会将类别加载,Java的类别载入是由类别载入器(Class loader)来达到的,预设上,在程序启动之后,主要会有三个类别加载器:Bootstrap Loader.E ...
- 深入理解JVM-类加载器深入解析(3)
深入理解JVM-类加载器深入解析(3) 获得ClassLoader的途径 获得当前类的ClassLoader clazz.getClassLoader() 获得当前线程上下文的ClassLoader ...
- JVM类加载(4)—加载器
定义: 虚拟机设计团队把类加载阶段中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称之为“类加载器 ...
- 深入理解JVM-类加载器深入解析(2)
深入理解JVM-类加载器深入解析(2) 加载:就是把二进制形式的java类型读入java虚拟机中 连接: 验证: 准备:为类变量分配内存,设置默认值.但是在到达初始化之前,类变量都没有初始化为真正的初 ...
- 我理解的Android加载器
Android的加载器(loader)是从Android 3.0开始出来的东西.要理解这里需要先理解为什么会出现加载器(也有地方把它说成是装载器)呢? 如果没有加载器... 首先Activity是我们 ...
- 深入java虚拟机学习 -- 类的加载机制(三)
类的初始化时机 在上篇文章中讲到了类的六种主动使用方式,反射是其中的一种(Class.forName("com.jack.test")),这里需要注意一点:当调用ClasLoade ...
- <JVM中篇:字节码与类的加载篇>04-再谈类的加载器
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
随机推荐
- Python IDE ——Anaconda+PyCharm的安装与配置
一 前言 最近莫名其妙地想学习一下Python,想着利用业余时间学习一下机器学习(或许仅仅是脑子一热吧).借着研究生期间对于PyCharm安装的印象,在自己的电脑上重新又安装了一遍.利用周末的一点时间 ...
- iOS 编译过程原理(2)
一.前言 <iOS编译过程的原理和应用>文章介绍了 iOS 编译相关基础知识和简单应用,但也很有多问题都没有解释清楚: Clang 和 LLVM 究竟是什么 源文件到机器码的细节 Link ...
- 深入理解NIO(一)—— NIO的简单使用及其三大组件介绍
深入理解NIO(一)—— NIO的简单使用及其三大组件介绍 深入理解NIO系列分为四个部分 第一个部分也就是本节为NIO的简单使用(我很少写这种新手教程,所以如果你是复习还好,应该不难理解这篇,但如果 ...
- Python库的安装方式
Python库的安装方式 1.Python库的自定义安装——找到相应网站,下载安装 示例:pywin32库安装 .exe,直接双击,自动识别安装目录 安装就可以了. 载入成功 2.Python库的工具 ...
- Mac OS修改VSCode Go的默认缩进格式
一.在VSCode中编写Go代码时,缩进是使用tab缩进,主要是由于以下两个方面. 1. Go官方提供的代码格式化工具gofmt默认是使用tab缩进,并且为8个字符宽度. 2. 并且在VSCode中, ...
- python基础知识 目录 简介
1.1编程语言介绍与分类 什么是编程语言? 本质:与人类语言一样.沟通 电流+一堆硬件 高电压1 低电压0 高电压1 低电压0 高电压1 低电压0 8 晶体管 010101010101 play so ...
- 《Three.js 入门指南》3.1.1 - 基本几何形状-立方体(CubeGeometry)
3.1 基本几何形状 立方体(CubeGeometry) 构造函数: THREE.CubeGeometry(width, height, depth, widthSegments, heightSeg ...
- Java进行二元操作类型转换
当对两个数值进行二元操作时,先要将两个操作数转换为同一种类型,然后再进行计算. 如果两个操作数中有一个是double类型,另一个操作数就会转换为double类型. 否则,如果其中一个操作数是float ...
- Go gRPC教程-服务端流式RPC(三)
前言 上一篇介绍了简单模式RPC,当数据量大或者需要不断传输数据时候,我们应该使用流式RPC,它允许我们边处理边传输数据.本篇先介绍服务端流式RPC. 服务端流式RPC:客户端发送请求到服务器,拿到一 ...
- spring04
今天设计到的内容是是spring的sqel和ioc的生命周期和bean的后置处理器 具体的测试文件如下: <?xml version="1.0" encoding=" ...