一、什么是反射
- 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的 方法的功能就称为java语言的反射机制。
二、反射的主要用途
反射是框架设计的灵魂
三、反射框架提供的功能
- 判断任意一个对象所属的类;
- 构造任意一个类的对象;
- 判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
- 调用任意一个对象的方法
四、反射的运用
1. 获得Class对象(3种方式)
1.使用Class类的forName静态方法
Class<?> aClass1 = Class.forName("类的全路径");
2.调用某个对象的getClass()获得
User user = new User();
Class<? extends User> aClass2 = user.getClass();
3.通过某一个对象获得
Class<User> aClass3 = User.class;
2. 创建实例(2种方式)
1. 通过使用Class对象的newInstance()方法创建实例
Object o1 = aClass1.newInstance();
2. 先获取构造器,通过构造器创建实例
Constructor<?> constructor1 = aClass1.getConstructor();
Object o2 = constructor1.newInstance();
注:
aClass1.getConstructor(Class<?>... parameterTypes)可指定不同参数构造方法
如:
//获取参数为String构造器实例
Constructor<?> constructor1 = aClass1.getConstructor(String.class);
Object o2 = constructor1.newInstance("你好呀");
或
//获取参数类型为int的构造器实例
Constructor<?> constructorInt1 = aClass1.getConstructor(int.class);
Object o3 = constructorInt1.newInstance(18);
3. 判断是否为某个类的实例(用于检查给定对象是否是具有此Class表示的对象的实例)
boolean instance = aClass1.isInstance(o2); //结果为 true
boolean instance = aClass1.isInstance("abc"); //结果为 false
4. 获取类的方法
1. 获取方法返回类或接口声明的所有方法,包括公共,受保护,默认,私有方法,不包括继承方法
Method[] declaredMethods = aClass1.getDeclaredMethods();
2. 获取所有公有方法(public),包括继承公用方法
Method[] methods = aClass1.getMethods();
3. 获取指定的方法,第一个参数为方法名,第二个为参数类型
Method getUserName = aClass1.getDeclaredMethod("getUserName", String.class);
4. 获取指定的方法,第一个参数为方法名,第二个为参数类型
Method getUserAge = aClass1.getMethod("getUserAge", int.class);
5. 方法的调用
//第一个参数为调用底层方法的对象,第二个参数为调用方法的参数
Object invoke = getUserName.invoke(o1,"哇呀呀呀");
System.out.println(invoke);//结果为 name:哇呀呀呀
6. 获取类的成员变量
1. 获取公有的成员变量
Field[] fields = aClass1.getFields();
2. 获取所有已声明的成员变量,不能得到父类的成员变量
Field[] declaredFields = aClass1.getDeclaredFields();
3. 获取公有成员变量,指定属性名
Field phone = aClass1.getField("phone");
4. 获取所有已声明的成员变量,指定属性名
Field name = aClass1.getDeclaredField("name");
7. 设置属性值
//获取公有成员变量,指定属性名
Field phone = aClass1.getField("phone");
phone.set(o1,"123456789");
//获取所有已声明的成员变量,指定属性名
Field name = aClass1.getDeclaredField("name");
//当属性为私有时,要设置此属性为true,否则会报错哦
name.setAccessible(true);
name.set(o1,"小小的愿望");
System.out.println(obj); //结果为 User(name=小小的愿望, age=0, phone=123456789)
五、反射的注意事项
- 反射比较消耗性能,所以避免在经常执行的代码中使用反射。
- 反射要求在没有安全限制的环境中运行,如果一个程序对安全性提出要求,最好不要使用反射。
- 反射允许代码执行一些通常不被允许的操作,所以使用反射有可能导致意想不到的后果。反射代码破坏了Java程序结构的抽象性,所以当程序运行的平台发生变化时,由于抽象的逻辑结构不能被识别,代码产生的效果与之前会产生差异。
六、 User类
package com.yf.business.Test;
import lombok.Data;
@Data
public class User {
private String name;
private int age;
public String phone;
public String getUserName(String name){
return "name:"+name;
}
public String getUserAge(int age){
return "age:"+age;
}
private String getUser(String name, int age){
return "name:"+name+",age:"+age;
}
//全参构造
public User(String name, int age,String phone) {
this.name = name;
this.age = age;
this.phone = phone;
}
public User(String name){
this.name = name;
this.age = 8;
}
public User(int age){
this.name = "hello";
this.age = age;
}
//无参构造
public User(){
}
}