How to force Java to reload class upon instantiation?

后端 未结 6 1168
执念已碎
执念已碎 2020-12-04 22:52

Background:
I have a MainTest class that has many buttons, each of which instantiate a class that I am coding/testing. I want the code/test cycle for these classes to be

相关标签:
6条回答
  • 2020-12-04 22:57

    Sounds a little scary, but this should help.

    http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html

    ClassLoader can dynamically load classes at runtime, I would read the api to determine if loading it again overrides the previous version.

    0 讨论(0)
  • 2020-12-04 22:57

    I found an article on exactly this problem.
    http://www.zeroturnaround.com/blog/reloading-objects-classes-classloaders/

    BUT, maerics answer looks good too. will try it later.

    0 讨论(0)
  • 2020-12-04 23:00

    It sounds like you want ot use the hot deployment when can be used with the debugger. When you debug a problem and recomiple some of its classes you can get the option to reload the changed classes.

    EDIT: Apart from using the debugging API, you can use Instrumentation. http://download-llnw.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html

    However, since using a debugger is by far the simplest way to do this, if this doesn't work, you are likely to run into the same problems.

    It sounds like what you need to test smaller pieces of work so it takes less than a second run some subset of your application.

    Or you could load your application faster by providing a dump and re-load facility for the memory. This way you could start your application from a snapshot (perhaps immediately)

    0 讨论(0)
  • 2020-12-04 23:05

    You can give a try to Java Rebel. It is a "development-only" class-loader designed to do exactly what you need but, perhaps, it could be expensive for your needs. In your case, Peter Lawrey's solution could be enough.

    0 讨论(0)
  • 2020-12-04 23:11

    I am not sure how to do this in code, but NetBeans does have an "Apply Code Changes" button that will do this.

    However, it can only change the implementation of the class, it cannot change it's signature. This means you cannot add, remove, or change instance variables or methods. This is due to the design of the JVM which does not allow these to be changed once a class has been loaded once.

    Since NetBeans can do it, there must be a way, but I do not know how to do it manually.

    If you run in an IDE that supports this feature, you can just click the button each time you modify a class. It will then recompile that class and reload it.

    0 讨论(0)
  • 2020-12-04 23:15

    There's no hope of "overloading" the new operator but you could certainly write a custom class loader that simply reloads the bytecode every time you ask it to load a class. No out-of-the-box classloaders will do what you're looking for because they all assume that the class definition will not change through the life of the JVM.

    But here's how you make it happen. Create a class loader called, say, Reloader which overrides the methods loadClass and findClass methods so that they simply reload the class files from disk every time they are called (instead of "caching" them for later use). Then you just have to call new Reloader().loadClass("foo.bar.MyClassName") any time you suspect the class definition has changed (e.g. as part of your testing framework's lifecycle methods).

    This article fills in some of the details but misses some important points, especially about using new instances of the classloader for subsequent reloads and delegating to the default classloader when appropriate. Here is a simple working example which repeatedly loads the class MyClass and assumes its class file exists in the relative "./bin" directory:

    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;
        }
    }
    

    At each invocation of the "do/while" block in the main method, a new Reloader is instantiated which loads the class from disk and returns it to the caller. So if you overwrite the bin/MyClass.class file to contain a new implementation with a different, overloaded toString method, then you should see the new implementation each time.

    0 讨论(0)
提交回复
热议问题