JVM类加载器命名空间的详细总结
类加载器的命名空间
本文的父子加载器不代表有继承关系,仅仅只是一种上下级的表达。
命名空间的概念
- 每个类加载器都有各自的命名空间,命名空间由该加载器及所有父加载器所加载的类组成
- 在同一个命名空间中,不会出现全限定类名相同的两个Class对象
- 在不同的命名空间中,可以出现全限定类名相同的两个Class对象
- 父加载器加载的类对其子加载器可见,子加载器加载的类对其父加载器不可见
- 如果两个加载器之间没有直接或间接父子的关系,那么它们各自加载的类相互不可见
案例验证
1.定义一个Student类,里面有一个Student类型的成员变量
public class Student{private Student student;//setter方法的参数是Object类型public void setStudent(Object object) {this.student = (Student) object;}
}
2.当Student.class字节码文件存在类路径下时
public class Demo {public static void main(String[] args) throws ClassNotFoundException,IllegalAccessException, InstantiationException,InvocationTargetException,NoSuchMethodException{//获取线程上下文类加载器,默认是Application ClassLoaderClassLoader classLoader = Thread.currentThread().getContextClassLoader();//使用类加载器加载两个Class对象Class c1 = classLoader.loadClass("Student");Class c2 = classLoader.loadClass("Student");System.out.println(c1 == c2);//使用两个Class对象分别创建一个新的实例(不使用强行转换)Object o1 = c1.newInstance();Object o2 = c2.newInstance();//获取setStudent方法Method m1 = c1.getMethod("setStudent",Object.class);//使用o1对象调用方法,o2对象作为参数传入m1.invoke(o1,o2);System.out.println(o1);}
}
运行结果如下
true
Student{student=Student{student=null}}
- c1 == c2 返回的结果是true,说明在堆内存中同一个类的Class对象有且仅有一个。(学过反射的同学都一定听过这句话,但是这个结论的前提是,在同一个命名空间中。)
- 赋值成功说明这两个实例是同一个类型。
为什么这里说堆内存中同一个类的Class对象有且仅有一个的前提是同一个命名空间中呢?请看下面的例子
这里自定义了一个类加载器,会把本地D盘下myclasspath文件夹下指定名称的字节码文件加载成类。
public class Demo {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {//创建两个自定义类加载器的对线下MyClassLoader c1 = new MyClassLoader();MyClassLoader c2 = new MyClassLoader();//分别使用两个类加载器加载Student类Class s1 = c1.loadClass("Student");Class s2 = c2.loadClass("Student");System.out.println(s1 == s2);Object o1 = s1.newInstance();Object o2 = s2.newInstance();Method m1 = s1.getMethod("setStudent", Object.class);m1.invoke(o1,o2);System.out.println(o1);}
}class MyClassLoader extends ClassLoader{@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String path = "D:\\myclasspth\\" + name + ".class";try {//创建byte数组输出流ByteArrayOutputStream os = new ByteArrayOutputStream();//把字节码文件复制到流中Files.copy(Paths.get(path),os);//得到字节数组byte[] bytes = os.toByteArray();//调用父类的defineClass方法加载类return defineClass(name,bytes,0,bytes.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException("找不到类文件");}}
}
如无意外,试了第一个例子的伙伴们会发现,这个程序输出结果和第一个例子一模一样。那么我提出这个例子的意义在哪里呢?
- 根据类加载器的双亲委派机制,自定义类加载器 < 应用类加载器 < 拓展类加载器 < 启动类加载器,自定义类加载器加载Student这个类的时候首先会去父加载器中检查是否已经加载过,以此类推。
- 因此,尝试过第一个例子的伙伴们在类路径下一定有Student.class这个字节码文件,因此这里实际使用的类加载器还是Application ClassLoader(有所怀疑的朋友可以通过class对象调用getClassLoader方法验证一下)
现在,我们把类路径下的Student.class文件复制到D盘的myclasspath文件夹下,原文件删除(使用IDEA的伙伴要把Student类也删除,不然运行的时候很可能就会自动生成字节码文件),然后重新运行程序。
这次的运行结果如下:
这个运行结果的重点在于
- s1 == s2 返回的结果是false
- 报错信息中的Student cannot be cast to Student
为什么s1 == s2返回的结果是false呢?
答案很简单,加载Student类的时候根据双亲委派机制发现类路径下也没有Student.class文件,因此就要自己去加载。而根据命名空间的概念,类加载器c1和c2没有任何父子关系,因此并不在同一个命名空间中,他们互相不知道对方加载过Student类,所以就会有两个Student类的Class对象。这说明了堆内存中同一个类的Class对象有且仅有一个的前提是同一个命名空间中。
为什么Student cannot be cast to Student?
因为Class对象不一样,JVM会认为这是两个完全不同的引用类型,所以就会引发类型转换异常。
结尾
学习这部分内容的时候上网查阅了很多资料,参考了不少的帖子,以上是自己整理后的一些理解和总结,如有错误,请各位指出纠正。
JVM类加载器命名空间的详细总结相关推荐
- Java高并发编程详解系列-JVM类加载器
之前的博客中提到了类加载的过程,提到了双亲委托机制,提到了关于类加载器的概念,这篇博客就来给大家分享一下什么是JVM的类加载器.通过实战的方式来了解一下类加载器器到底是什么. JVM类加载器分类 ...
- jvm十三:类加载器命名空间
package com.atChina.jvm;import java.io.*;public class Test16 extends ClassLoader{private String clas ...
- 《Java虚拟机原理图解》5. JVM类加载器机制与类加载过程
参考网址:http://blog.csdn.net/luanlouis/article/details/50529868 0.前言 读完本文,你将了解到: 一.为什么说Jabalpur语言是跨平台的 ...
- 彻底搞懂JVM类加载器:基本概念
点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 阿杜的世界 来源 | javaadu 在Java面试中,在考察完项目经验.基础技术 ...
- jvm:类加载器与双亲委派模型
两个类相等需要类本身相等,并且使用同一个类加载器进行加载.这是因为每一个类加载器都拥有一个独立的类名称空间. 这里的相等,包括类的 Class 对象的 equals() 方法.isAssignable ...
- 自定义类加载器_jvm超详细探索自定义类加载器(值得收藏)
原创:鲁班学院子牙老师 微信公众号搜索启明南 如果你想看懂本篇文章,需要你对类加载器有一定的了解.如JVM自带的类加载器.双亲委派.自定义类加载器.类加载每个阶段做了什么--如果你对这些知识还有夹生的 ...
- jvm类加载器以及双亲委派
首先来了解几个概念: 类加载: 概念:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验--转换解析--初始化,最终形成能被java虚拟机直接使用的java类型,就是jvm的类加载机制. ...
- jvm运行时类加载机制_JVM体系结构:JVM类加载器和运行时数据区
jvm运行时类加载机制 各位读者好! 在JVM系列的上一篇文章中,开发人员了解了Java虚拟机(JVM)及其体系结构. 本教程将帮助开发人员正确回答以下主题的问题: ClassLoader子系统 运行 ...
- JVM体系结构:JVM类加载器和运行时数据区
各位读者好! 在JVM系列的上一篇文章中,开发人员了解了Java虚拟机(JVM)及其体系结构. 本教程将帮助开发人员正确回答以下主题的问题: ClassLoader子系统 运行时数据区 1.简介 在继 ...
- JVM—类加载器和双亲委派模型
关注微信公众号:CodingTechWork,一起工作学习总结. 文章目录 引言 类加载器 类与类加载器关系 类加载器分类 启动类加载器 扩展类加载器 应用程序类加载器 双亲委派模型 介绍 工作流程 ...
最新文章
- 职称计算机证是继续教育的内容吗,豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~...
- python 南京大学_南京大学python课程系列笔记之python基础之第一周:走进python
- USB2.0 设备类代码表
- 自定义字符串变量赋值在查询语句中使用
- 《JavaScript设计模式与开发实践》模式篇(5)—— 观察者模式
- VTK:PolyData之ConvexHull
- 高效运维最佳实践:如何做好On-call和事故响应?
- SAP Spartacus UI ConfigurableRoutesService router.resetConfig 的调用逻辑
- QueryPerformanceFrequency 和 QueryPerformanceCounter用法
- Spring Cloud Config 规范 1
- 子文件夹的权限统一于E盘的权限
- notepad++,vim驼峰命名与下划线的互相转换
- azure机器学习_Azure机器学习中的数据清理
- 一个肉夹馍引起的思考
- [转载] numpy.argmin 使用
- python文件下载学习
- vue项目 报sockjs.js?9be2:1606 GET http://192.168.43.226:8080/sockjs-node/info?t=1584966826465 net::ERR
- 深入浅出通信原理丨边缘计算阅读周
- java-jsoup爬虫
- 【MM VS价】移动平均价V标准价格S(一)