Изменения, внесенные в статическую переменную через недавно загруженный класс, по-видимому, не применяются.(Джава) - PullRequest
0 голосов
/ 11 июня 2018

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

То, что статическая переменная CHANGED в моем Test не обновлялась, когда я изменял это через созданный экземпляр OtherClassиспользуя Reloader

Итак, вот код, который я использовал для проверки случая.

Test.java:

import java.io.IOException;

public class Test {

    public static boolean CHANGED = false;
    static Test obj = new Test();

    static void change() {
        CHANGED = true;
        System.out.println(CHANGED); // [1] It is clearly changed to true.
    }

    public static void main(String[] args) {
        System.out.println(new OtherClass().toString2());
        System.out.println(CHANGED);
        try {
            Object foo = reload();
            System.out.println(foo);

        } catch (InstantiationException | IllegalAccessException | IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println(CHANGED); // [2] But here it is false again.
        }
    }

    public static Object reload() throws InstantiationException, IllegalAccessException, IOException {
        Object foo = new Reloader().loadClass("OtherClass").newInstance();
        return foo;
    }

}

, который вызывает Reloader, который в основномсоздает новый экземпляр класса, перезагружая изменения с диска.И еще немного магии.Откровенно «украдено» для частного использования из: Как заставить Java перезагрузить класс при создании экземпляра? .

Reloader.java:

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class Reloader extends ClassLoader {

    @Override
    public Class<?> loadClass(String s) {
        return findClass(s);
    }

    @Override
    public Class<?> findClass(String s) {
        try {
            byte[] bytes = loadClassData(s);
            return defineClass(s, bytes, 0, bytes.length);
        } catch (IOException ioe) {
            try {
                return super.loadClass(s);
            } catch (ClassNotFoundException ignore) {
            }
            ioe.printStackTrace(System.out);
            return null;
        }
    }

    private static byte[] loadClassData(String className) throws IOException {
        File f = new File("bin/" + className.replaceAll("\\.", "/") + ".class");
        int size = (int) f.length();
        byte buff[] = new byte[size];
        try (FileInputStream fis = new FileInputStream(f)) {
            try (DataInputStream dis = new DataInputStream(fis)) {
                dis.readFully(buff);
            }
        }
        return buff;
    }
}

OtherClass.java

public class OtherClass {

    @Override
    public String toString() {
        Test.change();
        return "OtherClass";
    }

    public String toString2() {
        return "OLD";
    }
}

Итак, в файле Test.java есть 2 комментария, объясняющих, что я ожидал, но что на самом деле произошло.[1] Это изменилось на истину здесь, что и ожидалось.[2] Здесь все равно было ложно, хотя код определенно выполняется после [1], не ожидается.

Мой вопрос: почему или как значение не изменилось?Должно ли это быть из-за того, что загрузчик классов создает совершенно новый «фальшивый» новый класс Test, производный от него или что-то в этом роде?

EDIT : Забыл показать, где он был вызван.

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Вы пытаетесь переписать файлы .class, которые скомпилированы, или загрузить определение из этого?Вероятно, не будет работать хорошо.Оглядываясь вокруг, вы даже не можете использовать сериализуемость, как для экземпляров.
Скорее всего, вам нужно будет создать private static Boolean CHANGED = null; и сохранить его начальное значение в файле.тогда есть

public static Boolean isChanged(){ 
    if (CHANGED == null){
        CHANGED = //read value from file
       return CHANGED;
   } else return CHANGED;
}



public static void setChanged(Boolean val){
    CHANGED = val;
    //write value to disk
}
0 голосов
/ 12 июня 2018

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

попробуйте не использовать другой загрузчик классов, и у вас будет CHANGED как true.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...