Нет надежды на «перегрузку» оператора new
, но вы, безусловно, могли бы написать собственный загрузчик классов, который просто перезагружает байт-код каждый раз, когда вы просите его загрузить класс. Никакие готовые загрузчики классов не будут делать то, что вы ищете, потому что все они предполагают, что определение класса не изменится в течение жизни JVM.
Но вот как ты это делаешь. Создайте загрузчик классов с именем, скажем, Reloader
, который переопределяет методы loadClass
и findClass
, чтобы они просто перезагружали файлы классов с диска при каждом вызове (вместо «кэширования» их для последующего использования). Затем вам просто нужно вызвать new Reloader().loadClass("foo.bar.MyClassName")
каждый раз, когда вы подозреваете, что определение класса изменилось (например, как часть методов жизненного цикла вашей инфраструктуры тестирования).
Эта статья содержит некоторые детали, но упускает некоторые важные моменты, особенно об использовании новых экземпляров загрузчика классов для последующих перезагрузок и делегировании загрузчику классов по умолчанию, когда это необходимо. Вот простой рабочий пример, который многократно загружает класс MyClass
и предполагает, что его файл класса существует в относительной директории "./bin":
public class Reloader extends ClassLoader {
public static void main(String[] args) throws Exception {
do {
Object foo = new Reloader().loadClass("MyFoo").newInstance();
System.out.println("LOADED: " + foo); // Overload MyFoo#toString() for effect
System.out.println("Press <ENTER> when MyFoo.class has changed");
System.in.read();
} while (true);
}
@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 byte[] loadClassData(String className) throws IOException {
File f = new File("bin/" + className.replaceAll("\\.", "/") + ".class");
int size = (int) f.length();
byte buff[] = new byte[size];
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buff);
dis.close();
return buff;
}
}
При каждом вызове блока do / while в методе main создается новый Reloader, который загружает класс с диска и возвращает его вызывающей программе. Таким образом, если вы перезаписываете файл bin/MyClass.class
, чтобы он содержал новую реализацию с другим, перегруженным методом toString
, то вы должны видеть новую реализацию каждый раз.