在工作当中经常遇到反编译后的jar文件,并要传入参数了解其中的某些方法的输出,想到Java里面的反射可以实现加载jar文件并调用其中的方法来达到自己的目的。就写了个Demo代码。
以下的类可以编译生成hello.jar文件。
1 package org.lele.fatpanda; 2 3 public class Util 4 { 5 public static String myName; 6 /* 7 * 无参数,无返回值的方法。 8 */ 9 public static void getVersion() 10 { 11 System.out.println("java version: " + System.getProperty("java.version") ); 12 } 13 /* 14 *有参数,无返回值的方法。 15 */ 16 public static void setTmpName(String name) 17 { 18 myName = name; 19 System.out.println("Set Tmp Name Succeed and the name is : " + myName); 20 } 21 /* 22 * 单个参数,有返回值的方法。 23 */ 24 public static String getName(String prefix) 25 { 26 return prefix + "lele"; 27 } 28 /* 29 * 多个参数,有返回值的方法。 30 */ 31 public static String test(String i1, int i2) 32 { 33 return i1 + i2; 34 } 35 36 } 37 /* 38 * 一个生成jar文件的类文件,要使用public的访问权限,如果在方便进行反射调用,则要将方法声明为static。 39 */
下面的就是实现动态加载并调用的主要代码。
1 package com.xiyoulele.wh; 2 3 import java.io.File; 4 import java.lang.reflect.Method; 5 import java.net.URL; 6 import java.net.URLClassLoader; 7 8 public class Main 9 { 10 public static void main(String[] args) 11 { 12 URL[] urls = new URL[] {}; 13 MyClassLoader classLoader = new MyClassLoader(urls, null); //自定义ClassLoader来加载jar文件 14 15 try 16 { 17 classLoader.addJar(new File("c:\hello.jar").toURI().toURL()); //加载特定路径的jar文件 18 Class<?> clazz = classLoader.loadClass("org.lele.fatpanda.Util"); //动态加载jar文件当中的特定类的class文件 19 20 //传入一个参数一个返回值 21 22 Class<?>[] typeA = new Class[1]; //传入要调用的方法的参数类型 23 typeA[0] = String.class; 24 25 Object[] objsA = new Object[1]; //传入要调用的方法的具体参数 26 objsA[0] = new String("xiyou"); 27 28 Method method = clazz.getMethod("getName", typeA); //获取要被调用的特定方法 getName(String xx) 29 30 String result = method.invoke(clazz, objsA).toString(); //调用方法,获取方法的返回值。 31 32 System.out.println(result); //输出方法 33 34 //传入2个参数一个人返回值 35 36 Class<?>[] typesB = new Class[2]; 37 typesB[0] = String.class; 38 typesB[1] = Integer.TYPE; 39 40 Object[] ObjsB = new Object[2]; 41 ObjsB[0] = new String("ZT"); 42 ObjsB[1] = new Integer(520); 43 44 Method newMethod = clazz.getMethod("test", typesB); 45 String res = newMethod.invoke(clazz.newInstance(), ObjsB).toString(); 46 47 System.out.println(res); 48 49 //有传入的参数,没有返回值 50 Class<?>[] typesC = new Class[1]; 51 typesC[0] = String.class; 52 53 Object[] objsC = new Object[1]; 54 objsC[0] = new String("xiyoulele"); 55 56 Method methodC = clazz.getMethod("setTmpName", typesC); 57 methodC.invoke(clazz.newInstance(), objsC); 58 59 //无参数,无返回值 60 Method methodD = clazz.getDeclaredMethod("getVersion"); 61 methodD.invoke(clazz.newInstance()); 62 63 classLoader.close(); //关闭类的加载器 64 65 } catch (Exception e) 66 { 67 e.printStackTrace(); 68 } 69 } 70 //继承URLClassLoader来实现对jar文件的加载 71 static class MyClassLoader extends URLClassLoader 72 { 73 public MyClassLoader(URL[] urls) 74 { 75 super(urls); 76 } 77 public MyClassLoader(URL[] urls, ClassLoader parent) 78 { 79 super(urls, parent); 80 } 81 public void addJar(URL url) 82 { 83 this.addURL(url); 84 } 85 } 86 } 87 /* 88 * 需求:加载jar文件,动态调用里面的方法,该方法带有参数和返回值。 89 */
程序运行的结果: