类加载过程
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
加载时机:
并不是所有的类在程序启动时即被加载,为提升效率,虚拟机通常秉承的是按需加载的原则,即需要使用到相应的类时才加载对应的类。具体包括如下几个加载时机:
遇到new、getstatic、putstatic、invokestatic这4条指令时,如果对应的类没有被加载,虚拟机会首先加载对应的类。这4条指令对应的场景是:
创建一个实例对象
访问一个类的静态变量(注意:不包括被final修饰,在编译时已被放入常量池的变量)
执行一个类的静态方法
其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
类加载器
(1)Bootstrap ClassLoader:用于加载/lib路径下的类。主要加载JVM自身工作需要的类,完全由JVM自己控制,这个类不遵守双亲委派加载机制,它仅仅是一个类的加载工具,既没有父加载器也没有子加载器。
(2)ExtClassLoader:用于加载/lib/ext路径下的类。这个类本身是JVM自身的一部分,但不是由JVM自身实现的,服务的特定目标在java.ext.dirs目录下的类
(3)AppClassLoader:这个类服务java.class.path目录下的类,即classpath路径。
如果有需要,开发人员还可以加入自定义的类加载器。如果我们要实现自己的类加载器,不管是直接继承ClassLoader还是继承URLclassLoaderlei ,它的父加载器都是AppClassLoader,因为不管调用哪个父类构造器,创建的对象都必须最终调用getSystemClassLoader()作为父类加载器,而该方法获取的正是AppClassLoader。
如果应用中没有定义其他的类加载器,那么除了java.ext.dirs下的类是由ExtClassLoader来加载,其他的都是由AppClassLoader来加载。
既然存在如此多的类加载器,那么当一个类需要加载时,具体是由那个类进行加载呢?由于所有的类加载器都遵守“双亲委派模型”,所以虚拟机在运行期间可以保证一个类只会被加载一次。
双亲委派模型
双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,它会把这个请求交给自己的父类加载器去完成,父类加载器也会继续上自己的父类加载器发送请求,依次类推。如果父类已经加载过该类,则当前加载器会直接返回已加载的类,只有当父类没有加载过该类时,当前类加载器才会真正去加载该类。
本文暂时没有评论,来添加一个吧(●'◡'●)