前言:

Android中的动态加载机制能更好的优化我们的应用,同时实现动态的更新,这就便于我们管理我们的应用,通过插件化来减轻我们的内存以及CPU消耗,在不发布新版本的情况下能更新某些模块。 当然这里要说的并不是android中的动态加载机制,而是java中的ClassLoader动态加载我们的class,虽然android是基于Dalvik,但是先了解java中JVM怎么来加载我们的class的对于我们以后了解Android中的动态加载机制会有很大的帮助。 于是乎在网上查阅了很多关于类加载的文章了解JVM是如何通过ClassLoader来加载我们的class的。

JVM中的ClassLoadr:

java为我们提供了3个不同的ClassLoadr,分别是: 1.BootstrapClassLoader---主要负责加载java中的核心类库。是用C++代码实现的,在java虚拟机启动后初始化。 2.ExtensionClassLoader---主要负责加载java中的扩展类库。 3.AppClassLoader---用于java我们应用下的classpath中的class以及我们的jar。
JVM通过这些ClassLoadr把我们的class转换成字节码文件存贮到内存中,然后创建一个Class用特定的数据结构来封装他们,接着我们就能通过这个Class来访问其中的方法以及变量了。(这不就是我们的反射机制么,通过Class对象来获取其中的方法或者变量),当然JVM还有个验证的过程,只有通过javac编译来的class才能被ClassLoader所加载。 而ClassLoader是通过双亲委托模式来加载我们的class,就是先通过父类的ClassLoader来加载我们的class,如果父类加载失败,则通过我们的子ClassLoader来加载我们的class。(这里的父类与子类并不是集成关系) 我们可以通过URLClassLoader来动态加载我们的class也可以通过继承ClassLoader来实现我们的动态加载。而我们的ExtensionClassLoader与AppClassLoader都是继承自URLClassLoader。我这里是通过继承一个ClassLoader来实现的,通过获取Class的字节码文件来生成我们的Class,然后通过反射机制来调用我们类中的方法。 ClassLoader的扩展方法介绍: loadClass 通过指定的二进制名来加载类(这里要把我们的包路径传过去,例如"com.ljx.test.Test") defineClass 将byte数据转换成我们的Class类的实例 findloadClass 如果某个类加载器已经加载过这个class,则返回该类 .....还有很多这里就不一一例举了。

Test.java 先来创建需要加载的class,路径是F:Test.java,然后通过javac来生成我们的Test.class

Java中的ClassLoader 动态加载机制_第1张图片
这就是我们的Test的代码

MyClassLoader.java 通过继承ClassLoader来创建我们自己的ClassLoader,来加载Test.class

public class MyClassLoader extends ClassLoader {private byte[] results;public MyClassLoader(String pathName) {//拿到class转成的字节码文件results = loadClassFile(pathName);}public static void main(String[] args) {//初始化我们的classloader,同时拿到class所转成的字节码文件MyClassLoader classLoader = new MyClassLoader("F:\\Test.class");try {//这里要把包路径传入进去Class<?> clazz = classLoader.loadClass("com.ljx.yyy.Test");Object o = clazz.newInstance();//通过反射机制调用我们的Test.java中的printToString方法Method method = clazz.getMethod("printToString");method.invoke(clazz.newInstance());System.out.println(o.getClass().getClassLoader().toString());Method[] methods = clazz.getMethods();for (int i = 0; i < methods.length; i++) {//获取类中的方法名字String methodName = methods[i].getName();System.out.println("MethodName : " + methodName);Class<?>[] params = methods[i].getParameterTypes();for (int j = 0; j < params.length; j++) {//获取方法中的参数类型System.out.println("ParamsType : " + params[j].toString());}}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//把我们的class文件转成字节码,用于classloader动态加载private byte[] loadClassFile(String classPath) {ByteArrayOutputStream bos = new ByteArrayOutputStream();try {FileInputStream fi = new FileInputStream(classPath);BufferedInputStream bis = new BufferedInputStream(fi);byte[] data = new byte[1024 * 256];int ch = 0;while ((ch = bis.read(data, 0, data.length)) != -1) {bos.write(data, 0, ch);}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return bos.toByteArray();}@Overrideprotected Class<?> loadClass(String arg0, boolean arg1)throws ClassNotFoundException {Class<?> clazz = findLoadedClass(arg0);if (clazz == null) {if (getParent() != null) {try {//这里我们要用父加载器加载如果加载不成功会抛异常clazz = getParent().loadClass(arg0);} catch (Exception e) {//我们自定义的类加载器的父类 [email protected]System.out.println("getParent : " + getParent());//父类的父类 [email protected]System.out.println("getParent.getparent : " + getParent().getParent());//父类的父类的父类 为null 也就是我们的Bootstrap ClassLoader 因为它是JVM生成的由C++实现;//所以拿到的是空System.out.println("getParent.getparent.getparent : " + getParent().getParent().getParent());System.out.println("父类ClassLoader加载失败!");}}if (clazz == null) {clazz = defineClass(arg0, results, 0, results.length);}}return clazz;}}
先是获取我们在F:Test.class的字节码,然后通过它来得到我们的class,然后我们就能通过这个class来使用Test这个类中的方法,以下是执行main方法之后的结果: Java中的ClassLoader 动态加载机制_第2张图片

这样,基本上就实现了从本地加载一个class到我们的项目中,是不是感觉很神奇,通过这种方式我们就能动态的加载不在我们项目中的类,例如从网上获取class的byte来动态更新我们的功能模块,或者动态加载jar中的class来实现我们要实现的功能。 代码中很大一部分是参照了网上的一些例子,当然最主要的还是为了要阐述如何通过ClassLoader来动态加载我们需要加载的类,通过ClassLoader来更好的优化我们的应用。了解了JVM如何来加载class能更好的便于我们理解Android中的动态加载技术;由于技术有限,如果上述有不正确的地方希望见谅。

更多相关文章

  1. Android X86强制竖屏怎么办?安卓(Android)x86屏幕旋转成横屏解决
  2. android客户端和网站数据交互的实现(基于Http协议获取数据方法)
  3. Android运行时ART加载OAT文件的过程分析
  4. Andoid自动判断输入是电话,网址或者Email的方法----Linkify的应
  5. 浅析Android字体加载原理
  6. Android开发人员看过来:这些Kotlin化方法帮你提高开发技能
  7. Android 在onCreate()方法中获取控件宽高值为0解决方案
  8. Android录制屏幕的实现方法
  9. Android简单修改原有应用和添加应用的方法

随机推荐

  1. TP 商品详情页数据、加入购物车、登录、t
  2. C++算法学习之回溯法的应用
  3. 从零开始打造流程图、拓扑图项目【Nuxt.j
  4. python单向循环链表实例详解
  5. C++超详细讲解树与二叉树
  6. C++算法学习之分支限界法的应用
  7. VSCode配置PHP函数跳转
  8. TextView添加Onclick点击无效没反应解决
  9. android 长按菜单的使用
  10. 『ANDROID』反射取子类、父类 属性