转载

Class.forName & ClassLoader.loadClass 比较

类的生命周期,分为 加载,连接(验证,准备,解析),初始化,使用,卸载 这几个过程。

Class.forNameClassLoader.loadClass 都会执行 加载 过程,将指定的类加载到内存中供使用。

但加载后,在默认情况下: Class.forName初始化ClassLoader.loadClass 在加载后什么都不会做。

2 Class.forName

java.lang.Class 中有两个 forName 方法,参数不同,都是调用了private方法 forName0

private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class<?> caller) throws ClassNotFoundException;

参数:

  • name :类的全名
  • initialize :是否初始化
  • loader :使用的类加载器
  • caller :调用者的类

返回:使用loader加载的全名为name的类

forName(String className)
forName(String name, boolean initialize, ClassLoader loader)

2.1 仅指定className

public static Class<?> forName(String className)
                throws ClassNotFoundException {
        // 获取调用者的类
        Class<?> caller = Reflection.getCallerClass();
        // 使用调用者的调用者的ClassLoader加载,加载后对类进行初始化。
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
复制代码

2.2 同时指定ClassLoader

public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        Class<?> caller = null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
             //有SecurityManager时,才需要获取调用者的类。
            caller = Reflection.getCallerClass();
            if (sun.misc.VM.isSystemDomainLoader(loader)) {
                ClassLoader ccl = ClassLoader.getClassLoader(caller);
                if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                    sm.checkPermission(
                        SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
        }
        // 指定类全名,是否初始化,ClassLoader,调用者的类 调用forName0
        return forName0(name, initialize, loader, caller);
    }
复制代码

3 ClassLoader.loadClass

参数:

  • name :类的全名
  • resolve :加载后时候进行生命周期中的连接部分

返回:使用当前ClassLoader加载的全名为name的类

过程:

findLoadedClass(name)
parent.loadClass(name, false)
findBootstrapClassOrNull(name)
java.net.URLClassLoader
resolve
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 检查类是否已经加载
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 双亲委派,优先从parent中执行loadClass,但执行时,不进行连接。
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    // name是否在Bootstrap Classloader中加载过,是的话则返回该类。
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    
                    // 执行findClass查找类,findClass由ClassLoader的子类实现。
                    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中还有一个不带resolve的loadClass方法,在类加载完后不执行连接:

public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
复制代码

4 总结

Class.forName和ClassLoader.loadClass都会执行加载过程。不同的是,在类 加载 后:

  • Class.forName :默认执行 初始化 ,但可以指定;
  • ClassLoader.loadClass :默认不做任何事( 不连接,不初始化 ),但可以指定是否 连接
原文  https://juejin.im/post/5df9c059f265da33c4281279
正文到此结束
Loading...