调用通过不同ClassLoader加载的类的静态方法不起作用。这是预期的吗?

时间:2017-11-13 20:02:22

标签: java classloader

我有以下类,它使用一个简单的客户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调用的,因此会重新加载一个空的监听器列表?

1 个答案:

答案 0 :(得分:0)

这一行:

FooObservable.addListener(fooListener);

正在创建一个由默认类加载器创建的FooObservable的不同实例。因为它是一个不同的类加载器,所以它是一个完全不同的对象。打电话给md。&lt;&gt;从你的类加载器反对FooObservable。这是同一个静态类的两个不同实例(这是类加载器的一部分 - 你可以拥有同一个类的不同实例)。

如果不是调用md.invoke(ob)而是调用FooObservable.fooDidSomething(),那么您将看到一个成功的结果(来自父类加载器实例)。

不调用md.addListener(注释掉的行),类加载器加载的版本没有监听器。