一、初识反射机制
1.1 反射机制概述
JAVA 语言是一门静态语言,对象的各种信息在程序运行时便已经确认下来了,内部结构是不可变的。所以当程序在运行时,我们是无法获取对象中的信息的,但是Java 语言推出了对应解决办法--反射机制。反射机制可以动态的获取类对象的属性和方法,这便给Java语言添加了一些“灵活性”,使其成为了“准动态语言”。
JAVA 语言是先编译在运行的语言,所以程序中的对象属性在编译期便已经敲定了,不会再发生改变,但是通过反射机制可以实现属性的改变和获取。
1.2 反射机制概念
JAVA 语言正常想要获取对象一般是通过将类的完整包路径实例化之后获得的。但是通过反射机制的 getClass() 可以通过对象去反向获取类的完整包路径。
1.3 Java反射机制提供的功能
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类所具有的成员变量和方法在运行时获取泛型信息
-
在运行时调用任意一个对象的成员变量和方法
-
在运行时处理注解
-
生成动态代理
1.4 反射机制的优点和缺点
-
优点: 可以实现动态创建对象和编译,体现出很大的灵活性
-
缺点: 对程序的性能有影响。使用反射基本上是一种解释性操作,相当于给 JVM 去解释一些要求,然后 JVM 通过这个要求去执行相关的操作。这类操作总是慢于直接执行相同的操作。
二、反射机制相关的 API
-
反射
动态加载对象。在运行状态中,对于任何一个类,能够获取这个类的所有属性和方法,对于一个对象,能够调用它的的任意一个属性和方法,这种动态获取类的内容和动态调用对象的方法称为反射机制。 -
通过反射机制相关的API就可以获取任何Java类的包括属性、方法、构造器、修饰符等信息。元素不必在JVM运行时进行确定,反射可以使得它们在运行时动态地进行创建或调用。
JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
-
反射机制相关的 API
-
Class类:代表一个类
-
常用方法:
-
public static Class<?> forName(String className) : 通过 Class 直接调用,根据传入的类路径加载并将对应的类初始化
-
public Constructor<?>[] getConstructors(): 获取对象中全部的构造函数,存储进 Constructor[] 并将数组返回
-
public Field[] getDeclaredFields(): 获取对象中全部的变量,存储进 Field[] 并将数组返回
-
public Method[] getDeclaredMethods(): 获取对象中全部的方法,存储进 Method[] 并将数组返回
-
-
-
Constructor类:代表类的构造方法
-
常用方法:
- public T newInstance(Object … initargs): 搭配 Class 类的 getConstructors(),获取对应的构造方法
-
-
Field类:代表类的成员变量
-
Method:代表类的方法
-
-
反射 API 代码示例
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 反射 */ public class reflect { //运行时获取已知名称的类或已有对象相关信息,包括类的方法,属性,父类等信息 //JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中 int m; public reflect() { System.out.println("无参构造方法"); } public reflect(String k) { System.out.println("一个参数构造方法---" + k); } public reflect(String k, Integer v) { System.out.println("两个参数构造方法---" + k + ":" + v); } public void fun1() { System.out.println("无参数成员方法"); } public void fun2(String k) { System.out.println("一个参数成员方法---" + k); } public void fun3(String k, Integer v) { System.out.println("两个参数成员方法---" + k + ":" + v); } public static void main(String[] args) throws Exception{ //加载并初始化指定的类reflect Class classInfo = Class.forName("com.proxy.reflect");//代表类名是A System.out.println("类reflect构造函数如下所示:"); Constructor[] constructors = classInfo.getConstructors(); for (int i = 0; i < constructors.length; i++) { System.out.println(constructors[i].toString()); } //获得类的所有变量 System.out.println("\n类reflect变量如下:"); Field[] declaredFields = classInfo.getDeclaredFields(); for (int i = 0; i < declaredFields.length; i++) { System.out.println(declaredFields[i].toString()); } //获得类的所有方法 System.out.println("\n类reflect方法如下:"); Method[] declaredMethods = classInfo.getDeclaredMethods(); for (int i = 0; i < declaredMethods.length; i++) { System.out.println(declaredMethods[i].toString()); } //=========================================构造方法=============================== //第一种方式 //Constructor[] constructors = classInfo.getConstructors(); //调用两个参数构造方法 constructors[0].newInstance(new Object[]{"Hello",2023}); //调用一个参数构造方法 constructors[1].newInstance(new Object[]{"Hello"}); //调用无参构造方法 constructors[2].newInstance(); //第二种方式 //调用无参构造方法 Constructor constructor = classInfo.getConstructor(); constructor.newInstance(); //调用一个参数构造方法 constructor = classInfo.getConstructor(new Class[]{String.class}); constructor.newInstance(new Object[]{"Hello"}); //调用两个参数构造方法 constructor = classInfo.getConstructor(new Class[]{String.class, Integer.class}); constructor.newInstance(new Object[]{"Hello", 2023}); //=========================================成员方法============================ //调用无参构造函数,生成新的实例对象 Object obj = classInfo.getConstructor().newInstance(); //调用无参成员函数 Method method1 = classInfo.getMethod("fun1"); //通过实例对象进行方法的实例化 method1.invoke(obj); //调用一个参数成员函数 Method method2 = classInfo.getMethod("fun2", String.class); method2.invoke(obj, new Object[]{"Hello"}); //调用两个参数成员函数 Method method3 = classInfo.getMethod("fun3", String.class, Integer.class); method3.invoke(obj, new Object[]{"Hello", 2023}); } }
-
执行结果