美文网首页
二十一、Class.forName vs ClassLoader

二十一、Class.forName vs ClassLoader

作者: 此间有道 | 来源:发表于2020-08-12 21:53 被阅读0次
零、关键方法
  1. Class.forName(String className, boolean initialize, ClassLoader loader)
    1)initialize:是否执行类初始化操作,即是否执行<cinit>方法。
  2. Class.forName(String className)
    1)等价于:Class.forName(String className, true, currentLoader)
    2)currentLoader为真正加载当前类的classLoader(最后被委托的类加载器,执行defineClass方法的类加载器实例),非线程上下文的ClassLoader;
  3. ClassLoader.load(String className, boolean resolve)
    1)resolve:是否解析类,即是否解析符号为直接地址;
  4. ClassLoader.load(String className)
    1)等价:ClassLoader.load(String className, false)
一、 关联点

Class.forName最终也是调用ClassLoader去加载类的。

二、区别

1. 是否执行类初始化操作

1)Class.forName可以控制是否执行类初始化操作;
2)ClassLoader不会触发类初始化操作;

案例:数据库驱动需要使用Class.forName来触发静态库注册驱动;

2. 是否会解析数组类型

1)Class.forName会解析数组类型,如[Ljava.lang.String;
2)ClassLoader不会解析数组类型,加载时会抛出ClassNotFoundException;

3. 是否有缓存

1)类是缓存真正加载类的ClassLoader里的,此时需要避免委托给应用类加载器,而使用自定义类加载器去加载类
考虑打破双亲委派或指定AppClassLoader不可见路径;
2)只要指定每次加载类的ClassLoader即可实现热加载;

public class HotLoadClassTest {
    private final File path = new File("/Users/kivi/Documents");

    @Test
    public void testClassForName() throws Throwable {
        Class aClass = Class.forName("MyString", true, new MyClassLoader(new URL[]{path.toURL()}));
        aClass.getDeclaredMethod("echo").invoke(null);

        /** 替换MyString实现,可加载最近类 **/
        aClass = Class.forName("MyString", true, new MyClassLoader(new URL[]{path.toURL()}));
        aClass.getDeclaredMethod("echo").invoke(null);
    }

    @Test
    public void testClassLoader() throws Throwable {
        Class<?> aClass = new MyClassLoader(new URL[]{path.toURL()}).loadClass("MyString");
        aClass.getDeclaredMethod("echo").invoke(null);

        /** 替换MyString实现,可加载最近类 **/
        aClass = new MyClassLoader(new URL[]{path.toURL()}).loadClass("MyString");
        aClass.getDeclaredMethod("echo").invoke(null);
    }

    public static class MyClassLoader extends URLClassLoader {
        public MyClassLoader(URL[] urls) {
            super(urls);
        }
}

public class MyString {
    private static int invokeTime = 0;

    static {
        System.out.println("here is MyString static block");
    }

    public static void echo() {
        System.out.println("第" + (invokeTime++) + "次被调用");
    }
}

相关文章

网友评论

      本文标题:二十一、Class.forName vs ClassLoader

      本文链接:https://www.haomeiwen.com/subject/asomdktx.html