Несколько экземпляров статических переменных - PullRequest
13 голосов
/ 10 мая 2011

Я экспериментирую с использованием разных загрузчиков классов для загрузки определенного класса и проверяю, могут ли статические переменные в этом классе иметь разные экземпляры.

По сути, я пытаюсь написать код для того, что Стивен С упомянул в этом ответе .

Вот мои классы:

CustomClassLoader.java

class CustomClassLoader extends ClassLoader
{
    public Class loadClass(String classname)  throws ClassNotFoundException {
        return super.loadClass(classname, true);
    }
}

Test.java (который содержит драйвер)

class Test {
        public static void main(String[] args) throws Exception {
                CustomClassLoader c1 = new CustomClassLoader();
                CustomClassLoader  c2 = new CustomClassLoader();
                Class m1, m2;

                m1 = c1.loadClass("A");
                m2 = c2.loadClass("A");

                m1.getField("b").set(null, 10);

                System.out.println(m1.getField("b").get(null));
                System.out.println(m2.getField("b").get(null));
        }

}

A.java (который содержит статическую переменную)

class A {
        public static int b = 5;
}

Когда я запускаютестовый класс, я получаю следующий вывод:

$ java Test
10
10

Я ожидал, что выходные данные будут 10 и 5. Как я могу заставить код создать два экземпляра моей статической переменной?

ПримечаниеЯ делаю это только для экспериментов и обучения, но мне было бы интересно узнать, может ли это быть в реальном мире.

Ответы [ 4 ]

8 голосов
/ 10 мая 2011

Похоже, что класс "A" загружается загрузчиком родительского класса, а не вашим CustomClassLoader (потому что вы вызываете super.loadClass).

Следующая непроверенная поправка должна позволить вам определить класс «A», используя ваш собственный загрузчик классов (в то же время делегируя все остальное родительскому загрузчику).

Извиняюсь за ужасную ошибку, где я предполагаю, что единственный inputStream.read () прочитает все! Но, надеюсь, вы понимаете, о чем я.

    public Class loadClass(String classname)  throws ClassNotFoundException {
    if (classname.equals("A")) {
        InputStream is = getResourceAsStream("A.class");
        byte[] bodge = new byte[8192];  // Should read until EOF
        try {
            int len = is.read(bodge);
            return defineClass("A", bodge, 0, len);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return super.loadClass(classname, true);
}

Вероятно, в результате вы получите ClasscastExceptions или что-то подобное ...

6 голосов
/ 10 мая 2011

Ваша проблема в том, что new CustomClassLoader() создает загрузчик классов, который будет пытаться делегировать загрузочные классы системному загрузчику классов - и это будет одинаково для обоих экземпляров. Ваш CustomClassLoader также даже не может загружать классы сам. Попробуйте использовать URLClassLoader и передать null в качестве родителя.

Что касается приложений реального мира: это важно для веб-контейнеров Java и серверов приложений, так как позволяет различным приложениям быть полностью изолированными друг от друга, даже если они могут использовать множество одинаковых классов.

0 голосов
/ 25 декабря 2017

У меня была такая же проблема (интеграционные тесты), и я попробовал ее с подходом @Michael Borgwardt.Вот пример кода:

URLClassLoader classLoader1 = new URLClassLoader(new URL[]{new URL("file:///path/to/jar/my-classes.jar")}, null);
URLClassLoader classLoader2 = new URLClassLoader(new URL[]{new URL("file:///path/to/jar/my-classes.jar")}, null);

// Load with classLoader1
Class<?> myClass1 = classLoader1.loadClass("MyClass");
Constructor<?> constructor1 = myClass1.getConstructor();
Object instance1 = constructor1.newInstance();

// Load with classLoader2
Class<?> myClass2 = classLoader2.loadClass("MyClass");
Constructor<?> constructor2 = myClass2.getConstructor();
Object instance2 = constructor2.newInstance();

// Load with system classloader
MyClass myClass = new MyClass();

// ...
0 голосов
/ 10 мая 2011

Если вы посмотрите на источник ClassLoader или даже на javadoc, то обнаружите, что по умолчанию ClassLoader делегирует системному ClassLoader по умолчанию, который фактически является общим для экземпляров.

...