什么是反射(源码+注释)快速搞定

反射

(详解都在代码注释里)

1. 何为反射

相信大家都 new 过对象,然后去操作类内的成员方法,成员变量,构造方法,不过这些操作都是静态的,今天我们要了解的反射就是获取类,通过普通手段或暴力手段获或变量和方法,再实例化,进行操作,这些都是可以在程序运行时操作,为热加载。

2. 反射的作用

JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

3. 反射获取Class的三种方式
3.1 先定义一个Worker 类
package com.xcx.reflect;
// 这里只写了一部分方法
public class Worker {
    // 成原变量 Field
    private int id;
    private String name;
    
    //构造方法 Constructor
    public Worker() {}
    
    //成员方法 Method
    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }
}
3.2 main 函数实现获取
package com.xcx.reflect;

public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一种方式 这里我们会遇到报错,只需要抛出异常即可
        Class<?> cls1 = Class.forName("com.xcx.reflect.Worker");
        // 第二种方式
        Class<Worker> cls2 = Worker.class;
        // 第三种方式,需要实例化 Worker 对象
        Worker worker = new Worker();
        Class<? extends Worker> cls3 = worker.getClass();
        
        // 直接展示,得到的反射对象是否一样
        System.out.println(cls1 == cls2);
        System.out.println(cls2 == cls3);
        System.out.println(cls1 == cls3);
        // 输出结果是三个true
    }
}
4. 通过 Class 对象获取 Constructor 构造方法对象

getConstructors,getDeclaredConstructors, getConstructor, getDeclaredConstructor

注:以 s 结尾为获取多个方法,以 Declared 开头为暴力获取私有方法
		// 此方法获取类内所有的构造方法不包含私有构造方法
        Constructor<?>[] constructors = cls1.getConstructors();
        // (暴力获取)此方法获取类内,包括私有构造方法在内的所有构造方法
        Constructor<?>[] declaredConstructors = cls1.getDeclaredConstructors();
        // (★ 最常用)此方法获取了公共的有参构造方法,这里会有异常,抛出即可
        Constructor<?> constructor = cls1.getConstructor(int.class, String.class);
        // (暴力获取)此方法获取了私有的有参构造方法
        Constructor<?> declaredConstructor = cls1.getDeclaredConstructor(String.class);
    	
4.1 Constructor 对象实例化对象操作

对非私有构造方法实例化

/* 实例化对象操作,这里会报错,同样抛出即可,本来得到 Object 类,需要强制类型转换一下,不强转也没事,这里强转就是为了告知实际类型就是 Worker 类
*/
Worker o1 = (Worker)constructor.newInstance(10, "张三");
// 输出展示 Person [id=10, name=张三, test=10]

对私有化构造方法实例化

私有化构造方法对象 实例化需要调用 void setAccessible(boolean flag);

参数设置为 true;

// 设置权限,可以对私有化构造方法进行实例化
declaredConstructor.setAccessible(true);
// 得到权限后,实例化
Worker o2 = (Worker)declaredConstructor.newInstance("李四");
// 输出展示 Person [id=0, name=李四, test=10]
// 若没有给权限则报错 Exception in thread "main" java.lang.......
5. 反射操作核心 - Method

这里获取方法Method与获取Constructor构造方法类似,主要注意方法内部参数形式

4.1 通过 Class 对象获取对应的 Method 成员方法对象
		// 此方法获取类内所有公共成员方法
        Method[] methods = cls1.getMethods();
        // 【暴力获取】 此方法获取类内,包括私有成员方法的所有成员方法
        Method[] declaredMethods = cls1.getDeclaredMethods();
        /*
        【★ 核心方法】
        此方法获取类内, 一个公共成员方法(必须提供方法名,参数类型,参数类型,...... )
         public void game(String name) {
                System.out.println("玩" + name);
           }
         */
        Method method = cls1.getMethod( "game", String.class);

        /*
        【暴力获取】
        此方法获取类内, 一个私有成员方法(必须提供给方法名,参数类型, 参数类型,......)
        private void testPrivate(String str) {
                System.out.println("吃" + str);
           }
         */
        Method declaredMethod = cls1.getDeclaredMethod("testPrivate" , String.class);
4.2 Method 成员方法对象执行对应方法操作

注重 : 方法名,参数类型,参数个数

	    // 实例化对象
        Object o = cls1.getConstructor().newInstance();
        // 非私有化成员方法 ,输出结果: 玩吃鸡
        method.invoke(o,"吃鸡");
        System.out.println();
        // 私有化成员方法赋予操作权限之后操作,这里与 Constructor内容 执行相似
        declaredMethod.setAccessible(true);
        // 输出结果: 吃饺子
        declaredMethod.invoke(o, "饺子");
5. 反射操作数据存储和获取 - Field

注重: 成员变量名

5.1 通过 Class 对象获取对应的 Field 成员变量对象
	    // 获取类内所有非私有化成员变量对象数组
        Field[] fields = cls1.getFields();
        // 【暴力反射】获取类内所有成员变量对象数组,包括私有化成员变量对象
        Field[] declaredFields = cls1.getDeclaredFields();
        // 根据指定的成员变量名称,获取对应的非私有化成员变量对象,这里会报错,直接抛出异常
        Field name = cls1.getField("name");
        //【★ 重点方法】【暴力反射】根据指定的成员变量名称,获取对应的成员变量对象,包括私 有化成员变量
        Field age = cls1.getDeclaredField("age");
5.2 Field 对象操作获取数据和赋值数据
// 实例化操作
        Object o3 = cls1.getConstructor().newInstance();
        // 给公有 test 赋值,不需要赋予权限
        test.set(o3,20);
        System.out.println(test.get(o3));
        // 这里用了另一种赋予权限操作 也可以  age.setAccessible(true); 下面这一种可以同时赋予多个权限
        AccessibleObject.setAccessible(new AccessibleObject[]{id, name}, true);
        // 【★ 重点方法】 调用 void setAccessible(boolean flag); 给 私有化 id 赋值
        id.set(o3, 1);
        // 给获取权限的 私有化 name 赋值
        name.set(o3, "青轴侠");
        System.out.println(id.get(o3));
        System.out.println(name.get(o3));
6. 再提一嘴暴力反射权限问题解决

对应方法

void setAccessible(boolean flag); // 重点方法 ★

反射操作中 Constructor, Method ,Field 对象都可以调用该方法解决 私有化反射对象权限操作问题

参数提供为 true 当前私有化构造方法对象有对应的操作权限。

public static void setAccessible(AccessibleObject[] array, boolean flag) // 重点方法 ★

AccessibleObject 类工具方法,所需参数是 AccessibleObject 数组和对应的权限标记,flag 通常为 true。

Field Method Constructor 都是 AccessibleObject 子类

7.小结

三种方式获取Class

get(变量,构造方法,成员方法)// 普通获取

get Declear (变量,构造方法,成员方法)// 暴力获取

实例化

用方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值