加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

Java的神秘世界:为何说ClassLoader 是 Java最神秘的技术之一

发布时间:2019-10-16 20:07:44 所属栏目:建站 来源:java互联网高级架构
导读:ClassLoader 是 Java 届最为隐秘的技能之一,无数人被它伤透了思维,摸不清门道毕竟在那边。网上的文章也是一篇又一篇,颠末本人的亲身判断,绝大部门内容都是在误导别人。本文我带读者彻底吃透 ClassLoader,往后其余的相干文章你们可以不必再细看了。 Cl

值得留意的是图中的 ExtensionClassLoader 的 parent 指针画了虚线,这是由于它的 parent 的值是 null,当 parent 字段是 null 时就暗示它的父加载器是「根加载器」。假如某个 Class 工具的 classLoader 属性值是 null,那么就暗示这个类也是「根加载器」加载的。留意这里的 parent 不是 super 不是父类,只是 ClassLoader 内部的字段。

Class.forName

当我们在行使 jdbc 驱动时,常常会行使 Class.forName 要领来动态加载驱动类。

  1. Class.forName("com.mysql.cj.jdbc.Driver"); 

其道理是 mysql 驱动的 Driver 类里有一个静态代码块,它会在 Driver 类被加载的时辰执行。这个静态代码块会将 mysql 驱动实例注册到全局的 jdbc 驱动打点器里。

  1. class Driver { 
  2.  static { 
  3.  try { 
  4.  java.sql.DriverManager.registerDriver(new Driver()); 
  5.  } catch (SQLException E) { 
  6.  throw new RuntimeException("Can't register driver!"); 
  7.  } 
  8.  } 
  9.  ... 

forName 要领同样也是行使挪用者 Class 工具的 ClassLoader 来加载方针类。不外 forName 还提供了多参数版本,可以指定行使哪个 ClassLoader 来加载

  1. Class<?> forName(String name, boolean initialize, ClassLoader cl) 

通过这种情势的 forName 要领可以打破内置加载器的限定,通过行使自定类加载器应承我们自由加载其余恣意来历的类库。按照 ClassLoader 的转达性,方针类库转达引用到的其余类库也将会行使自界说加载器加载。

自界说加载器

ClassLoader 内里有三个重要的要领 loadClass()、findClass() 和 defineClass()。

loadClass() 要领是加载方针类的进口,它起首会查找当前 ClassLoader 以及它的双亲内里是否已经加载了方针类,假如没有找到就会让双亲实行加载,假如双亲都加载不了,就会挪用 findClass() 让自界说加载器本身来加载方针类。ClassLoader 的 findClass() 要领是必要子类来包围的,差异的加载器将行使差异的逻辑来获取方针类的字节码。拿到这个字节码之后再挪用 defineClass() 要领将字节码转换成 Class 工具。下面我行使伪代码暗示一下根基进程

  1. class ClassLoader { 
  2.  // 加载进口,界说了双亲委派法则 
  3.  Class loadClass(String name) { 
  4.  // 是否已经加载了 
  5.  Class t = this.findFromLoaded(name); 
  6.  if(t == null) { 
  7.  // 交给双亲 
  8.  t = this.parent.loadClass(name) 
  9.  } 
  10.  if(t == null) { 
  11.  // 双亲都不可,只能靠本身了 
  12.  t = this.findClass(name); 
  13.  } 
  14.  return t; 
  15.  } 
  16.   
  17.  // 交给子类本身去实现 
  18.  Class findClass(String name) { 
  19.  throw ClassNotFoundException(); 
  20.  } 
  21.   
  22.  // 组装Class工具 
  23.  Class defineClass(byte[] code, String name) { 
  24.  return buildClassFromCode(code, name); 
  25.  } 
  26. class CustomClassLoader extends ClassLoader { 
  27.  Class findClass(String name) { 
  28.  // 探求字节码 
  29.  byte[] code = findCodeFromSomewhere(name); 
  30.  // 组装Class工具 
  31.  return this.defineClass(code, name); 
  32.  } 

自界说类加载器不易粉碎双亲委派法则,不要等闲包围 loadClass 要领。不然也许会导致自界说加载器无法加载内置的焦点类库。在行使自界说加载器时,要明晰好它的父加载器是谁,将父加载器通过子类的结构器传入。假如父类加载器是 null,那就暗示父加载器是「根加载器」。

  1. // ClassLoader 结构器 
  2. protected ClassLoader(String name, ClassLoader parent); 

双亲委派法则也许会酿成三亲委派,四亲委派,取决于你行使的父加载器是谁,它会一向递归委派到根加载器。

Class.forName vs ClassLoader.loadClass

这两个要领都可以用来加载方针类,它们之间有一个小小的区别,那就是 Class.forName() 要领可以获取原生范例的 Class,而 ClassLoader.loadClass() 则会报错。

  1. Class<?> x = Class.forName("[I"); 
  2. System.out.println(x); 
  3. x = ClassLoader.getSystemClassLoader().loadClass("[I"); 
  4. System.out.println(x); 
  5. --------------------- 
  6. class [I 
  7. Exception in thread "main" java.lang.ClassNotFoundException: [I 
  8. ... 

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读