基于java语言的开发,可以使用其反射机制:在程序运行时,加载编译时并不确定的类,使用这些类的成员和方法。
反射的作用:解决合作开发时,自身编程不受合作方的进度、变更影响,实现自身代码编译。
反射的工作原理:当一个类被加载以后,Java虚拟机就会自动产生一个Class对象;通过加载所需的类到虚拟机,
进而获取虚拟机产生的Class对象;最后使用这个Class对象对应的构造方法、成员、方法等声明和定义的信息。
基于JVM虚拟机的动态加载器ClassLoader的使用:
//定义一个测试类,用来被反射调用
package com.grandshow;
public class Test {
private String str;
public Test(String s) {
this.str = s;
}
public void show() {
System.out.println(str);
}
}
package com.grandshow;
import java.lang.reflect.Constructor;
public class Client {
public static void main(String[] s) {
try {
//获取动态加载器ClassLoader,加载Class到虚拟机,返回一个Class对象clazz
Class clazz = ClassLoader.getSystemClassLoader().loadClass(
"com.grandshow.Test");
//通过clazz 获取构造方法并生成对象
Constructor constructor = clazz.getConstructor(String.class);
Object obj = constructor.newInstance("GrandShow");
//通过clazz 获取成员方法并执行
Method method = clazz.getMethod("show", null);
method.invoke(obj, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
基于DVM虚拟机的Android,则使用dalvik.system.DexClassLoader 和 dalvik.system.PathClassLoader类加载器。主要区别在于 PathClassLoader 只能直接操作 dex 文件或者已经安装过的 apk;而 DexClassLoader 则可以
加载外部的 apk、jar 或 dex文件,并会在指定的 outpath 路径存放其 dex 文件。
DexClassLoader:
//获取目标类的包名
String packageName = activityInfo.packageName;
//获取目标类所在的apk或者jar存放的路径
String dexPath = activityInfo.applicationInfo.sourceDir;
//获取目标类dex文件存放在调用者里的路径
String dexOutputDir = getApplicationInfo().dataDir;
//获取目标类所使用的C/C++库存放路径
String nativeLibraryDir = activityInfo.applicationInfo.nativeLibraryDir;
//获取类装载器
ClassLoader classLoader = getClassLoader();
DexClassLoader dcl = new DexClassLoader(dexPath,dexOutputDir,nativeLibraryDir,classLoader);
try {
//装载目标类
Class<?> clazz = dcl.loadClass(packageName + ".Test");
//获取构造器并实例化对象
Constructor<?> constructor = clazz.getConstructor();
Object o = constructor.newInstance();
//获取成员方法
Method display = clazz.getMethod("show", String.class);
display.invoke(o, "grandShow");
} catch (Exception e) {
e.printStackTrace();
}
PathClassLoader :
// 获取apk或者jar的路径
String apkPath = actInfo.applicationInfo.sourceDir;
// 获取lib库代码的目录
String libPath = actInfo.applicationInfo.nativeLibraryDir;
PathClassLoader pcl = new PathClassLoader(apkPath, libPath,
this.getClassLoader());
// 加载类
try {
Class clazz = pcl.loadClass("com.grandshow.Test");
Method method = clazz.getMethod("show",String.class);
method.invoke(clazz.newInstance(), "grandShow");
} catch (Exception e) {
e.printStackTrace();
}