目录

Android黑科技动态加载(一)之Java中的ClassLoader
Android黑科技动态加载(二)之Android中的ClassLoader
Android黑科技动态加载(三)之动态加载资源
Android黑科技动态加载(四)之插件化开发

项目地址

我们的认识

我们都知道, 刚写好的Java的源文件是以.java为扩展名的, 需要让JVM去解析的时候, 必须编译成Java字节码, 而Java字节码文件就是以.class为扩展名的. ClassLoader的对象就是去加载这些Java字节码文件

Java默认的ClassLoader

在Java默认环境中, 提供了三种Classloader

  • BootStrap ClassLoader : 启动类加载器,Java类加载器中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jarresources.jarcharsets.jar

  • Extension ClassLoader : 扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar

  • App ClassLoader : 系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

java_classloader.jpg

有兴趣的朋友可以通过Class.getClassLoader()去验证一下.

ClassLoader加载原理

加载顺序(双亲委托机制)

如果我们自定义一个ClassLoader叫做MyClassLoader, 当查找需要的类的时候, MyClassLoader会把该责任委托给它的父类加载器不是通过继承的父类, 是通过parent属性去持有. 整个过程从顶到下, 如果一个类找不到, 那么查找顺序是BootStrap ClassLoader->Extension ClassLoader->App ClassLoader->MyClassLoader->抛出异常ClassNotFoundException

两个类是否相等

一般我们认为两个类是否相等, 仅仅通过包名+类名去区分. 事实上还有一个条件, 就是加载该类的ClassLoader是否是同一个

两个关键方法

ClassLoader中认为比较关键的方法有三个:

  • public Class<?> loadClass(String name) : 根据双亲委托机制的方式查找class

  • protected Class<?> findClass(String name) : 根据该ClassLoader的方式去查找class

  • protected final Class<?> defineClass() : 该方法有多个重载, 具体参数不写了. 主要作用是把类加载到内存中

loadClass为一个模板方法, 有兴趣的话可以去看看源码. 所以一般我们只需要重写findClass即可.

上面三个方法有关系的, loadClass->findClass->defineClass. loadClass使用双亲委托机制去查找要加载的类, 当上层ClassLoader不能加载该类时, 就会去使用自己的findClass去加载类. 加载到的类(可能为空)会传入defineClass中, 如果为空则抛出异常.

自定义ClassLoader

我们下面自定义一个MyClassLoader去加载外部的RemoteClass.class文件

RemoteClass.class

package top.august1996.demo;public class RemoteClass {    public void catched() {        System.out.println("I am catched...");    }}

我们把上面文件移到任意目录(/Users/August/Desktop)

cd /Users/August/Desktopjavac RemoteClass.java

现在我们就在桌面上编译了一个字节码文件

MyClassLoader.java

package top.august1996.demo;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class MyClassLoader extends ClassLoader {    private String mClassPath; // Class存放的的目录    public MyClassLoader(String classPath) {        mClassPath = classPath;    }    @Override    protected Class<?> findClass(String name) {        File clsFile = new File(mClassPath, getClassName(name));        FileInputStream fis = null;        ByteArrayOutputStream baos = new ByteArrayOutputStream();        byte[] b = null;        try {            fis = new FileInputStream(clsFile);            int data = 0;            while ((data = fis.read()) != -1) {                baos.write(data);            }            b = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally {            if (fis != null) {                try {                    fis.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (baos != null) {                try {                    baos.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        // 上面是基本的数据流操作, 把Class文件转换成二进制流        return defineClass(name, b, 0, b.length);    }    /**     * 获取Class的完整文件名     *      * @param name     * @return     */    private String getClassName(String name) {        String clsName = null;        if (name != null) {            int lastIndexOf = name.lastIndexOf(".");            if (lastIndexOf == -1) {                clsName = name + ".class";            } else {                clsName = name.substring(lastIndexOf + 1) + ".class";            }        }        return clsName;    }}

TestDemo.java

package top.august1996.demo;import java.lang.reflect.Method;public class TestDemo {    public static void main(String[] args) throws Exception {        MyClassLoader classLoader = new MyClassLoader("/Users/August/Desktop");        Class<?> cls = classLoader.findClass("top.august1996.demo.RemoteClass");        Object object = cls.newInstance();        Method method = cls.getDeclaredMethod("catched", null);        method.invoke(object, null);    }}
I am catched...

我们使用反射区调用自己加载的RemoteClasscatched方法, 可以看到结果已经是成功的了.

更多相关文章

  1. Android(安卓)进阶 教你打造 Android(安卓)中的 IOC 框架 【View
  2. Android入门(1) 不一样的HelloWorld
  3. android绘图Paint.setXfermode()和Canvas.saveLayer()方法的作用
  4. 【Android(安卓)修炼手册】常用技术篇 -- 聊聊 Android(安卓)的
  5. Android消息机制
  6. 浅谈Java中Collections.sort对List排序的两种方法
  7. NPM 和webpack 的基础使用
  8. Python list sort方法的具体使用
  9. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程

随机推荐

  1. 智能手机软件平台 Android VS iPhone OS:
  2. android 实时获取wifi信号强度
  3. Android 下载图片的问题
  4. Android:自定义DialogFragment的内容和按
  5. Android SDK Tutorial: Button onClick E
  6. Android之设计模式
  7. Carrier Configuration in Android 6.0
  8. android jni 调用结构体示例
  9. Android简单实现猜拳游戏
  10. ObservableInt 无法使用