本文研究的主要是Java 動態加載jar和class文件的相關內容,具體如下。
JAVA中類文件加載是動態的。也就是說當我們用到的時候才會去加載,如果不用的話,就不會去加載我們的類。
JAVA為我們提供了兩種動態機制。第一種是隱式機制。第二種是顯示機制。如下:
兩種方法:
Class.forName()方法具有兩個形式:
public static Class forName(String className)public static Class forName(String className, boolean initialize,ClassLoader loader)調用只有一個參數的forName()方法等效於Class.forName(className, true, loader)。
這兩個方法,最後都要連接到原生方法forName0().
而三個參數的forName(),最後調用的是: forName0(name, initialize, loader);
不管使用的是new 實例化某個類、或是使用只有一個參數的Class.forName()方法,內部都隱含了“載入類+ 運行靜態代碼塊”的步驟。
而使用具有三個參數的Class.forName()方法時,如果第二個參數為false,那麼類加載器只會加載類,而不會初始化靜態代碼塊,只有當實例化這個類的時候,靜態代碼塊才會被初始化,靜態代碼塊是在類第一次實例化的時候才初始化的。
ClassLoader就是用來Load Class的,當一個Class被加載的時候,這個Class所引用到的所有Class也會被加載,而且這種加載是遞歸的,也就是說,如果A引用到B,B 引用到C,那麼當A被加載的時候,B也會被加載,而B被加載的時候,C也會加載。如此遞歸直到所有需要的Class都加載好。
package com.demo.test;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;public class DynamicLoadDemo {enum FileType {JAR, CLASS, OTHER}static class MyClassLoader extends ClassLoader {public synchronized Class<?> loadClass(String name, File file) throws FileNotFoundException {Class<?> cls = findLoadedClass(name);if(cls != null) {return cls;}FileInputStream fis = new FileInputStream(file);ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;try {while (true) {len = fis.read(buffer);if (len == -1) {break;}baos.write(buffer, 0, len);}//FileInputStream的flush是空操作,因為flush的作用是把緩存中的東西寫入實體(硬盤或網絡流)中,這裡沒有這種必要所以為空//baos.flush();byte[] data = baos.toByteArray();return defineClass(null, data, 0, data.length);}catch (IOException e) {e.printStackTrace();}finally {try {baos.close();}catch (IOException e) {e.printStackTrace();}try {fis.close();}catch (IOException e) {e.printStackTrace();}}return null;}}public static void main(String[] args) {String className = "com.demo.test.HelloWorld";String paths[] = { "HelloWorld.jar", "HelloWorld.class" };for (String path : paths) {String lowerPath = path.toLowerCase();FileType fileType = FileType.OTHER;if (lowerPath.endsWith(".jar") || lowerPath.endsWith(".zip")) {fileType = FileType.JAR;} else if (lowerPath.endsWith(".class")) {fileType = FileType.CLASS;}if (fileType == FileType.OTHER) {return;}File file = new File(path);if (!file.exists()) {return;}try {URL url = file.toURI().toURL();System.out.println(url.toString());Class<?> cls = null;switch (fileType) {case JAR: URLClassLoader classLoader = new URLClassLoader(new URL[] { url }, Thread.currentThread().getContextClassLoader());cls = classLoader.loadClass(className);break;case CLASS: MyClassLoader myClassLoader = new MyClassLoader();cls = myClassLoader.loadClass(className, file);break;default: break;}if (cls == null) {return;}// 實例變量Field field = cls.getDeclaredField("hello");if (!field.isAccessible()) {field.setAccessible(true);}System.out.println(field.get(cls.newInstance()));// 調用靜態不帶參數方法Method staticMethod = cls.getDeclaredMethod("sayStaticHello", null);if (!staticMethod.isAccessible()) {staticMethod.setAccessible(true);}// 如果函數的返回值是void,就會返回nullstaticMethod.invoke(cls, null);// 實例帶參數方法方法Method method = cls.getDeclaredMethod("say", String.class);if (!method.isAccessible()) {method.setAccessible(true);}Object ret = method.invoke(cls.newInstance(), "hello world");System.out.println(ret);}catch (MalformedURLException e) {e.printStackTrace();}catch (ClassNotFoundException e) {e.printStackTrace();}catch (NoSuchMethodException e) {e.printStackTrace();}catch (SecurityException e) {e.printStackTrace();}catch (IllegalAccessException e) {e.printStackTrace();}catch (IllegalArgumentException e) {e.printStackTrace();}catch (InvocationTargetException e) {e.printStackTrace();}catch (InstantiationException e) {e.printStackTrace();}catch (NoSuchFieldException e) {e.printStackTrace();}catch (FileNotFoundException e) {e.printStackTrace();}}}}結果:
以上就是本文關於Java 動態加載jar和class文件實例解析的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!