我有以下类,它使用一个简单的客户ClassLoader来加载一个类,然后直接在其上调用一个静态方法:
public class App {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
MyCustClassLoader loader = new MyCustClassLoader();
Class<?> c = loader.findClass("classloading.FooObservable");
Object ob = c.newInstance();
Method md = c.getDeclaredMethod("addListener", Listener.class);
FooListener fooListener = new FooListener("app class loader");
// md.invoke(ob, fooListener); <<< works it I uncomment this.
FooObservable.addListener(fooListener);
md = c.getMethod("fooDidSomething");
md.invoke(ob);
md.invoke(ob);
md.invoke(ob);
}
}
我的自定义类加载器如下所示:
package classloading;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyCustClassLoader extends ClassLoader {
@Override
public Class<?> findClass(String name) {
byte[] bt = loadClassData(name);
return defineClass(name, bt, 0, bt.length);
}
private byte[] loadClassData(String className) {
//read class
InputStream is = getClass().getClassLoader().getResourceAsStream(className.replace(".", "/")+".class");
ByteArrayOutputStream byteSt = new ByteArrayOutputStream();
//write into byte
int len =0;
try {
while((len=is.read())!=-1){
byteSt.write(len);
}
} catch (IOException e) {
e.printStackTrace();
}
//convert into byte array
return byteSt.toByteArray();
}
}
有问题的静态方法在类FooObservable
中定义,它包含一个监听器列表和一个可以调用的通知方法,以通知监听器发生了什么事情:
package classloading;
import java.util.ArrayList;
import java.util.List;
public class FooObservable {
private static List<Listener> listeners = new ArrayList<Listener>();
int x = 0;
public static void addListener(Listener l) {
listeners.add(l);
}
public void fooDidSomething() {
x++;
for (Listener l : listeners) {
l.notify(x);
}
}
}
它似乎不起作用,因为没有打印。但是,当我取消注释上面的行md.invoke
类应用并注释掉静态调用FooObservable.addListener
时,它会起作用,我会看到:
foo listener (app class loader) notified: 1
foo listener (app class loader) notified: 2
foo listener (app class loader) notified: 3
为什么会这样?是否取消注释这一行的事实,静态调用addListener
是针对使用Java AppClassLoader加载的FooObservable
调用的,因此会重新加载一个空的监听器列表?
答案 0 :(得分:0)
这一行:
FooObservable.addListener(fooListener);
正在创建一个由默认类加载器创建的FooObservable的不同实例。因为它是一个不同的类加载器,所以它是一个完全不同的对象。打电话给md。&lt;&gt;从你的类加载器反对FooObservable。这是同一个静态类的两个不同实例(这是类加载器的一部分 - 你可以拥有同一个类的不同实例)。
如果不是调用md.invoke(ob)而是调用FooObservable.fooDidSomething(),那么您将看到一个成功的结果(来自父类加载器实例)。
不调用md.addListener(注释掉的行),类加载器加载的版本没有监听器。