JVM学习笔记17——类加载器双亲委托机制实力剖析
发布日期:2021-06-29 01:18:53
浏览次数:2
分类:技术文章
本文共 4101 字,大约阅读时间需要 13 分钟。
@Override protected Class findClass(String className) throws ClassNotFoundException { System.out.println("findClass invoked: " + className); System.out.println("class loader name: " + this.classLoaderName); byte[] bytes = this.loadClassDate(className); return this.defineClass(className,bytes,0,bytes.length); }
在MyTest16中加入输出,发现并不会执行findClass方法
System.out.println(o.getClass().getClassLoader());
输出类加载器看到是AppClassLoader加载的o
上述两点说明在Object o 并不是由我们自定义的类加载器加载的,这是因为双亲委托模型,我们自定义的类加载器委托给了系统类加载器
系统类加载器就是这个类的定义类加载器,系统类加载器和MyTest16就是他的初始类加载器
public class MyTest16 extends ClassLoader{ private String classLoaderName; private String path; private final String fileExtension = ".class"; public MyTest16(String classLoaderName){ super(); // 将系统类加载器当做该类加载器的父类加载器 this.classLoaderName = classLoaderName; } public MyTest16(ClassLoader parent, String classLoaderName){ super(parent); // 显式指定父类加载器 this.classLoaderName = classLoaderName; } public void setPath(String path) { this.path = path; } @Override public String toString() { return "MyTest16{" + "classLoaderName='" + classLoaderName + '\'' + '}'; } @Override protected Class findClass(String className) throws ClassNotFoundException { System.out.println("findClass invoked: " + className); System.out.println("class loader name: " + this.classLoaderName); byte[] bytes = this.loadClassDate(className); return this.defineClass(className,bytes,0,bytes.length); } private byte[] loadClassDate(String name){ InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = null; name = name.replace(".","/"); try { is = new FileInputStream(new File(this.path + name + this.fileExtension)); baos = new ByteArrayOutputStream(); int ch = 0; while(-1 != (ch = is.read())){ baos.write(ch); } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); }finally { try { is.close(); baos.close(); } catch (IOException e) { e.printStackTrace(); } } return data; } public static void main(String[] args) throws Exception{ MyTest16 loader1 = new MyTest16("loader1"); // 在本地建立指定目录,然后删掉idea编译的MyTest1,可以发现findClass执行了 loader1.setPath("D:\\workspace\\"); // loader1.setPath("/d/workspace/jvm_lecture/target/classes/"); Class clazz = loader1.loadClass("com.yshuoo.jvm.classloader.MyTest1"); System.out.println("class: " + clazz.hashCode()); Object object = clazz.newInstance(); System.out.println(object); }}
对MyTest16做出修改,可以指定路径去加载,在系统类加载器默认路径外创建一个完整的路径,之后编译好的MyTest1,执行发现findClass方法执行,证明我们自定义的类加载器从指定路径加载了MyTest1(删掉了原本target里的MyTest1.class 父类加载器——系统类加载器加载失败)
new 一个新的类加载器loader2,和loader1一样从同一的路径加载,重新构造项目恢复MyTest1
public static void main(String[] args) throws Exception{ MyTest16 loader1 = new MyTest16("loader1"); // 在本地建立指定目录,然后删掉idea编译的MyTest1,可以发现findClass执行了 loader1.setPath("D:\\workspace\\"); // loader1.setPath("/d/workspace/jvm_lecture/target/classes/"); Class clazz = loader1.loadClass("com.yshuoo.jvm.classloader.MyTest1"); System.out.println("class: " + clazz.hashCode()); Object object = clazz.newInstance(); System.out.println(object); System.out.println("************"); MyTest16 loader2 = new MyTest16("loader2"); loader2.setPath("D:\\workspace\\"); Class clazz2 = loader2.loadClass("com.yshuoo.jvm.classloader.MyTest1"); System.out.println("class: " + clazz2.hashCode()); Object object2 = clazz2.newInstance(); System.out.println(object2); }
可以看出系统类加载器第一次加载过了MyTest1,第二次不再重新加载
再把MyTest1.class删掉
执行结果如下:
两个类加载器都执行了,而且同一个类被加载了两次,这和命名空间有关系
- 每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成
- 在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类
- 在不同的命名空间中,有可能会出现类的完整名字爱(包括类的包名)相同的两个类
转载地址:https://blog.csdn.net/yshuoo/article/details/116520594 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
不错!
[***.144.177.141]2024年04月01日 16时09分42秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
jmeter-性能测试7-Stepping Thread Group插件
2019-04-29
jmeter-性能测试9-测试执行
2019-04-29
沟通交流碎碎念
2019-04-29
电信集成笔试题
2019-04-29
jmeter-性能测试8-性能测试基本过程及示例
2019-04-29
1.vue起步
2019-04-29
3.vue条件语句
2019-04-29
10.vue实战--form表单属性绑定
2019-04-29
11.vue实战--form表单字段验证提交验证
2019-04-29
12.vue实战--接口请求,组件使用,页面跳转配置
2019-04-29
打破职能之缺陷预防之路
2019-04-29
mac开启mysql,重置mysql密码,允许远程连接
2019-04-29
安装kibana
2019-04-29
linux安装nodejs
2019-04-29
tomcat部署vue,spring项目
2019-04-29
idea2020打包war包
2019-04-29
测试框架
2019-04-29
解决切换分支时,maven不自动下载依赖的问题
2019-04-29
java正则
2019-04-29
ios app开发环境配置方法总结
2019-04-29