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对象
1 2 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构造方法对象
1 2 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成员变量对象
1 2 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成员方法对象
1 2 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