反射
反射
定义: 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