简单概述
反射:将类的各个组成部分封装为其他对象,这就是反射机制,举例来说在一个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)
@ToStringpublic 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默认返回的nullSystem.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@AllArgsConstructorpublic 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@AllArgsConstructorpublic 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、注意点
暴力反射在成员变量、构造器和方法中都能使用。
