I was trying out a Reloader class which should reload the class from disk when it's used. When something popped up that I didn't quite got a grasp on.
Which was that the static variable CHANGED
in my Test
would not update when I modified it through an instance of OtherClass
created using the Reloader
So here is the code I used to test the case out.
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;
}
}
Which calls the Reloader, which basically creates a new instance of a class reloading the changes from disk. And some more magic. Blatantly "stolen" for private use from: How to force Java to reload class upon instantiation?.
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";
}
}
So in the Test.java file, there is 2 comments explaining what I expected to happen, but what actually happened. [1] It changed to true here, what was expected. [2] It was still false here, even though the code is definitely executed after [1], not expected.
My question then is, why or how did the value not change? Might it have to do that the class loader creates a whole new 'fake' new Test class that is derived from it or something?
EDIT: Forgot to show where it was invoked.