反射

反射

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

用途: 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

注意: 有关反射的类都在java.lang.reflect包下

实例前提

例如我们有一个类:

后面代码都是根据下面的Reflect类进行

package cn.test.reflection; // 包

public class Reflect {
    // 成员属性
    public String name; // 公有
    private int age; // 私有
    
    // 普通方法
    public void show() { // 公有
        System.out.println("show()...");
    }
    private void show2(String name, int age) { // 私有
        System.out.println("show2()...");
        System.out.println(name);
        System.out.println(age);  
    }
    
    // getter,setter,toString,有参无参构造等....

获取Class对象的三种方式

  • Class<?> clazz1 = Reflect.class; (高效,推荐使用)
  • Class<?> clazz2 = Class.forName("cn.tedu.reflection.Reflect");
  • Class<?> clazz3 = new Reflect().getClass();

打印clazz1, clazz2, clazz3输出:

class cn.test.reflection.Reflect
class cn.test.reflection.Reflect
class cn.test.reflection.Reflect

反射构造方法

方法:

返回值 方法 说明
Constructor[] getConstructors(); 返回所有public修饰的构造方法
Constructor getConstructor(Class<?>... parameterTypes) 返回无参构造方法
参数是构造参数的类型,例如
clazz.getConstructor(String.class, int.class);

代码:

Class<?> clazz = Reflect.class;
// 获取所有构造方法
Constructor<?>[] constructors = clazz.getConstructors();
// 遍历构造方法
for (Constructor<?> constructor : constructors) {
    // 输出参数数组
    System.out.println("参数: " + Arrays.toString(constructor.getParameterTypes()));
}

结果:

参数: [int]
参数: [class java.lang.String, int]

反射成员变量

方法:

返回值 方法 说明
Field[] getFields(); 返回所有public修饰的属性
Field getField(String name); 返回指定的public属性,
name是属性名
例如:
clazz.getField("age")

代码:

Class<?> clazz = Reflect.class;
Field[] fields = clazz.getFields();// 获取所有属性
for (Field field : fields) { // 遍历属性
    // 输出属性名和类型
    System.out.println(field.getName() + " : " + field.getType());
}

结果: (只能获取public的属性)

name : class java.lang.String

反射成员方法

返回值 方法 参数
Method[] getMethods() 返回所有public修饰的方法
Method getMethod(String name, Class<?>... parameterTypes) 返回指定的方法,
name是方法名,
后面的参数是方法的参数类型.例如clazz.getMethod("show2", String.class, int.class);

代码:

Class<?> clazz = Reflect.class;
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.println("方法名: " + method.getName());
    System.out.println("参数: " + Arrays.toString(method.getParameterTypes()));
    System.out.println("返回值: " + method.getReturnType());
    System.out.println("-------------------------------------");
}

结果:

方法名: toString
参数: []
返回值: class java.lang.String
-------------------------------------
方法名: getName
参数: []
返回值: class java.lang.String
-------------------------------------
方法名: setName
参数: [class java.lang.String]
返回值: void
-------------------------------------
...
// 等等...(包括Object)的方法

反射创建对象

返回值 方法 说明
T (泛型) newInstance() 创建对象(调用无参构造)

使用Class创建对象

代码:

Class<?> clazz = Reflect.class;
// 创建对象
Reflect r1 = (Reflect) clazz.newInstance();

// 使用对象的方法
r1.setAge(1);
r1.setName("张三");
System.out.println(r1);

结果:

Reflect{name='张三', age=1}

使用指定构造器创建

代码:

Class<?> clazz = Reflect.class;
// 获取指定构造器
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
// 创建对象
Reflect r2 = (Reflect) constructor.newInstance("李四", 44);
System.out.println(r2);

结果:

Reflect{name='李四', age=44}

反射private属性

反射private的属性可用于反射普通属性

私有属性必须设置setAccessible(true);, 设置为true才能进行访问private的

方法:

返回值 方法 说明
Field getDeclaredField(String name) 返回指定的属性, name是属性名
Field[] getDeclaredFields() 返回所有属性

代码:

// 获取Class对象
Class<?> clazz = Reflect.class;
// 暴力反射
Field age = clazz.getDeclaredField("age");
// 获取类型
System.out.println(age.getType().getName()); // int
// 设置私有可见, 否则还是无法访问私有的属性值
age.setAccessible(true);
// 设置私有变量值
Object obj = clazz.newInstance();
age.set(obj, 2);
// 获取私有变量的值
System.out.println(age.get(obj));

结果:

int
2

反射private方法

反射private的方法可用于反射普通方法

私有属性必须设置setAccessible(true);, 设置为true才能进行访问private的

方法:

返回值 方法 说明
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取指定的方法, name是方法名
例如:clazz.getDeclaredMethod("show2", String.class, int.class);
Method[] getDeclaredMethods() 获取所有的方法

代码:

// 获取Class独享
Class<?> clazz = Reflect.class;
// 暴力反射
// 第一个参数是方法名,
// 第二个参数是这个方法需要啥类型的参数
Method show2 = clazz.getDeclaredMethod("show2", String.class, int.class);

// 设置访问权限, --私有可见.  否则无法访问private修饰的方法
show2.setAccessible(true);

// 让方法执行起来
// 第一个参数是, 要执行那个对象的方法
// 第二个参数, 要给方法传入什么实参
Object obj = clazz.newInstance();
show2.invoke(obj, "jack", 20);

结果:

show2()...jack : 20
jack
20
posted @ 2020-05-27 09:12  zpk-aaron  阅读(221)  评论(0编辑  收藏  举报