DexClassLoader简介

DexClassLoader简介


     了解ClassLoader,首先就要知道ClassLoader是用来干什么的,顾名思义,它就是用来加载Class文件到JVM,以供程序使用的。我们知道,java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的,所以可想而知ClassLoader的重要性如何。 

ClassLoader的分类和基本的加载流程:

 bootstrap classloader:

既然ClassLoader是用来加载类到JVM中的,那么ClassLoader又是如何被加载呢?难道它不是java的类? 没有错,在这里确实有一个ClassLoader不是用java语言所编写的,而是JVM实现的一部分,这个ClassLoader就是bootstrap classloader(启动类加载器),这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,核心API里面也包括了以下两种用java实现的ClassLoader

ExtClassLoader:

一个Classloader就是ExtClassLoader。这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类。

AppClassLoader:

另一个是AppClassLoader,这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载。 

     当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。 

ClassLoader的双亲委托加载模式:

先给出一段使用classloader的一段代码:

@SuppressLint("NewApi")  
    public void test() {  
        // dex下载的位置--可以是内部存储或外部存储位置  
        File dexInputFile = new File(Environment.getExternalStorageDirectory().toString() + File.separator  
                + "elvis_plugin_dex_sayhello.jar");  
        String dexInputFileDir = dexInputFile.getAbsolutePath();  
        // dex输出位置--只能是内部存储位置  
        String dexOutputFileDir = getFilesDir().getAbsolutePath();  
        // dexClassLoader对象  
        DexClassLoader dexClassLoader = new DexClassLoader(dexInputFileDir, dexOutputFileDir, null,  
                this.getClass().getClassLoader());  
        // 利用反射调用插件包内的类的方法  
        try {  
            Class<?> clazz = dexClassLoader.loadClass("com.elvis.plugin.sayhello.SayHello");  
            Object obj = clazz.newInstance();  
            // //设置参数格式  
            // Class[] param = new Class[2];  
            // param[0] = Integer.TYPE;  
            // param[1] = Integer.TYPE;  
            Method method = clazz.getMethod("say");  
            // method.invoke(obj,1,12);  
            method.invoke(obj);  
        } catch (ClassNotFoundException e) {  
            Log.e("elvis", "ClassNotFoundException");  
            e.printStackTrace();  
        } catch (InstantiationException e) {  
            Log.e("elvis", "InstantiationException");  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            Log.e("elvis", "IllegalAccessException");  
            e.printStackTrace();  
        } catch (NoSuchMethodException e) {  
            Log.e("elvis", "NoSuchMethodException");  
            e.printStackTrace();  
        } catch (IllegalArgumentException e) {  
            Log.e("elvis", "IllegalArgumentException");  
            e.printStackTrace();  
        } catch (InvocationTargetException e) {  
            Log.e("elvis", "InvocationTargetException");  
            e.printStackTrace();  
        }  
    }  

我们可以发现classloader的关键两条API是:

DexClassLoader dexClassLoader = new DexClassLoader(dexInputFileDir, dexOutputFileDir, null,this.getClass().getClassLoader());

Class<?> clazz = dexClassLoader.loadClass("com.elvis.plugin.sayhello.SayHello");

首先,每个ClassLoader都会有一个parent ClassLoader,当实例化子classLoader时必须传入parent ClassLoader,若null,那么就默认该ClassLoader的parent是bootstrap classloader。

双亲委托模式:

在任何一个自定义ClassLoader加载一个类之前,它都会先委托它的父亲ClassLoader进行加载,只有当父亲ClassLoader无法加载成功后,才会由自己加载

这里给出了loadclass函数源码API:(这里就可以详细看到关于双亲委托模式的实现)

    /**
     * Loads the class with the specified name, optionally linking it after
     * loading. The following steps are performed:
     * <ol>
     * <li> Call {@link #findLoadedClass(String)} to determine if the requested
     * class has already been loaded.</li>
     * <li>If the class has not yet been loaded: Invoke this method on the
     * parent class loader.</li>
     * <li>If the class has still not been loaded: Call
     * {@link #findClass(String)} to find the class.</li>
     * </ol>
     * <p>
     * <strong>Note:</strong> In the Android reference implementation, the
     * {@code resolve} parameter is ignored; classes are never linked.
     * </p>
     *
     * @return the {@code Class} object.
     * @param className
     *            the name of the class to look for.
     * @param resolve
     *            Indicates if the class should be resolved after loading. This
     *            parameter is ignored on the Android reference implementation;
     *            classes are not resolved.
     * @throws ClassNotFoundException
     *             if the class can not be found.
     */
    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = findLoadedClass(className);

        if (clazz == null) {
            ClassNotFoundException suppressed = null;
            try {
                clazz = parent.loadClass(className, false);
            } catch (ClassNotFoundException e) {
                suppressed = e;
            }

            if (clazz == null) {
                try {
                    clazz = findClass(className);
                } catch (ClassNotFoundException e) {
                    e.addSuppressed(suppressed);
                    throw e;
                }
            }
        }

        return clazz;
    }


DexClassLoader的使用:

请见我的博文:http://blog.csdn.net/qq979418391/article/details/50578607


DexClassLoader的深入解读:

关于Class.forName方法与loadClass方法的区别:http://www.iteye.com/topic/83978






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值