描述:以下是類熱替換的核心代碼。程序直觀明瞭,如有錯誤請大家提出,本人及時改正,謝謝!
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文件即可看到效果。