【Java基础】Java反射机制

2022-05-12 20:00:00 浏览数 (1)

本篇目录

1- 反射是什么? 2- 获取类对象的三种方式 3- 通过类对象获取该类的所有方法并调用 4- 通过类对象调用指定私有方法 5- 通过类对象获取所有属性并输出 6- 通过类对象获取指定属性并修改属性的值 7- 通过类对象获取指定构造方法并调用

1 反射是什么?

反射机制是Java中的一个高级特性,通过反射机制,我们可以操作任意一个类,包括获取这个类的所有属性和方法,包括私有属性和构造方法。

在我们日常开发中其实也经常接触到反射,比如我们经常使用的IDEA,当我们调用一个方法时,会动态的获取该方法的参数以及参数名称,各位就不好奇这是怎么做到的吗?

再比如Java中封神的框架Spring系列,也是大规模的使用了反射机制,最经典的就是使用Xml的方式配置Bean时需要设置全限定类名才能成功的注入Bean,为什么呢?

本篇内容我在JDK11的运行环境下以几个反射使用例子带大家学习一下反射的使用方式。

2 获取类对象的三种方式

这里的类对象和实例对象不是一个概念。确切的说,类对象是Class类的实例对象,在 java.lang 包下有一个类名为Class.java的Java文件,而我们现在要获取的类对象其实就是获取Class实例对象。下面是三种获取一个类的Class对象的方式:

第一种:通过类的实例对象获取Class对象

代码语言:javascript复制
// 实例化Test对象
Test test=new Test();
// 获取Class对象
Class c=test.getClass();

第二种:通过类名直接获取Class对象

代码语言:javascript复制
// 获取Class对象
Class c=Test.class;

第三种:通过类的全限定类名获取Class对象

代码语言:javascript复制
// 利用Class类的静态方法获取指定全限定类名的Class对象
Class c=Class.forName("demo.Test");

如上就是获取类的Class对象三种方式,第三种可能大家在学习JDBC时都有接触,其实就是通过全限定类名去获取指定类的Class对象。

多代码预警,每一行代码都有注释,以帮助理解

3 通过类对象获取该类的所有方法并调用

上一段我们已经获取到了该类的类对象了,接下来就是对于类对象的作用了。

这里我们假设Test类有两个public方法和一个private方法,我们利用类对象获取到这些方法,并且调用它。

代码语言:javascript复制
// 获取该类的Class对象
Test test = new Test();
Class<? extends Test> clazz = test.getClass();
// 获取该类的所有方法包括私有方法
Method[] methods = clazz.getDeclaredMethods();
// 遍历打印方法名
for (Method method : methods) {
    // 设置私有方法访问权限为可访问
    method.setAccessible(true);
    // 调用这个方法
    method.invoke(test, null);
}

这里比较关键的两个方法,分别是setAccessible方法和invoke方法。

setAccessible方法:可以设置私有方法或属性的访问权限为可访问,让我们可以修改和调用,没有这一步,我们就只能调用公共方法。

invoke方法:参数obj为当前类的实例对象(不是类对象),第二个参数为方法的参数列表。该方法可以实现执行目标方法。

4 通过类对象调用指定私有方法

代码语言:javascript复制
// 创建该类的实例对象
Test test = new Test();
// 获取该类的Class对象
Class<? extends Test> clazz = test.getClass();
// 获取指定方法
Method test3 = clazz.getDeclaredMethod("test3", null);
// 设置该方法的权限为可访问
test3.setAccessible(true);
// 调用该方法
test3.invoke(test, null);

5 通过类对象获取所有属性并输出

代码语言:javascript复制
// 创建该类的实例对象
Test test = new Test();
// 获取该类的Class对象
Class<? extends Test> clazz = test.getClass();
// 获取该类的所有属性,包括私有属性
Field[] declaredFields = clazz.getDeclaredFields();
// 遍历属性
for (Field field : declaredFields) {
    // 设置属性的访问权限为可访问
    field.setAccessible(true);
    // 打印该属性当前的值
    System.out.println(field.get(test));
}

6 通过类对象获取指定属性并修改属性的值

代码语言:javascript复制
// 创建该类的实例对象
Test test = new Test();
// 获取该类的Class对象
Class<? extends Test> clazz = test.getClass();
// 获取指定名称的属性
Field test1 = clazz.getDeclaredField("test1");
// 设置该属性的访问权限为允许访问
test1.setAccessible(true);
// 修改该属性的值
test1.set(test, "修改后的值");
// 打印该属性的值
System.out.println(test1.get(test));

7 通过类对象获取指定构造方法并调用

代码语言:javascript复制
// 获取类对象
Class<Test> clazz = Test.class;
// 获取指定构造方法
Constructor<Test> constructor = clazz.getConstructor(null);
// 使用该构造方法实例化对象
Test test = constructor.newInstance();
// 使用实例对象调用方法
test.test4();

0 人点赞