简单概述
反射:将类的各个组成部分封装为其他对象,这就是反射机制,举例来说在一个java实体类当中,有
类名、成员变量、构造方法、成员方法,而反射封装的各个组成部分就是这些对象。
如下图:java在计算机中经历的三个阶段,也对应着创建反射的三种方式。
创建反射的三种方式
- Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象,它对应的就是上图的第一阶段(Source源代码阶段)。
- 类名.class:通过类名的属性class获取,对应的是第二阶段(Class类对象阶段)。
- 对象.getClass():getClass()方法是在Object类中定义着,对应的是第三阶段(Runtime运行时阶段)
总结:
同一个字节码文件(.class)在一次程序运行过程中,只会被加载一次,不论通过三种方式的哪一种获取的对象都是同一个,也就是说虽然创建反射有三种方式,但他们之间都是相等的,如下举例;
反射常用属性
1、Field属性(成员变量)
Field[] getFields():获取所有public修饰符的成员变量
Field getField(String name):获取单个指定名称的public修饰符的成员变量
Fields[] getDeclaredFields():获取所有的成员的变量,不考虑修饰符
Fields[] getDeclaredFidld(String name):获取单个指定名称的成员变量,不考虑修饰符
常用操作
1.1:设置值
void set(Object obj,Object value)
1.2:获取值
get(Object obj)
1.3:如果想要访问、修改不是public修饰的成员变量,就需要忽略访问权限修饰符的安全检查,把属 性设置为true即可,也称为暴力反射
setAccessible(boolean flag)
@ToString
public class ReflectDto {
//四种修饰符
public String a0 = "1";
protected String a1 = "2";
String a2;
private String a3;
}
public static void main(String[] args) throws Exception {
//一个实体类对象
ReflectDto dto = new ReflectDto();
//创建Class对象
Class<ReflectDto> dtoClass = ReflectDto.class;
//获取所有的public修饰的成员变量
Field[] fields = dtoClass.getFields();
//获取public修饰的单个成员变量
Field a0 = dtoClass.getField("a0");
//如果不设置a0的属性值,java默认返回的null
System.out.println(a0);
//得到值
Object o = a0.get(dto);
//设置值
a0.set(dto,"李四");
//获取所有的成员变量,不考虑修饰符
Field[] declaredFields = dtoClass.getDeclaredFields();
//获取单个的成员变量,不考虑修饰符
Field a1 = dtoClass.getDeclaredField("a1");
//暴力反射(再去访问不是public修饰的成员变量,需要去忽略访问修饰符的安全检查)
a1.setAccessible(true);
//得到值
Object o1 = a1.get(dto);
//设置值
a1.set(dto,"王五");
}
2、Constructor属性(构造器)
Constructor<?> getConstructors()
Constructor
Constructor<?> getConstructors()
Constructor
setAccessible(boolean flag):暴力反射
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ReflectDto {
public String a0 = "1";
protected String a1 = "2";
int a2;
private String a3;
}
public static void main(String[] args) throws Exception {
//一个实体类对象
ReflectDto dto = new ReflectDto();
//创建Class对象
Class dtoClass = ReflectDto.class;
//获取无参构造方法
Constructor constructor = dtoClass.getConstructor();
//无参构造创建属性的两种方式
Object o = constructor.newInstance();
//如果使用无参构造创建属性,还可以进行简化,Class对象提供了一个Class.newInstance方法
Object reflectDto1 = dtoClass.newInstance();
//获取有参构造方法
Constructor constructor1 = dtoClass.getConstructor(String.class, String.class,int.class,String.class);
//创建对象
Object reflectDto = constructor1.newInstance("张三", "李四",1,"赵柳");
}
3、Method属性(方法对象)
Object invoke(Object obj,Object… args):执行方法
String getName:获取方法名
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ReflectDto{
public String a0 = "1";
protected String a1 = "2";
int a2;
private String a3;
public void eat(){
System.out.println("eat...");
}
public void eat(String param){
System.out.println("eat..."+param);
}
private void eat2(){
System.out.println("eat2...");
}
}
public static void main(String[] args) throws Exception {
//一个实体类对象
ReflectDto dto = new ReflectDto();
//创建Class对象
Class dtoClass = ReflectDto.class;
Method method = dtoClass.getMethod("eat");
method.invoke(dto);
Method eat = dtoClass.getMethod("eat", String.class);
//真实的对象 实际传递的参数
eat.invoke(dto,"午饭");
/**
* 获取所有public修饰的方法,包括他的父类方法,例如这里的ReflectDto类,他没有继承任何类,
* 所以他的父类是Object,那么getMethods也会把Object的方法获取到。
*/
Method[] methods = dtoClass.getMethods();
for (Method method1 : methods) {
System.out.println(method1);
System.out.println("获取方法名:"+method1.getName());
}
}
4、getName():获取类名
5、注意点
暴力反射在成员变量、构造器和方法中都能使用。