描述:以下是类热替换的核心代码。程序直观明了,如有错误请大家提出,本人及时改正,谢谢!
ClassLoader重要类说明:
findLoadedClass:每个类加载器都维护有自己的一份已加载类名字空间,其中不能出现两个同名的类。凡是通过该类加载器加载的类,无论是直接的还是间接的,都保存在自己的名字空间中,该方法就是在该名字空间中寻找指定的类是否已存在,如果存在就返回给类的引用,否则就返回 null。这里的直接是指,存在于该类加载器的加载路径上并由该加载器完成加载,间接是指,由该类加载器把类的加载工作委托给其他类加载器完成类的实际加载。
getSystemClassLoader:Java2 中新增的方法。该方法返回系统使用的 ClassLoader。可以在自己定制的类加载器中通过该方法把一部分工作转交给系统类加载器去处理。
defineClass:该方法是 ClassLoader 中非常重要的一个方法,它接收以字节数组表示的类字节码,并把它转换成 Class 实例,该方法转换一个类的同时,会先要求装载该类的父类以及实现的接口类。
loadClass:加载类的入口方法,调用该方法完成类的显式加载。通过对该方法的重新实现,我们可以完全控制和管理类的加载过程。
resolveClass:链接一个指定的类。这是一个在某些情况下确保类可用的必要方法,详见 Java 语言规范中“执行”一章对该方法的描述。
以下为实现代码:
主程序
public class MainActivity {
public static void main(String[] args) throws ClassNotFoundException, InterruptedException {
Thread thread = new Thread(new Runnable() {
public void run() {
for(;;) {
CustomCL loader = new CustomCL(System.getProperty("user.dir") + "/bin/", new String[]{"Worker"});
try {
Object inst = loader.loadClass("Worker").newInstance();
Method method = inst.getClass().getMethod("doIt", new Class[] {});
method.invoke(inst, new Object[] {});
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
thread.join();
}
}
自定义类加载器
public class CustomCL extends ClassLoader {
private String path;
private Set<String> clazzs;
public CustomCL(String path, String[] clazzs) {
super(null); // 不使用父类实现
this.clazzs = new HashSet<String>(Arrays.asList(clazzs));
this.path = path;
onBoot(clazzs);
}
private void onBoot(String[] clazzs) {
for (String name : clazzs) {
defClass(name);
}
}
private Class<?> defClass(String name) {
String diskUrl = path + name.replace('.', File.separatorChar) + ".class";
Class<?> clazz = null;
try {
File clazzF = new File(diskUrl);
FileInputStream stream = new FileInputStream(clazzF);
int len = (int) clazzF.length();
byte[] b = new byte[len];
stream.read(b);
stream.close();
int off = 0;
clazz = defineClass(name, b, off, b.length);
} catch (IOException e) {
e.printStackTrace();
}
return clazz;
}
/**
* 读取类
*/
@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(name);
if (!this.clazzs.contains(name) && clazz == null) {
clazz = getSystemClassLoader().loadClass(name);
}
if (clazz == null) {
throw new ClassNotFoundException(name);
}
if (resolve == true) {
resolveClass(clazz);
}
return clazz;
}
/**
* 加载类
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//一些外部类的加载可以重写这个方法,此处略。
return super.findClass(name);
}
}
待替换的类
public class Worker {
public void doIt() {
System.out.println("This is === old === do it!");
}
}
运行此程序替换各种版本的worker.class文件即可看到效果。