Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。
Java的类加载
- 编译:java文件编译后生成class字节码文件
- 类加载机制:JVM把class文件加载到内存,并对数据进行校验、准备、解析、初始化,最终形成JVM可以直接使用的Java类型的过程。
  Java的反射机制Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取、调用对象方法的功能称为Java语言的反射机制。
Java的反射就是利用上面第二步加载到JVM中的.class文件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
总体来说,反射就是把java类中的各种成分映射成一个个的Java对象,并且可以进行操作。例如一个类有成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
反射的必要性:
1.反射机制是很多java框架的基石。
2.有时候要适应某些需求,Java类里面不一定能直接调用另外的方法,这时候也可以通过反射机制来实现。
反射的缺点:
反射的代码比正常调用的代码更多,性能也慢,所以应避免使用反射。
Java反射获取对象
Class类:代表一个类
Constructor类:代表类的构造方法
Field类:代表类的成员变量(类的属性)
Method类:代表类的方法
1.获取Class对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 获取Class对象的三种方式1.通过对象获取      对象名.getClass()
 2.通过类名获取      类名.class
 3.通过全类名获取    Class.forName(全类名)
 
 三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。
 
 
 Class stuClass = Class.forName("com.example.Student");
 System.out.println(stuClass.getName());
 
 | 
2.获取Constructor构造方法对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 1.获取构造方法:
 1).批量的方法:
 public Constructor[] getConstructors():所有"公有的"构造方法
 public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
 
 2).获取单个的方法,并调用:
 public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 
 调用构造方法:
 Constructor-->newInstance(Object... initargs)
 
 2.newInstance是 Constructor类的方法(管理构造函数的类)
 api的解释为:newInstance(Object... initargs)
 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
 它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用
 
 3.Constructor con = clazz.getConstructor(null);
 1)因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
 2)返回的是描述这个无参构造函数的类对象。
 
 
 Class clazz = Class.forName("com.example.Student");
 Constructor  con = clazz.getDeclaredConstructor(char.class);
 System.out.println(con);
 
 con.setAccessible(true);
 Object obj = con.newInstance('男');
 System.out.println("obj = " + obj);
 
 
 | 
3.获取Field成员变量对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | 获取成员变量并调用:1.批量的
 Field[] getFields():获取所有的"公有字段"
 Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
 2.获取单个的:
 public Field getField(String fieldName):获取某个"公有的"字段;
 public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
 
 设置字段的值:
 Field --> public void set(Object obj,Object value):
 第一个参数:要传入设置的对象,第二个参数:要传入实参
 参数说明:
 1.obj:要设置的字段所在的对象;
 2.value:要为字段设置的值;
 
 
 Class stuClass = Class.forName("com.example.Student");
 Field f = stuClass.getDeclaredField("name");
 
 Object obj = stuClass.getConstructor().newInstance();
 f.setAccessible(true);
 
 f.set(obj, "刘德华");
 
 Student stu = (Student)obj;
 System.out.println("验证姓名:" + stu.name);
 
 | 
4.获取Method成员方法对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | 获取成员方法并调用:1.批量的:
 public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
 public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
 2.获取单个的:
 public Method getMethod(String name,Class<?>... parameterTypes):
 参数:
 name : 方法名;
 Class ... : 形参的Class类型对象
 public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
 
 调用方法:
 Method --> public Object invoke(Object obj,Object... args):
 参数说明:
 obj : 要调用方法的对象;
 args:调用方式时所传递的实参;
 
 
 Class stuClass = Class.forName("com.example.Student");
 Method m = stuClass.getMethod("show1", String.class);
 System.out.println(m);
 
 
 Object obj = stuClass.getConstructor().newInstance();
 Object result = m.invoke(obj, "刘德华");
 System.out.println("返回值:" + result);
 
 | 
[1] https://www.cnblogs.com/tech-bird/p/3525336.html