classloader 加载jar,classloader加载配置文件

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: