在 Java 中,使用反射来创建对象、创建数组、调用方法

  假设已有下面的类:

  • 示例类:Demo
package org.wangpai.reflectionuses.model;

/**
 * @since 2022-9-11
 */
public class Demo {
    private FieldA fieldA;

    private FieldB fieldB;

    /**
     * 无参构造器
     *
     * @since 2022-9-11
     */
    public Demo() {
        System.out.println("无参构造器 Demo() 被调用");
        System.out.println();
    }

    /**
     * 有参构造器
     *
     * @since 2022-9-11
     */
    public Demo(ParaA paraA, ParaB paraB) {
        System.out.println("构造器 Demo(ParaA paraA, ParaB paraB) 被调用");
        System.out.println("  > paraA:" + paraA);
        System.out.println("  > paraB:" + paraB);
        System.out.println();
        this.fieldA = new FieldA(paraA.toString());
        this.fieldB = new FieldB(paraB.toString());
    }

    /**
     * 公有静态方法
     *
     * @since 2022-9-11
     */
    public static void publicStaticFun(ParaA paraA, ParaB paraB) {
        System.out.println("公有静态方法 publicStaticFun(ParaA paraA, ParaB paraB) 被调用");
        System.out.println("  > paraA:" + paraA);
        System.out.println("  > paraB:" + paraB);
        System.out.println();
    }

    /**
     * 私有有静态方法
     *
     * @since 2022-9-11
     */
    private static void privateStaticFun(ParaA paraA, ParaB paraB) {
        System.out.println("私有有静态方法 privateStaticFun(ParaA paraA, ParaB paraB) 被调用");
        System.out.println("  > paraA:" + paraA);
        System.out.println("  > paraB:" + paraB);
        System.out.println();
    }

    /**
     * 公有非静态方法
     *
     * @since 2022-9-11
     */
    public void publicFun(ParaA paraA, ParaB paraB) {
        System.out.println("公有方法 publicFun(ParaA paraA, ParaB paraB) 被调用");
        System.out.println("  > paraA:" + paraA);
        System.out.println("  > paraB:" + paraB);
        System.out.println();
    }

    /**
     * 私有非静态方法
     *
     * @since 2022-9-11
     */
    private void privateFun(ParaA paraA, ParaB paraB) {
        System.out.println("私有方法 privateFun(ParaA paraA, ParaB paraB) 被调用");
        System.out.println("  > paraA:" + paraA);
        System.out.println("  > paraB:" + paraB);
        System.out.println();
    }

    /**
     * 公有非静态可变参方法(无前面的固定参数)
     *
     * @since 2022-9-11
     */
    public void publicVarParaFunWithNoFixedPara(ParaA... paraAS) {
        System.out.println("公有可变参方法(无前面的固定参数) publicVarParaFunWithNoFixedPara(ParaA... paraAS) 被调用");
        for (int order = 0; order < paraAS.length; ++order) {
            System.out.println(String.format("  > 可变参参数,第 %d 参数是:", order + 1) + paraAS[order]);
        }
        System.out.println();
    }

    /**
     * 公有非静态可变参方法(有前面的固定参数)
     *
     * @since 2022-9-11
     */
    public void publicVarParaFunWithFixedPara(ParaA paraA, ParaB... paraBs) {
        System.out.println("公有可变参方法(有前面的固定参数) publicVarParaFunWithFixedPara(ParaA paraA, ParaB... paraBs) 被调用");
        System.out.println("  > 固定参数 paraA:" + paraA);
        for (int order = 0; order < paraBs.length; ++order) {
            System.out.println(String.format("  > 可变参参数,第 %d 参数是:", order + 1) + paraBs[order]);
        }
        System.out.println();
    }

    /**
     * 私有非静态可变参方法(无前面的固定参数)
     *
     * @since 2022-9-11
     */
    private void privateVarParaFunWithNoFixedPara(ParaA... ParaAs) {
        System.out.println("私有可变参方法(无前面的固定参数) privateVarParaFunWithNoFixedPara(ParaA... ParaAs) 被调用");
        for (int order = 0; order < ParaAs.length; ++order) {
            System.out.println(String.format("  > 可变参参数,第 %d 参数:", order + 1) + ParaAs[order]);
        }
        System.out.println();
    }

    /**
     * 私有非静态可变参方法(有前面的固定参数)
     *
     * @since 2022-9-11
     */
    private void privateVarParaFunWithFixedPara(ParaA paraA, ParaB... paraBs) {
        System.out.println("私有可变参方法 privateVarParaFunWithFixedPara(ParaA paraA, ParaB... paraBs) 被调用");
        System.out.println("  > 固定参数 paraA:" + paraA);
        for (int order = 0; order < paraBs.length; ++order) {
            System.out.println(String.format("  > 可变参参数,第 %d 参数:", order + 1) + paraBs[order]);
        }
        System.out.println();
    }

    /**
     * @since 2023-8-13
     */
    public void showFields() {
        System.out.println("公有方法 showFields() 被调用");
        System.out.println("  > fieldA:" + this.fieldA);
        System.out.println("  > fieldB:" + this.fieldB);
        System.out.println();
    }
}
  • 字段类:FieldA
package org.wangpai.reflectionuses.model;

/**
 * 参数类 FieldA
 *
 * @since 2023-8-13
 */
public class FieldA {
    private String info;

    /**
     * @since 2023-8-13
     */
    public FieldA() {
        super();
    }

    /**
     * @since 2023-8-13
     */
    public FieldA(String str) {
        super();
        this.info = str;
    }

    /**
     * @since 2023-8-13
     */
    @Override
    public String toString() {
        return this.info;
    }
}
  • 字段类:FieldB
package org.wangpai.reflectionuses.model;

/**
 * 参数类 FieldB
 *
 * @since 2023-8-13
 */
public class FieldB {
    private String info;

    /**
     * @since 2023-8-13
     */
    public FieldB() {
        super();
    }

    /**
     * @since 2023-8-13
     */
    public FieldB(String str) {
        super();
        this.info = str;
    }

    /**
     * @since 2023-8-13
     */
    @Override
    public String toString() {
        return this.info;
    }
}
  • 参数类:ParaA
package org.wangpai.reflectionuses.model;

/**
 * 参数类 ParaA
 *
 * @since 2022-9-11
 */
public class ParaA {
    private String info;

    public ParaA() {
        super();
    }

    public ParaA(String str) {
        super();
        this.info = str;
    }

    @Override
    public String toString() {
        return this.info;
    }
}
  • 参数类:ParaB
package org.wangpai.reflectionuses.model;

/**
 * 参数类 ParaB
 *
 * @since 2022-9-11
 */
public class ParaB {
    private String info;

    public ParaB() {
        super();
    }

    public ParaB(String str) {
        super();
        this.info = str;
    }

    @Override
    public String toString() {
        return this.info;
    }
}

反射访问字段

ParaA paraA = new ParaA("这是 ParaA");
ParaB paraB = new ParaB("这是 ParaB");
Demo demo = new Demo(paraA, paraB);
Field fA = demo.getClass().getDeclaredField("fieldA");
fA.setAccessible(true); // 设置允许反射读写私有字段
FieldA fieldA = (FieldA) fA.get(demo);
System.out.println("fieldA:" + fieldA);
构造器 Demo(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA
  > paraB:这是 ParaB

fieldA:这是 ParaA

反射修改字段

ParaA paraA1 = new ParaA("这是 ParaA1");
ParaB paraB1 = new ParaB("这是 ParaB1");
Demo demo = new Demo(paraA1, paraB1);
FieldA fieldA2 = new FieldA("这是 FieldA2");
Field fA = demo.getClass().getDeclaredField("fieldA");
fA.setAccessible(true); // 设置允许反射读写私有字段
fA.set(demo, fieldA2);
demo.showFields();
构造器 Demo(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA1
  > paraB:这是 ParaB1

公有方法 showFields() 被调用
  > fieldA:这是 FieldA2
  > fieldB:这是 ParaB1

反射创建对象

ParaA paraA = new ParaA("这是 ParaA");
ParaB paraB = new ParaB("这是 ParaB");
Demo demo = Demo.class
        .getConstructor(ParaA.class, ParaB.class)
        .newInstance(paraA, paraB);
构造器 Demo(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA
  > paraB:这是 ParaB

反射调用方法

反射调用公有静态方法

ParaA paraA = new ParaA("这是 ParaA");
ParaB paraB = new ParaB("这是 ParaB");
Demo.class.getMethod("publicStaticFun", ParaA.class, ParaB.class)
        .invoke(null, paraA, paraB);
公有静态方法 publicStaticFun(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA
  > paraB:这是 ParaB

反射调用私有静态方法

ParaA paraA = new ParaA("这是 ParaA");
ParaB paraB = new ParaB("这是 ParaB");
var privateFun = Demo.class.getDeclaredMethod("privateStaticFun", ParaA.class, ParaB.class);
privateFun.setAccessible(true); // 如果此处的类本来就有权限调用用反射调用的方法,则此行代码可以省略
privateFun.invoke(null, paraA, paraB);
私有有静态方法 privateStaticFun(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA
  > paraB:这是 ParaB

反射调用公有非静态方法

  调用上述 Test 对象的可变参私有方法的办法是:

Demo demo = new Demo();
ParaA paraA = new ParaA("这是 ParaA");
ParaB paraB = new ParaB("这是 ParaB");
Demo.class.getMethod("publicFun", ParaA.class, ParaB.class)
        .invoke(demo, paraA, paraB);
无参构造器 Demo() 被调用

公有方法 publicFun(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA
  > paraB:这是 ParaB

反射调用私有非静态方法

Demo demo = new Demo();
ParaA paraA = new ParaA("这是 ParaA");
ParaB paraB = new ParaB("这是 ParaB");
var privateFun = Demo.class.getDeclaredMethod("privateFun", ParaA.class, ParaB.class);
privateFun.setAccessible(true); // 如果此处的类本来就有权限调用用反射调用的方法,则此行代码可以省略
privateFun.invoke(demo, paraA, paraB);
无参构造器 Demo() 被调用

私有方法 privateFun(ParaA paraA, ParaB paraB) 被调用
  > paraA:这是 ParaA
  > paraB:这是 ParaB

反射调用公有非静态可变参方法(无前面的固定参数)

Demo demo = new Demo();
ParaA paraAOne = new ParaA("这是第一个 ParaA");
ParaA paraATwo = new ParaA("这是第二个 ParaA");
ParaA[] paraAs = new ParaA[]{paraAOne, paraATwo};
/**
 * 虽然 paraAs 已经是数组,但此处还是要将可变参数组再封装到一个数组中。
 * 不过,如果固定参数存在时,可以不用再外加数组,改为直接将各个元素列出。
 * 此处因为固定参数不存在,所以需再套一层数组
 */
Demo.class.getMethod("publicVarParaFunWithNoFixedPara", ParaA[].class)
        .invoke(demo, new Object[]{paraAs});
无参构造器 Demo() 被调用

公有可变参方法(无前面的固定参数) publicVarParaFunWithNoFixedPara(ParaA... paraAS) 被调用
  > 可变参参数,第 1 参数是:这是第一个 ParaA
  > 可变参参数,第 2 参数是:这是第二个 ParaA

反射调用私有非静态可变参方法(有前面的固定参数)

Demo demo = new Demo();
ParaA paraA = new ParaA("这是 ParaA");
ParaB paraBOne = new ParaB("这是第一个 ParaB");
ParaB paraBTwo = new ParaB("这是第二个 ParaB");
ParaB[] paraBs = new ParaB[]{paraBOne, paraBTwo};
Demo.class.getDeclaredMethod("publicVarParaFunWithFixedPara", ParaA.class, ParaB[].class)
        .invoke(demo, paraA, paraBs); // 因为固定参数有 1 个及以上,所以此处可以不用数组来包装
无参构造器 Demo() 被调用

公有可变参方法(有前面的固定参数) publicVarParaFunWithFixedPara(ParaA paraA, ParaB... paraBs) 被调用
  > 固定参数 paraA:这是 ParaA
  > 可变参参数,第 1 参数是:这是第一个 ParaB
  > 可变参参数,第 2 参数是:这是第二个 ParaB

反射调用私有非静态可变参方法(无前面的固定参数)

Demo demo = new Demo();
ParaA paraAOne = new ParaA("这是第一个 ParaA");
ParaA paraATwo = new ParaA("这是第二个 ParaA");
ParaA[] paraAs = new ParaA[]{paraAOne, paraATwo};
var privateFun = Demo.class.getDeclaredMethod(
        "privateVarParaFunWithNoFixedPara", ParaA[].class);
privateFun.setAccessible(true);
/**
 * 虽然 paraAs 已经是数组,但此处还是要将可变参数组再封装到一个数组中。
 * 不过,如果固定参数存在时,可以不用再外加数组,改为直接将各个元素列出。
 * 此处因为固定参数不存在,所以需再套一层数组
 */
privateFun.invoke(demo, new Object[]{paraAs});
无参构造器 Demo() 被调用

私有可变参方法(无前面的固定参数) privateVarParaFunWithNoFixedPara(ParaA... ParaAs) 被调用
  > 可变参参数,第 1 参数:这是第一个 ParaA
  > 可变参参数,第 2 参数:这是第二个 ParaA

反射调用私有非静态可变参方法(有前面的固定参数)

Demo demo = new Demo();
ParaA paraA = new ParaA("这是 ParaA");
ParaB paraBOne = new ParaB("这是第一个 ParaB");
ParaB paraBTwo = new ParaB("这是第二个 ParaB");
ParaB[] paraBs = new ParaB[]{paraBOne, paraBTwo};
var privateFun = Demo.class.getDeclaredMethod(
        "privateVarParaFunWithFixedPara", ParaA.class, ParaB[].class);
privateFun.setAccessible(true);
// 因为固定参数有 1 个及以上,所以此处可以不用数组来包装
privateFun.invoke(demo, paraA, paraBs);
无参构造器 Demo() 被调用

私有可变参方法 privateVarParaFunWithFixedPara(ParaA paraA, ParaB... paraBs) 被调用
  > 固定参数 paraA:这是 ParaA
  > 可变参参数,第 1 参数:这是第一个 ParaB
  > 可变参参数,第 2 参数:这是第二个 ParaB

反射创建数组

int arrayLength = 10;
// 注意:这样创建之后,得到的是一个空有长度无内容的空数组,因此,后续使用该数组,还需要依次初始化该数组的各个元素
Demo[] targetArray = (Demo[]) Array.newInstance(Demo[].class.getComponentType(), arrayLength);

反射调用的方法自身可以抛出异常的情形

  如果反射调用的方法本身可以抛出异常,则当其抛出异常时,此异常会被反射“吞掉”,封装成 InvocationTargetException 异常重新抛出。可以使用该封装异常的方法 getTargetException 或 getCause 来获取被吞掉的异常。例如,

try {
    /**
     * 此处为某反射调用代码
     */
} catch (InvocationTargetException exception) {
    Throwable realException = exception.getTargetException();
    if (realException instanceof MyXXXException) {
        throw (MyXXXException) realException;
    } else {
        // TODO:可以选择再抛出 InvocationTargetException 异常,也可以抛出自己想抛出的异常。或者做其它事情。
    }
}

完整源代码

  已上传至 GitHub 中,可免费下载:https://github.com/wangpaiblog/20210715_reflection-sample

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值