How to load same class more than once in jvm / How to dynamically reload a class

Loading a class more than once using java’s built in ClassLoader is not possible because:
Builtin ClassLoader always checks if a class has already been loaded. If it is, it simply does nothing and returns.
Hence to reload a class, you have to use your custom ClassLoader.
Code to reload a class using custom ClassLoader is as follows:

public class Test {
	public static void main(String[] args) throws Exception {
		//notice different instances of ClassLoader. Reason follows below.
		Class<?> c1 = new TestClassLoader().loadClass("Test");
		Class<?> c2 = new TestClassLoader().loadClass("Test");
		//print class name for first instance
		System.out.println(c1);
		//print class name for second instance
		System.out.println(c2);
		// confirm that the two class instances are different by comparing their
		// references. This should print false if the instances are different
		// which means that the class is loaded twice
		System.out.println(c1 == c2);
	}
}

class TestClassLoader extends ClassLoader {
	@Override
	public Class<?> loadClass(String name) throws ClassNotFoundException {
		// load other classes normally using System ClassLoader
		if (!name.equals("Test")) {
			return super.loadClass(name);
		}
		InputStream in = null;
		try {
			// get input stream linked to this class
			in = ClassLoader.getSystemResourceAsStream(name + ".class");
			int data = in.read();
			// initialize buffer
			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
			// loop over data till more data is available
			while (data != -1) {
				// write data to buffer
				buffer.write(data);
				data = in.read();
			}
			// convert to byte array as this is the format accepted by
			// defineClass method
			byte[] classData = buffer.toByteArray();
			// converts a byte array to a instance of class java.lang.Class
			return defineClass(name, classData, 0, classData.length);
		} catch (IOException e) {
			throw new ClassNotFoundException();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					// ignore
				}
			}
		}
	}
}

Code is self-explanatory by its comments. We shall explore some other facts in the following lines:

Let’s tweak in:

  1.  Every loaded class has to be linked also. ClassLoader’s resolve() method does this automatically.
  2. resolve() method does not allow any ClassLoader instance to link the same class twice. Therefore we had to create two different ClassLoader instances to load the class.
  3. Loading a class more than once using the same ClassLoader instance will give the below error:                                                                                        Exception in thread “main” java.lang.LinkageError: loader (instance of TestClassLoader): attempted duplicate class definition for name: "Test"
  4. resolve() method is final, hence cannot be overridden.

Leave a Reply