1. 程式人生 > >Class 類載入器,內部類載入實驗

Class 類載入器,內部類載入實驗

最近實驗通過jdk編譯後的Class多出一個內部類class檔案,美元$符號的class檔案,如A.class ,A$B.class,載入A.class總是報錯。

除了載入內部類方法,還有就是把class檔案打包成jar,通過自定義URLClassLoader  載入jar檔案,做類似與Osgi的工作。

通過類載入器,做一個動態載入模組的應用伺服器。


通過網上找到程式碼例子改改後解決現在的問題。

Exception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "com.lw.loader.TestClass$TestInnerClass.<init>(Lcom/lw/loader/TestClass;)V" the class loader (instance of com/lw/loader/DynamicClassLoader) of the current class, com/lw/loader/TestClass, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, com/lw/loader/TestClass$TestInnerClass, have different Class objects for the type tClass;)V used in the signature
	at com.lw.loader.TestClass.<init>(TestClass.java:12)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
	at java.lang.Class.newInstance(Class.java:374)
	at com.lw.loader.DynamicClassLoaderTest.main(DynamicClassLoaderTest.java:17)


類載入器 重寫findClass,通過defineClass寫入二進位制定義Class類

package com.lw.loader;

import java.io.File;
import java.io.FileInputStream;
import java.util.Hashtable;
import java.util.jar.Manifest;

public class DynamicClassLoader extends ClassLoader {
	private Manifest manifest;
	private Hashtable<String, ClassInfo> classInfo = new Hashtable<String, ClassInfo>();

	/**
	 * Provide delegation constructor
	 */
	DynamicClassLoader(ClassLoader parent) {
		super(parent);
	}

	/**
	 * Same old ClassLoader constructor
	 */
	DynamicClassLoader() {
		super();
	}

	private String getClassPath(String className) {
		String relativeClassPath = className.replace('.', File.separatorChar) + ".class";

		String classPath;
		try {
			classPath = ClassLoader.getSystemResource(relativeClassPath).toURI().getPath().substring(1);
			
			System.out.println(classPath);
			if ((new File(classPath)).exists())
				return classPath;
		} catch (java.net.URISyntaxException e) {
		}

		return null;
	}

	/**
	 * This is the method where the task of class loading is delegated to our custom loader.
	 * 
	 * @param name the name of the class
	 * @return the resulting <code>Class</code> object
	 * @exception ClassNotFoundException if the class could not be found
	 */
	protected Class findClass(String name) throws ClassNotFoundException {
		// get path of given class
		String classPath = getClassPath(name);
		if (classPath == null)
			throw new ClassNotFoundException(name);

		// get last modified time of class file
		File f = new File(classPath);
		long lastModified = f.lastModified();

		// check if given class loaded already
		ClassInfo loadedClassInfo = classInfo.get(name);

		// if class loaded is the newest one, no need to reload it
		if ((loadedClassInfo != null) && (loadedClassInfo.lastModified >= lastModified))
			return loadedClassInfo.classType;

		FileInputStream fi = null;

		try {
			fi = new FileInputStream(f);
			byte[] classBytes = new byte[fi.available()];
			fi.read(classBytes);
			Class result = defineClass(name, classBytes, 0, classBytes.length);
			classInfo.put(name, new ClassInfo(result, lastModified));
			return result;
		} catch (Exception e) {
			// We could not find the class, so indicate the problem with an exception
			e.printStackTrace();
			throw new ClassNotFoundException(name);
		} finally {
			if (null != fi) {
				try {
					fi.close();
				} catch (Exception e) {
				}
			}
		}
	}
}
ClassInfo 資訊
package com.lw.loader;

public class ClassInfo {
	public Class classType;
	
	public long lastModified;

	public ClassInfo(Class classType) {
		this.classType = classType;
		this.lastModified = -1;
	}

	public ClassInfo(Class classType, long lastModified) {
		this.classType = classType;
		this.lastModified = lastModified;
	}
}

測試類
package com.lw.loader;

public class TestClass {
	public class TestInnerClass {

		public void printMessage() {
			System.out.println("Test inner info");
		}
	}

	public TestClass() {
		TestInnerClass cls = new TestInnerClass();
	}

	public void printMessage() {
		System.out.println("Test info changed");
	}
}

測試方法
package com.lw.loader;

import java.lang.reflect.Method;

public class DynamicClassLoaderTest {
	public static void main(String[] args) throws Exception {
		while (true) {
			DynamicClassLoader classLoader = new DynamicClassLoader();
			
//			classLoader.findClass("com.lw.loader.TestClass$TestInnerClass"); 
			

			Class c = classLoader.findClass("com.lw.loader.TestClass");

			Method printMessage = c.getMethod("printMessage");

			Object o = c.newInstance();

			printMessage.invoke(o);

			Thread.sleep(5000);
		}
	}
}