Java面试中经常会问到Java类加载机制是什么样的,今天我们就从Java类加载器和类加载过程两方面来介绍一下,首先来说一下类的加载过程。
Java面试题中经常会问类的加载过程是什么样的,或者是通过给你一个程序,回答出程序的输出结果是什么,这些知识点都是Java类加载过程相关的,下面就来详细的说一说类加载的7个过程。
加载
将class文件加载到内存中,并在方法区创建对应的class对象
验证
校验加载的class文件是否符合字节码规范
准备
解析
JVM 针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符 7 类引用进行解析。这个阶段的主要任务是将其在常量池中的符号引用替换成直接其在内存中的直接引用。
初始化
到了初始化阶段,用户定义的 Java 程序代码才真正开始执行。在这个阶段,JVM 会根据语句执行顺序对类对象进行初始化,一般来说当 JVM 遇到下面 5 种情况的时候会触发初始化:
使用
当 JVM 完成初始化阶段之后,JVM 便开始从入口方法开始执行用户的程序代码。
卸载
当用户程序代码执行完毕后,JVM 便开始销毁创建的 Class 对象,最后负责运行的 JVM 也退出内存。
从上面几个例子可以看出,分析一个类的执行顺序大概可以按照如下步骤:
如果在初始化 main 方法所在类的时候遇到了其他类的初始化,那么就先加载对应的类,加载完成之后返回。如此反复循环,最终返回 main 方法所在类。
启动类加载器:Bootstrap ClassLoader,它用来加载Java的核心库,主要是<JAVA_HOME>/lib下的类。该加载器无法被Java程序直接引用。
扩展类加载器:ExtClassLoader,它用来加载Java的扩展类,主要是<JAVA_HOME>/lib/ext下的类。
应用类加载器:AppClassLoader,它负责加载用户类路径所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义自己的类加载器,那么这个就是程序中默认的类加载器。
提到类加载器,双亲委派模型是必然会提到的。双亲委派模型是指当我们调用类加载器的loadClass方法进行类加载时,该类加载器会首先请求它的父类加载器进行加载,依次递归。如果所有父类加载器都加载失败,则当前类加载器自己进行加载操作。这样做可以保证Java核心类的安全,比如说你不能够去覆盖java.lang.String类。
下面从loadClass的源码来看一下双亲委派模型是如何实现的
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先检查这个类是不是已经被加载了 Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { // 找当前类加载器的父类去加载 if (parent != null) { c = parent.loadClass(name, false); } else { //根类加载器没有父类了,所以由根类加载器加载 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { long t1 = System.nanoTime(); //如果父类加载器加载失败,再由当前类加载器加载 c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } } 复制代码
如果自定义类加载器不破坏双亲委派模型,只需要继承ClassLoader类并重写findClass方法即可。
如果自定义类加载器要破坏双亲委派模型,需要继承ClassLoader类并重写loadClass方法和findClass方法。
谈到破坏双亲委派模型,可能会被问到你知道有哪些打破双亲委派模型的例子吗,如何打破的?