打算研究一下Android的代码动态加载,先看一下Java是怎么实现的- - 虽然Java SE的一些奇技淫巧一般不能用在Android上……
利用java.net.URLClassLoader加载特定的jar文件,并通过loadClass方法获取Class,或用Class.forName获取Class。
获取Class的引用之后,可以用newInstance创建该类的实例,通过反射调用该类中定义的方法。若该类实现了某个接口,可先将新建的对象强制转换为该接口的实例,然后调用接口中的方法。(若采用后一种方式,需注意被动态加载的代码中的接口定义与调用处的接口定义须兼容。包名和接口名必须一致,被调用处的接口定义中须包含调用处接口定义的所有方法,但被调用处的接口定义可以有多余的东西)
新建一个java project,新建一个package名为com.dynamic
新建TestClass类,这个类将会被动态加载:
package com.dynamic;
public class TestClass implements TestInterface {
@Override
public void testMethod(String str) {
System.out.println("test [" + str + "]");
}
}
package com.dynamic;
public interface TestInterface {
public void testMethod(String str);
}
之后将这个工程的代码导出为jar文件。
在另一个project里的测试代码:
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import com.dynamic.TestInterface;
public class Main {
public static void main(String[] args) {
try {
File jarFile = new File("1.jar");
URLClassLoader loader = (URLClassLoader) ClassLoader.getSystemClassLoader();
//反射调用addURL方法
Method _addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
_addURL.setAccessible(true);
_addURL.invoke(loader, jarFile.toURI().toURL());
//尝试加载类并用反射调用其中的方法
Class<?> cls = loader.loadClass("com.dynamic.TestClass");
Method m = cls.getMethod("testMethod", String.class);
Object obj = cls.newInstance();
m.invoke(obj, "hello world");
//强制转换为接口的实例
Class<?> cls1 = Class.forName("com.dynamic.TestClass");
TestInterface i1 = (TestInterface) cls1.newInstance();
i1.testMethod("interface");
loader.close();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}