Dynamic Class Reloading در جاوا کمی پیچیده تر از Dynamic Class Loading است، بخاطر اینکه ClassLoader پیش فرض در جاوا فقط کلاس هایی را در زمان اجرا load می کند که تابحال load نشده اند یعنی متد loadClass از کلاس java.lang.ClassLoader عملا قابلیت class reloading را ندارد و وقتی کلاسی load شد java.lang.ClassLoader دیگر نمی تواند تغییرات آن را reload کند.
برای این کار باید یک ClassLoader سفارشی خاص خود را بنویسیم که فرزند java.lang.ClassLoader است:
public class NewClassLoader extends ClassLoader{
public NewClassLoader(ClassLoader parent) {
super(parent);
}
public Class loadClass(String name) throws ClassNotFoundException {
if(!"com.test.NewClass".equals(name))
return super.loadClass(name);
try {
String url = "file:/home/saeed/NetBeansProjects/ClassLoading/build/classes/com/test/NewClass.class";
URL myUrl = new URL(url);
URLConnection connection = myUrl.openConnection();
InputStream input = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1){
buffer.write(data);
data = input.read();
}
input.close();
byte[] classData = buffer.toByteArray();
return defineClass("com.test.NewClass",
classData, 0, classData.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
در کلاس زیر دو متد loadClass و reloadClass داریم، اگر پس از load کلاس NewClass به آن دو متد اضافه کنیم (echo و یک overload برای test) و در بدنه متد test نیز تغییر اعمال کنیم با فراخوانی متد reloadClass می بینیم که تغییرات اعمال شده load شده است.
public class ClassLoaderTest {
private ClassLoader parentClassLoader;
private NewClassLoader classLoader;
public ClassLoaderTest() {
parentClassLoader = NewClassLoader.class.getClassLoader();
}
public void loadClass() throws ClassNotFoundException, InstantiationException,
InstantiationException, IllegalAccessException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException {
classLoader = new NewClassLoader(parentClassLoader);
Class myObjectClass = classLoader.loadClass("com.test.NewClass");
Object obj = myObjectClass.newInstance();
System.out.println("call test method before change:");
obj.getClass().getMethod("test").invoke(obj);
}
public void reloadClass() throws ClassNotFoundException, InstantiationException,
IllegalAccessException, NoSuchMethodException, IllegalArgumentException,
InvocationTargetException {
classLoader = new NewClassLoader(parentClassLoader);
Class myObjectClass = classLoader.loadClass("com.test.NewClass");
Object obj = myObjectClass.newInstance();
System.out.println("call test method after change:");
obj.getClass().getMethod("test").invoke(obj);
System.out.println("call new echo method after add it:");
System.out.println("" + obj.getClass().
getMethod("echo", String.class).invoke(obj, "Saeed"));
System.out.println("call new overload test method after add it:");
System.out.println("" + obj.getClass().
getMethod("test", Integer.class).invoke(obj, 10));
}
}
نکته ای که وجود دارد new کردن شئ از کلاس NewClassLoader در ابتدای هر دو متد loadClass و reloadClass است که به این دلیل است که متد resolve از کلاس java.lang.ClassLoader اجازه دوبار لینک کردن یک کلاس در زمان اجرا را نمی دهد! از طرف دیگر این متد final است و نمی توان آن را در NewClassLoader بازنویسی (override) کرد، بنابراین باید در هر سری reload یک شئ جدبد از کلاس NewClassLoader ساخت.