关键词:[Java] [反射] [invoke]
其实我的需求是在系统中 测试用户导入的jar包,所有网上找了很多解决方案,踩过很多坑,再加上以前搞c++的,对java不是很熟,这里特意记录下,算是基本满足需求了;
使用反射获得jar包中的类、方法、参数、返回值类型
使用反射获取jar包中的类、方法、参数、以及返回类型,主要参照这篇文章
这里面我的TestJar.jar 里面 就一个Demo类,是这样的:
package com.baidu;
public class Demo {
public Demo() {
}
public static void main(String[] args) {
}
public String getInfo() {
return "hello world";
}
public int getSum(int a, int b) {
return a + b;
}
}
@Test
public void test2() {
String path = "E:\\Desktop\\Programmer\\JavaFile\\MyWeb\\test\\web\\WEB-INF\\lib\\";
String fileName = "TestJar.jar";
try {
JarFile jarFile = new JarFile(path + fileName);
Enumeration<JarEntry> e = jarFile.entries();
JarEntry entry;
while (e.hasMoreElements()) {
entry = (JarEntry) e.nextElement();
//
if (entry.getName().indexOf("META-INF") < 0 && entry.getName().indexOf(".class") >= 0) {
String classFullName = entry.getName();
//去掉后缀.class
String className = classFullName.substring(0, classFullName.length() - 6).replace("/", ".");
System.out.println(className);
Class<?> c = null;
try {
try {
// 用className这个类来装载c,但还没有实例化
c = Class.forName(className);
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
Method[] methods = c.getMethods();
for (Method method : methods) {
String methodName = method.getName();
System.out.println("方法名称:" + methodName);
System.out.println("返回值类型" + method.getReturnType());
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> clas : parameterTypes) {
// String parameterName = clas.getName();
String parameterName = clas.getSimpleName();
System.out.println("参数类型:" + parameterName);
}
System.out.println("==========================");
}
} catch (Exception e1) {
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
运行代码后的输出结果
com.baidu.Demo
方法名称:main
返回值类型void
参数类型:String[]
==========================
方法名称:getSum
返回值类型int
参数类型:int
参数类型:int
==========================
方法名称:getInfo
返回值类型class java.lang.String
==========================
方法名称:wait
返回值类型void
参数类型:long
参数类型:int
==========================
方法名称:wait
返回值类型void
==========================
方法名称:wait
返回值类型void
参数类型:long
==========================
方法名称:equals
返回值类型boolean
参数类型:Object
==========================
方法名称:toString
返回值类型class java.lang.String
==========================
方法名称:hashCode
返回值类型int
==========================
方法名称:getClass
返回值类型class java.lang.Class
==========================
方法名称:notify
返回值类型void
==========================
方法名称:notifyAll
返回值类型void
==========================
Process finished with exit code 0
如何动态实例化一个类,并运行其中的方法
//用className来状态这个c,className就是上面那个代码中的,可以理解为com.xxx.xxx(去掉了后面的.class)
Class<?> c = null;
c = Class.forName(className);
//创建对象实例
Object instance=c.newInstance();
这样还不能直接调用instance的方法,要先获取 这个类中的方法 然后再 invoke;
这里我以 TestJar.jar 里面的demo 类下的 getInfo 方法为例:
// 用className这个类来装载c
c = Class.forName(className);
// 实例化对象
Object instance=c.newInstance();
//获取实例当中的方法名为show,参数只有一个且类型为string的public方法
Method method=c.getMethod("getInfo");
// 如果该方法有参数,后面就跟参数类型
// Method method = MyTest.getMethod("show", String.class);
// //传入实例以及方法参数信息(如果有)执行这个方法
Object ret = method.invoke(instance);
System.out.println("运行动态装载jar包的getInfo方法,并获得输出");
// 如果有返回值,可以直接打印ret获得输出
System.out.println(method.invoke(instance ));
全部代码
public void test2() {
String path = "E:\\Desktop\\Programmer\\JavaFile\\MyWeb\\test\\web\\WEB-INF\\lib\\";
String fileName = "TestJar.jar";
try {
JarFile jarFile = new JarFile(path + fileName);
Enumeration<JarEntry> e = jarFile.entries();
JarEntry entry;
while (e.hasMoreElements()) {
entry = (JarEntry) e.nextElement();
//
if (entry.getName().indexOf("META-INF") < 0 && entry.getName().indexOf(".class") >= 0) {
String classFullName = entry.getName();
//去掉后缀.class
String className = classFullName.substring(0, classFullName.length() - 6).replace("/", ".");
System.out.println(className);
Class<?> c = null;
try {
try {
// 用className这个类来装载c
c = Class.forName(className);
Object instance=c.newInstance();
Method method=c.getMethod("getInfo");
System.out.println("运行动态装载jar包的getInfo方法,并获得输出");
System.out.println(method.invoke(instance ));
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
Method[] methods = c.getMethods();
for (Method method : methods) {
String methodName = method.getName();
System.out.println("方法名称:" + methodName);
System.out.println("返回值类型" + method.getReturnType());
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> clas : parameterTypes) {
// String parameterName = clas.getName();
String parameterName = clas.getSimpleName();
System.out.println("参数类型:" + parameterName);
}
System.out.println("==========================");
}
} catch (Exception e1) {
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
输出
com.baidu.Demo
运行动态装载jar包的getInfo方法,并获得输出
hello world
方法名称:main
返回值类型void
参数类型:String[]
==========================
方法名称:getSum
返回值类型int
参数类型:int
参数类型:int
==========================
方法名称:getInfo
返回值类型class java.lang.String
==========================
方法名称:wait
返回值类型void
参数类型:long
参数类型:int
==========================
方法名称:wait
返回值类型void
==========================
方法名称:wait
返回值类型void
参数类型:long
==========================
方法名称:equals
返回值类型boolean
参数类型:Object
==========================
方法名称:toString
返回值类型class java.lang.String
==========================
方法名称:hashCode
返回值类型int
==========================
方法名称:getClass
返回值类型class java.lang.Class
==========================
方法名称:notify
返回值类型void
==========================
方法名称:notifyAll
返回值类型void
==========================
Process finished with exit code 0
用getSum方法也是一样:
c = Class.forName(className);
Object instance=c.newInstance();
Method method=c.getMethod("getSum",int.class,int.class);
System.out.println("运行动态装载jar包的getSum方法,并获得输出");
System.out.println(method.invoke(instance,2,3));
com.baidu.Demo
运行动态装载jar包的getSum方法,并获得输出
5