classloader 加载jar,classloader加载配置文件
获得ClassLoader的途径
1.获得当前类的类加载器
clazz.getClassLoader()2 .获得当前线程上下文的类加载器
Thread.currentThread().getContextClassLoader();3.获得系统的类加载器
类别载入器。getsystemclass loader()4 .获得调用者的类加载器
司机经理。getcallerclassloaderClassLoader源码解析
(推荐学习:Java视频教程)
概述
代码一:
公共类测试12 {
公共静态void main(String[] args) {
String[] strings=新字符串[6];
系统。出去。println(字符串。getclass().get class loader());
//运行结果:空
测试12[]测试12s=新测试12[1];
系统。出去。println(测试12s。getclass().get class loader());
//运行结果:孙。杂项启动器$app类加载器@ 18 B4 AAC 2
int[]ints=new int[2];
系统。出去。println(整数。getclass().get class loader());
//运行结果:空
}
}loadClass方法
负载等级的源码如下,荷载等级方法加载拥有指定的二进制名称的类,默认按照如下顺序寻找类:
答调用findLoadedClass(字符串)检查这个类是否被加载
b)调用父类加载器的负载等级方法,如果父类加载器为空,就会调用启动类加载器
c)调用findClass(字符串)方法寻找
使用上述步骤如果类被找到且分解为没错,就会去调用resolveClass(类)方法
受保护阶层?装载类别(字符串名称,布尔解析)
引发ClassNotFoundException
{
synchronized(getClassLoadingLock(name)){
//首先,检查该类是否已经加载
班级?c=findLoadedClass(name);
if (c==null) {
长t0=系统。纳米时间();
尝试{
如果(家长!=null) {
c=parent.loadClass(name,false);
}否则{
c=findBootstrapClassOrNull(name);
}
} catch(ClassNotFoundException e){
//如果找不到类,则引发ClassNotFoundException
//来自非空的父类加载器
}
if (c==null) {
//如果还是找不到,那么就按顺序调用查找类
//来查找类。
长t1=系统。纳米时间();
c=查找类(名称);
//这是定义类加载器;记录统计数据
星期日杂项性能计数器。getparentdelegationtime().添加时间(t1-t0);
星期日杂项性能计数器。getfindclasstime().addElapsedTimeFrom(t1);
星期日杂项性能计数器。getfindclass().increment();
}
}
如果(解决){
解决类(c);
}
返回c;
}
}findClass方法
查找类的源码如下,findClass寻找拥有指定二进制名称的类,JVM鼓励我们重写此方法,需要自定义加载器遵循双亲委托机制,该方法会在检查完父类加载器之后被负载等级方法调用,默认返回ClassNotFoundException异常。
受保护阶层?findClass(字符串名称)抛出ClassNotFoundException {
抛出新的ClassNotFoundException(名称);
}defineClass方法
定义类的源码如下,定义类方法将一个字节数组转换为班级的实例。
受保护的最终类?定义类(字符串名,byte[] b,int off,int len,
保护域保护域)
抛出ClassFormatError
{
保护域=预定义类别(名称保护域);
string source=defineClassSourceLocation(保护域);
班级?c=defineClass1(name,b,off,len,protectionDomain,source);
postDefineClass(c,保护域);
返回c;
}自定义类加载器
/**
* 继承了类加载器,这是一个自定义的类加载器
* @作者夜的那种黑丶
*/
公共类ClassLoaderTest扩展类别载入器{
公共静态void main(String[] args)引发异常{
类加载器测试加载器=新类加载器测试( loader );
班级?clazz=loader。加载类(类加载器.测试01’);
object object=clazz。新实例();
系统。出去。println(对象);
系统。出去。println(对象。getclass().get class loader());
}
//- 以上为测试代码-
/**
* 类加载器名称,标识作用
*/
私有字符串classLoaderName
/**
* 从磁盘读物字节码文件的扩展名
*/
私有字符串file extension= . 1 类;
/**
* 创建一个类加载器对象,将系统类加载器当做该类加载器的父加载器
* @param classLoaderName类加载器名称
*/
私有类加载器测试(字符串类加载器名称){
//将系统类加载器当做该类加载器的父加载器
super();
这个。类加载器名称=类加载器名称;
}
/**
* 创建一个类加载器对象,显示指定该类加载器的父加载器
* 前提是需要有一个类加载器作为父加载器
* @param parent父加载器
* @param classLoaderName类加载器名称
*/
私有类加载器测试(类加载器父级,字符串classLoaderName) {
//显示指定该类加载器的父加载器
超级(父母);
这个。类加载器名称=类加载器名称;
}
/**
* 寻找拥有指定二进制名称的类,重写类加载器类的同名方法,需要自定义加载器遵循双亲委托机制
* 该方法会在检查完父类加载器之后被负载等级方法调用
* 默认返回ClassNotFoundException异常
* @param className类名
* @返回类的实例
* @throws ClassNotFoundException如果类不能被找到,抛出此异常
*/
@覆盖
受保护阶层?findClass(字符串类名)抛出ClassNotFoundException {
byte[]data=this。加载类数据(类名);
/*
* 通过定义类方法将字节数组转换为班级
*定义类别:将一个字节数组转换为班级的实例,在使用这个班级之前必须要被解析
*/
返回this.defineClass(类名,数据,0,数据。长度);
}
/**
* io操作,根据类名找到对应文件,返回班级文件的二进制信息
* @param className类名
* @返回类文件的二进制信息
* @throws ClassNotFoundException如果类不能被找到,抛出此异常
*/
私有字节[]loadClassData(字符串类名)抛出ClassNotFoundException {
输入流输入流=空
字节[]数据;
ByteArrayOutputStream ByteArrayOutputStream=null;
尝试{
这个。类别载入器名称=this。类别载入器名称。替换( . ), /);
inputStream=新文件inputStream(新文件(班名这个。文件扩展名));
byteArrayOutputStream=new byteArrayOutputStream();
内部通道
而(-1!=(ch=inputstream。read()){
bytearrayoutputstream。写(ch);
}
data=bytearray输出流。tobytearray();
} catch(异常e) {
抛出新的ClassNotFoundException();
}最后{
尝试{
if (inputStream!=null) {
输入流。close();
}
if (byteArrayOutputStream!=null) {
bytearrayoutputstream。close();
}
} catch (IOException e) {
e。printstacktrace();
}
}
返回数据;
}
}以上是一段自定义类加载器的代码,我们执行这段代码
类加载器。测试01@7f31245a
星期日杂项启动器$ app类加载器@ 18 B4 AAC 2可以看见,这段代码中进行类加载的类加载器还是系统类加载器(AppClassLoader)。这是因为虚拟机(Java虚拟机的缩写)的双亲委托机制造成的,私有ClassLoaderTest(字符串classLoaderName)将系统类加载器当做我们自定义类加载器的父加载器,jvm的双亲委托机制使自定义类加载器委托系统类加载器完成加载。
改造以下代码,添加一个小路属性用来指定类加载位置:
公共类ClassLoaderTest扩展类别载入器{
公共静态void main(String[] args)引发异常{
类加载器测试加载器=新类加载器测试( loader );
装载机。设置路径(/home/fanxuan/Study/Java/JVM Study/out/production/JVM Study/);
班级?clazz=loader。加载类(类加载器.测试01’);
系统。出去。println( class: clazz );
object object=clazz。新实例();
系统。出去。println(对象);
系统。出去。println(对象。getclass().get class loader());
}
//- 以上为测试代码-
/**
* 从指定路径加载
*/
私有字符串路径;
.
/**
* io操作,根据类名找到对应文件,返回班级文件的二进制信息
* @param className类名
* @返回类文件的二进制信息
* @throws ClassNotFoundException如果类不能被找到,抛出此异常
*/
私有字节[]loadClassData(字符串类名)抛出ClassNotFoundException {
输入流输入流=空
字节[]数据;
ByteArrayOutputStream ByteArrayOutputStream=null;
className=className.replace( . , /);
尝试{
这个。类别载入器名称=this。类别载入器名称。替换( . ), /);
inputStream=新文件inputStream(新文件(这个。路径类名this。文件扩展名));
byteArrayOutputStream=new byteArrayOutputStream();
内部通道
而(-1!=(ch=inputstream。read()){
bytearrayoutputstream。写(ch);
}
data=bytearray输出流。tobytearray();
} catch(异常e) {
抛出新的ClassNotFoundException();
}最后{
尝试{
if (inputStream!=null) {
输入流。close();
}
if (byteArrayOutputStream!=null) {
bytearrayoutputstream。close();
}
} catch (IOException e) {
e。printstacktrace();
}
}
返回数据;
}
公共空设置路径(字符串路径){
this.path=path
}
}运行一下
class:class classloader .测试01
类加载器。测试01@7f31245a
星期日杂项启动器$ app类加载器@ 18 B4 AAC 2修改一下测试代码,并删除工程下的Test01.class文件
公共静态void main(String[] args)引发异常{
类加载器测试加载器=新类加载器测试( loader );
loader.setPath(/home/fanxuan/桌面/);
班级?clazz=loader。加载类(类加载器.测试01’);
系统。出去。println( class: clazz );
object object=clazz。新实例();
系统。出去。println(对象);
系统。出去。println(对象。getclass().get class loader());
}运行一下
class:class classloader .测试01
类加载器。测试01@135fbaa4
类加载器ClassLoaderTest@7f31245a分析
改造后的两块代码,第一块代码中加载类的是系统类加载器AppClassLoader,第二块代码中加载类的是自定义类加载器ClassLoaderTest。是因为ClassLoaderTest会委托他的父加载器载器加载类,第一块代码的小路直接是工程下,AppClassLoader可以加载到,而第二块代码的小路在桌面目录下,所以载器无法加载到,然后ClassLoaderTest自身尝试加载并成功加载到。如果第二块代码工程目录下的Test01.class文件没有被删除,那么依然是载器加载。
再来测试一块代码
公共静态void main(String[] args)引发异常{
类加载器测试加载器=新类加载器测试( loader );
装载机。设置路径(/home/fanxuan/Study/Java/JVM Study/out/production/JVM Study/);
班级?clazz=loader。加载类(类加载器.测试01’);
系统。出去。println( class: clazz。hashcode());
object object=clazz。新实例();
系统。出去。println(对象。getclass().get class loader());
类别载入器测试载入器2=新类别载入器测试( loader );
2号装载机。设置路径(/home/樊轩/Study/Java/JVM Study/out/production/JVM Study/);
班级?clazz 2=装载机2。加载类(类加载器.测试01’);
系统。出去。println( class: clazz 2。hashcode());
对象对象2=clazz 2。新实例();
系统。出去。println(对象2。getclass().get class loader());
}结果显而易见,类由系统类加载器加载,并且班级和分类2是相同的。
班级:2133927002
星期日杂项启动器$ app类加载器@ 18 B4 AAC 2
班级:2133927002
星期日杂项启动器$ app类加载器@ 18 B4 AAC 2再改造一下
公共静态void main(String[] args)引发异常{
类加载器测试加载器=新类加载器测试( loader );
loader.setPath(/home/fanxuan/桌面/);
班级?clazz=loader。加载类(类加载器.测试01’);
系统。出去。println( class: clazz。hashcode());
object object=clazz。新实例();
系统。出去。println(对象。getclass().get class loader());
类加载器测试加载器2=新的类加载器测试(“加载器2”);
2号装载机。设置路径(/home/fanxuan/桌面/);
班级?clazz 2=装载机2。加载类(类加载器.测试01’);
系统。出去。println( class: clazz 2。hashcode());
对象对象2=clazz 2。新实例();
系统。出去。println(对象2。getclass().get class loader());
}运行结果
班级:325040804
类加载器ClassLoaderTest@7f31245a
班级:621009875
类加载器类别加载器测试@ 45ee 12a 7类别加载器测试是显而易见,但是班级和分类2是不同的,这是因为类加载器的命名空间的原因。
我们可以通过设置父类加载器来让装货设备和装载机2处于同一命名空间
公共静态void main(String[] args)引发异常{
类加载器测试加载器=新类加载器测试( loader );
loader.setPath(/home/fanxuan/桌面/);
班级?clazz=loader。加载类(类加载器.测试01’);
系统。出去。println( class: clazz。hashcode());
object object=clazz。新实例();
系统。出去。println(对象。getclass().get class loader());
ClassLoaderTest loader2=新的ClassLoaderTest(loader, loader 2 );
2号装载机。设置路径(/home/fanxuan/桌面/);
班级?clazz 2=装载机2。加载类(类加载器.测试01’);
系统。出去。println( class: clazz 2。hashcode());
对象对象2=clazz 2。新实例();
系统。出去。println(对象2。getclass().get class loader());
}运行结果
班级:325040804
类加载器ClassLoaderTest@7f31245a
班级:325040804
类加载器类别载入器测试@ 7f 31245 a扩展:命名空间
1.每个类加载器都有自己的命名空间,命名空间由该加载器及所有的父加载器所加载的类组成
2.在同一命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类
3.在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类
我们,大量的免费爪哇入门教程,欢迎在线学习!以上就是爪哇岛类加载器类加载器详解的详细内容,更多请关注我们其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。