关键词:[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