类加载---双亲委派机制

类加载---双亲委派机制

双亲委派机制指的是,当类加载器收到类加载的请求时候会首先调用父类(ClassLoader)的findLoadedClass方法,判断类是否加载过,如果已经加载过则直接返回,否则会将加载任务委托给成员变量parent,并不是指的父类。parent加载器在收到类加载请求后,也会先判断需要加载的类是否已经加载过,如果加载过则结束,否则也会将加载任务委托给成员变量parent去进行类加载。这里是一个循环过程,直到将家加载任务委托给Bootstrap ClassLoader 结束,如果Bootstrap ClassLoader也没有找到则交给各个子类自己加载,一直到最后,如果没有任何类加载器能加载则会抛出ClassNotFoundException。

ClassLoader

通过代码我们可以比较明确的了解到双亲委派的加载机制。

 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // 首先判断需要加载的类是否已经被加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    // 如果parent 不为空则委托parent进行加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                     // parent 也没有找到则委托BootstrapClassLoader进行加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // 如果以上都没有找到在此处抛出异常;
                }
                
                if (c == null) {
                    //如果依旧没有找到则调用自己的findClass继续查找
                    c = findClass(name);
                }
            }
            //最终return 找到的结果
            return c;
    }

 Android中的ClassLoader

 接下来我们通过一个简单例子来看下android中各个类的加载都是由哪个类加载器进行加载的。

System.out.println(Activity.class.getClassLoader());
System.out.println(LoadUtils.class.getClassLoader());//自己写的任意类
System.out.println(String.class.getClassLoader());
System.out.println(LoadUtils.class.getClassLoader().getParent());
输出结果如下:
System.out: java.lang.BootClassLoader@7ed285f
System.out: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.plugin-2/base.apk", zip file "/sdcard/pluginapp-debug.apk"],nativeLibraryDirectories=[/data/app/com.example.plugin-2/lib/arm64, /system/lib64, /vendor/lib64]]]
System.out: java.lang.BootClassLoader@7ed285f
System.out: java.lang.BootClassLoader@7ed285f

可以看出String和Activity类是由BootClassLoader加载,而我们自己任意写的一个类则由

PathClassLoader进行加载。看到最后一条结果我们是否好奇为什么PathClassLoader的parent是BootClassLoader我们是在哪里给他赋值的呢,还有另外一个疑问为什么我们使用的是PathClassLoader加载Activity呢,这些都是从哪里来赋值的呢?

从ActivityThread的attach方法中一步步跟下来我们发现最终赋值调用的是ClassLoader中的createSystemClassLoader方法得到了上述打印结果的源头。

private static ClassLoader createSystemClassLoader() {
        String classPath = System.getProperty("java.class.path", ".");
        String librarySearchPath = System.getProperty("java.library.path", "");
        // TODO Make this a java.net.URLClassLoader once we have those?
        return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance());
    }

接下来我们使用PathClassLoader和DexClassLoader来分别加载类。

   String apkPath = "/sdcard/pluginapp-debug.apk";
        long time1 = System.currentTimeMillis();
        DexClassLoader dexClassLoader = new DexClassLoader(apkPath, getCacheDir().getAbsolutePath(),null, LoadUtils.class.getClassLoader());
        try {
            Class<?> aClass = dexClassLoader.loadClass("com.example.pluginapp.PluginApp");
            System.out.println(aClass.getName() + ", DexClassLoader cost time :" + (System.currentTimeMillis() - time1));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


        long time2 = System.currentTimeMillis();
        PathClassLoader pathClassLoader = new PathClassLoader(apkPath, dexClassLoader);
        try {
            Class<?> bClass = pathClassLoader.loadClass("com.example.pluginapp.PluginApp");
            System.out.println(bClass.getName() + ", PathClassLoader cost time :" + (System.currentTimeMillis() - time2));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

打印结果如下
System.out: com.example.pluginapp.PluginApp, DexClassLoader cost time :23
System.out: com.example.pluginapp.PluginApp, PathClassLoader cost time :293

从上图可以看出其实DexClassLoader 和PathClassLoader 都可以加载外部的apk,从我多次实验来看dexclassLoade的加载时间会稍微短一些,所以加载外部apk我个人推荐使用DexClassLoader 。

DexClassLoader构造方法中parent传入PathClassLoader 简易流程图:

好处

1 避免重复加载类。

2 防止文中String.class 或者 Activity.class核心类被篡改。

写在最后

好记性不如烂笔头,学习一个知识需要自己手动的去进行代码编写加深印象,不要因为简单而不去实践坚持把简单的事情做好,就是不简单!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值