JAVA反射

1 概述

白盒测试时,工具类最容易对付,直接调用类方法即可;public修饰的实例方法也还行,先实例化后调用;但是遇到private修饰的方法就头大了,虽然可以在类里写个main方法调用,但破坏了代码本身的完整性,功能代码与测试代码混在一起

不过,反射让我们彻底告别这个问题

2 基本成员

由class展开,类有构造函数(Constructor),类有成员变量(Field),类还有方法(Method)

然后使用public、private、protected、static、final等来修饰

当然还有注解,参数,返回值等,并且有相应的类型

所有这些,就像零件一样,组装成一个完整的class文件

反射正是将整个class拆散,来获取一个个零部件

3 简单API

测试样本

public class App {

    private static int COUNT = 0;
    public final int ONE = 1;

    public App() {
        COUNT++;
    }

    public int inc(int... nums) {
        return COUNT + ONE * nums.length;
    }

    @Deprecated
    public static int count() {
        return COUNT;
    }
}

3-1 Constructor

public class AppTest {

    static void log(String desc, Object ret) {
        System.out.println(String.format("%-20s : %s", desc, ret));
    }

    public static void main(String[] args) throws Exception {

        Class clz = App.class;
        for (Constructor constructor : clz.getConstructors()) {
            log("getName", constructor.getName());
            log("getDeclaringClass", constructor.getDeclaringClass());
            log("getModifiers", constructor.getModifiers());
            log("getParameterCount", constructor.getParameterCount());
            log("getParameterTypes", Arrays.toString(constructor.getParameterTypes()));
        }

        App app = clz.getConstructor(null).newInstance(null);
        log("app.inc()", app.inc());
    }
}
--------------
getName              : App
getDeclaringClass    : class App
getModifiers         : 1
getParameterCount    : 0
getParameterTypes    : []
app.inc()            : 1

3-2 Method

public class AppTest {

    static void log(String desc, Object ret) {
        System.out.println(String.format("%-20s : %s", desc, ret));
    }

    public static void main(String[] args) throws Exception {

        Class clz = App.class;
        for(Method method: clz.getDeclaredMethods()) {
            System.out.println(method.getName());
            log("\tgetModifiers", Modifier.toString(method.getModifiers()));
            log("\tgetParameterCount", method.getParameterCount());
            log("\tgetParameterTypes", Arrays.toString(method.getParameterTypes()));
            log("\tgetAnnotations", Arrays.toString(method.getAnnotations()));
            log("\tisVarArgs", method.isVarArgs());
        }

        Method m = clz.getDeclaredMethod("inc", int[].class);
        int[] param = {1, 2, 3};
        int result = (int)m.invoke(new App(), new Object[]{param});
        log("invoke inc", result);
    }
}public class AppTest {

    static void log(String desc, Object ret) {
        System.out.println(String.format("%-20s : %s", desc, ret));
    }

    public static void main(String[] args) throws Exception {

        Class clz = App.class;
        for(Method method: clz.getDeclaredMethods()) {
            System.out.println(method.getName());
            log("\tgetModifiers", Modifier.toString(method.getModifiers()));
            log("\tgetParameterCount", method.getParameterCount());
            log("\tgetParameterTypes", Arrays.toString(method.getParameterTypes()));
            log("\tgetAnnotations", Arrays.toString(method.getAnnotations()));
            log("\tisVarArgs", method.isVarArgs());
        }

        Method m = clz.getDeclaredMethod("inc", int[].class);
        int[] param = {1, 2, 3};
        int result = (int)m.invoke(new App(), new Object[]{param});
        log("invoke inc", result);
    }
}
-----------
count
    getModifiers        : public static
    getParameterCount   : 0
    getParameterTypes   : []
    getAnnotations      : [@java.lang.Deprecated()]
    isVarArgs           : false
inc
    getModifiers        : public transient
    getParameterCount   : 1
    getParameterTypes   : [class [I]
    getAnnotations      : []
    isVarArgs           : true
invoke inc           : 4

3-3 Field

public class AppTest {

    static void log(String desc, Object ret) {
        System.out.println(String.format("%-20s : %s", desc, ret));
    }

    public static void main(String[] args) throws Exception {

        App app = new App();
        Class clz = App.class;
        Field field = clz.getDeclaredField("ONE");
        log("getInt", field.getInt(app));
        log("getModifiers", Modifier.toString(field.getModifiers()));
    }
}
----------------
getInt               : 1
getModifiers         : public final

4 访问私有方法

  • 调用getDeclaredMethod获取方法,

  • 再使用setAccessible(true)使方法可访问

public class App {

   private void privateMethod() {
       System.out.println("private method");
   }
}

public class AppTest {

    public static void main(String[] args) throws Exception {

        App app = new App();
        Class clz = App.class;

        Method method = clz.getDeclaredMethod("privateMethod");
        method.setAccessible(true);
        method.invoke(app);
    }
}

5 变参方法

  • 当变参类型为int时,invoke传入int[]可行
  • 当变参类型为String时,传入String[]却不行,需要用new Object[] {}包装
public class App {
    public void sum(int... nums) {
        int total = Arrays.stream(nums).sum();
        System.out.println(String.format("sum(%s) = %s", Arrays.toString(nums), total));
    }

    public void log(String... hobby) {
        System.out.println(String.format("Jack like %s", Arrays.toString(hobby)));
    }

    public static void main(String[] args) throws Exception {
        App app = new App();
        Class clz = App.class;
        for(Method method: clz.getDeclaredMethods()) {
            if (method.getName().equals("sum")) {
                int[] nums = {1, 2, 3, 4, 5};
//                method.invoke(app, 1, 2, 3, 4, 5);    //error
                method.invoke(app, nums);

            } else if (method.getName().equals("log")) {
                String[] hobby = new String[] {"coding", "game", "girl"};
//                method.invoke(app, hobby);        //error
                method.invoke(app, new Object[]{hobby});
            }
        }
    }
}

你可能感兴趣的:(JAVA反射)