ClassLoader工作机制

本文摘自《深入分析Java Web技术内幕》
ClassLoader:类加载器
作用:1.负责将Class加载到JVM中
2.审查每个类由谁加载,是一种父优先的等级加载机制
3.将Class字节码重新解析成JVM统一要求的对象格式
ClassLoader类结构分析

 defineClass(byte[],int ,int)
 findClass(string)**
 loadClass(String)**
 resolveClass(Class<?>)

defineClass将byte字节流解析成JVM能够识别的Class对象,有了这个方法不仅可以通过class文件实例化对象,还可以通过其他方式实例化对象,如通过网络接收到一个类的字节码,拿这个字节码流直接创建类的Class对象形式实例化对象。注意,如果直接调用这个方法生成类的Class对象,这个类的Class对象还没有resolve,这个resolve将会在这个对象真正实例化时才进行
defineClass通常和findClass方法一起使用,通过直接覆盖ClassLoader父类的findClass方法来实现类的加载规则,从而取得要加载类的字节码,然后调用defineClass方法生成类的Class对象,如果想在类被加载到JVM中时就被Link,那么可以接着调用另外一个resolveClass方法,也可以选择让JVM来解决什么时候才连接这个类
如果不想重新定义加载类的规则,也没有复杂的处理逻辑,只想在运行时能够加载自己指定的一个类,可以用this,getClass().getClassLoader().loadClass(“class”)调用ClassLoader的loadClass方法以获取这个类的Class对象,这个loadClass还有重载方法,你同样可以决定在什么时候解析这个类
ClassLoader是个抽象类,它还有很多子类,如果要实现自己的ClassLoader,一般都会继承URLClassLoader这个子类,因为这个类已经帮我们实现了大部分工作


ClassLoader的等级加载机制——上级委托机制
任何一个会员到达一个会员接待室,先检查这个会员是否已经被自己接待过,没如果接待过,则拒绝本次接待;如果没有,向上询问这个会员是否应该在上一级的更高级别的接待室接待,上级接待室会根据他们的接待规则,检查这个会员是否已经被接待过,拒绝并将已经接待的结果反馈给下一级;如果没有接待过,再向上一级发送借贷请求,直到有以及接待室接待或者告诉下一级这个会员不是自己接待的这个结果;如果这个会员来到的这个接待室得到上一级的接待室反馈认为这个会员没有被接待,并且不应该由它们接待,这个接待室就会正式接待这个会员,并发给他入会证明,这个会员就被定义为这个接待室等级的会员

- BootStrap ClassLoader:这个ClassLoader就是接待室服务自身的,主要加载JVM自身工作需要的类,这个ClassLoader完全由JVM自己控制,别人访问不到这个类,不遵守前面的加载规则,仅仅是一个类的加载工具,既没有更高一级的父加载器,也没有子加载器
2.ExtClassLoader:是JVM自身的一部分,但是他的血统不是很纯正,并不是JVM亲自实现的,可以理解为这个类加载器是那些与这个大会合作但会的员工会员,这些会员既不是JVM内部的,也和普通的外部会员不同,所以就由这个类加载器来加载。他服务的特定目标在System.getProperty(“java.ext.dirs”)目录下
- AppClassLoader 这个类加载器就是专门为接待会员服务的,父类是ExtClassLoader,服务目标是广大普通会员,所有在System.getProperty(“java.class.path”)目录下的类都可以被这个类加载器加载,这个目录就是classpath
如果我们需要实现自己的类加载器,不管是直接实现抽象类classLoader,还是继承URLClassLoader,它的父加载器都是AppClassLoader,因为不管调用哪个父类构造器,创建的对象都必须最终调用getSystemClassLoader()作为父加载器,getSystemClassLoader()方法会去到的是AppClassLoader
JVM加载class文件到内存有两种方式
- 隐式加载:不通过在代码里调用ClassLoader来加载需要的类,而是通过JVM来自动加载需要的类到内存的方式。例如,我们在类中继承或者引用某个类时,JVM在解析当前这个类时发现引用的类不在内存中,那么久会自动将这些类加载到内存中
- 显示加载:在代码中调用ClassLoader类来加载一个类的方式。例如调用this.getClass.getClassLoader().loadClass()或者Class.forName,或者我们自己实现的ClassLoader的findClass()方法等


常见加载类错误分析:

  • ClassNotFoundException:原因:当JVM要加载指定文件的字节码到内存时,并没有找到这个文件对应的字节码,也就只是这个文件并不存在。
    解决办法:检查当前的classpath目录下有没有指定的文件存在,如果不知道当前的classpath路径,可以通过以下命令来获取
    this.getClass().getClassLoader().getResource(" ").toString()
  • NoClassDefFoundError:原因:使用New关键字、属性引用某个类,继承了某个接口或类,以及方法的某个参数中引用了某各类,这时会触发JVM隐式加载这些类时发现这些类不存在的异常
    解决办法:确保每个类引用的类都在当前的classpath下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值