1、类加载机制
JVM的类加载机制主要有以下三种
- 全盘负责。当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入。
- 父类委托。先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。
- 缓存机制。缓存机制保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换为Class对象,存入缓存区中。
2、类加载器加载Class大致经过如下步骤。
- (1)、先判断此类是否被载入过(即缓存区中是否有此Class),如果有则返回对应的java.lang.Class对象。否则判断父类加载器是否存在。(2)、如果父类加载器不存在(如果没有父类加载器,则要么parent一定是根类加载器,要么本省就是根类加载器),则请求使用根类加载器来载入目标类,如果成功则返回对应的java.lang.Class对象,失败则抛出ClassNotFoundException异常。(3)、如果父类加载器存在,则请求使用父类加载器去载入目标类,如果成功则返回对应的java.lang.Class对象,失败则使用当前类加载器尝试寻找Class文件(从与此ClassLoader相关的类路径中寻找),如果找到则从文件中载入class,成功则返回对应的java.lang.Class对象,如果找不到则抛出ClassNotFoundException.
流程图如下
ClassLoader类的loadClass方法源码如下。
/** * Loads the class with the specified <a href="#name">binary name</a>. The * default implementation of this method searches for classes in the * following order: * * <p><ol> * * <li><p> Invoke {@link #findLoadedClass(String)} to check if the class * has already been loaded. </p></li> * * <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method * on the parent class loader. If the parent is <tt>null</tt> the class * loader built-in to the virtual machine is used, instead. </p></li> * * <li><p> Invoke the {@link #findClass(String)} method to find the * class. </p></li> * * </ol> * * <p> If the class was found using the above steps, and the * <tt>resolve</tt> flag is true, this method will then invoke the {@link * #resolveClass(Class)} method on the resulting <tt>Class</tt> object. * * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link * #findClass(String)}, rather than this method. </p> * * <p> Unless overridden, this method synchronizes on the result of * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method * during the entire class loading process. * * @param name * The <a href="#name">binary name</a> of the class * * @param resolve * If <tt>true</tt> then resolve the class * * @return The resulting <tt>Class</tt> object * * @throws ClassNotFoundException * If the class could not be found */ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded缓存中是否存在此类 Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) {//父类加载器存在,使用父类加载器载入目标类 c = parent.loadClass(name, false); } else {//父类加载器不存在,则使用根类加载器载入目标类 c = findBootstrapClassOrNull(name);//此方法为native方法。 } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader // 加载失败则抛出ClassNotFoundException } if (c == null) {//父类加载器或根类加载器均未加载成功,则使用当前类加载器寻找Class文件,ClassLoader允许子类重写findClass方法 // If still not found, then invoke findClass in order // to find the class. 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; } }