1、什么是反射
反射是一种在运行时动态地获取和操作对象、类、方法以及属性的机制。它允许程序在运行时检测和使用类的信息,包括类的属性、方法和构造函数等。通过反射,可以在运行时通过类名获取类的实例、调用类的方法、获取和设置类的属性,以及动态地创建对象和调用类的私有方法等。
使用反射,可以在不依赖具体类的情况下进行操作,从而实现一些灵活性和动态性的需求。比如在框架开发或者动态加载类的场景下,反射可以帮助我们通过类名字符串来加载和使用类,而不需要提前编译时知道类的具体信息,从而扩展了程序的灵活性。在一些工具类库和框架中,例如JUnit、Spring等,反射也广泛应用于实现一些通用的功能和操作。
Java中的反射API位于java.lang.reflect包中,提供了Class、Field、Method等类和接口,用于获取和操作类的信息。通过这些类和接口,我们可以获取类的构造函数、字段、方法等信息,并进行相应的操作,例如创建对象、调用方法、修改字段的值等。反射虽然强大,但也增加了一定的复杂性和性能开销,因此在使用时需要权衡使用场景和影响。
2、反射的优缺点
优点:
- 动态性:反射提供了在运行时动态地获取和操作对象、类、方法等的能力。它使得程序能够在运行时动态地获取和使用类的信息,而不需要在编译时就确定具体的类型。这种动态性使得反射在一些框架和工具的开发中特别有用。
- 灵活性和可扩展性:反射允许程序在运行时根据需要对类进行操作。它可以用于动态创建对象、调用方法、获取和修改属性的值等。这种灵活性和可扩展性使得反射在一些场景下能够适应不同的需求并实现更高级的功能。
缺点:
- 性能开销:由于反射需要在运行时动态地获取和操作类的信息,它通常比直接使用静态编译时的方法调用更加耗费性能。反射涉及的方法调用、类型转换和访问检查等都需要一定的开销,可能会导致程序的执行效率降低。
- 安全问题:反射可以绕过一些访问控制机制,例如私有方法和字段的访问。在一些安全敏感的环境中,滥用反射可能会导致安全漏洞。因此,使用反射时需要谨慎并遵循安全最佳实践。
- 编码复杂性:反射的使用需要通过一些反射API来获取和操作类的信息,这些API相对复杂,需要额外的代码来处理异常和类型转换。这可能会增加代码的复杂性和维护成本。
综上所述,反射在一些动态和灵活的场景中能够提供许多优势,但也需注意其性能开销、安全问题和编码复杂性。在使用反射时,需要根据具体的应用场景权衡利弊,并遵循最佳实践来确保代码的可靠性和性能效率。
3、反射解剖
反射允许对成员变量,成员方法和构造方法的信息进行编程访问
4、获取Class的4种方式
1. 知道具体类的情况下可以使用:
Class aClass2 = A.class;
2. 通过 Class.forName()
传入类的全路径获取:
Class aClass = Class.forName("com.example.springboot.reflect.A");
3. 通过对象实例instance.getClass()
获取:
A a = new A(); Class aClass1 = a.getClass();
4. 通过类加载器xxxClassLoader.loadClass()
传入类路径获取:
Class aClass3 = ClassLoader.getSystemClassLoader().loadClass("com.example.springboot.reflect.A");
1、创建一个我们要使用反射操作的类 TargetObject
。
public class TargetObject { private String value; public TargetObject() { value = "海绵宝宝"; } public void publicMethod(String s) { System.out.println("我爱 " + s); } private void privateMethod() { System.out.println("它的名字是 " + value); } }
2、使用反射操作这个类的方法以及参数
import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { // 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例 Class<?> aClass = Class.forName("com.example.springboot.reflect.TargetObject"); TargetObject targetObject = (TargetObject) aClass.newInstance(); // 获取 TargetObject 类中定义的所有方法 Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod.getName()); } // 获取指定方法并调用 Method publicMethod = aClass.getDeclaredMethod("publicMethod", String.class); publicMethod.invoke(targetObject, "派大星"); // 获取指定参数并对参数进行修改 Field value = aClass.getDeclaredField("value"); // 为了对类中的参数进行修改我们取消安全检查 value.setAccessible(true); value.set(targetObject, "海绵宝宝"); // 调用private方法 Method privateMethod = aClass.getDeclaredMethod("privateMethod"); // 为了调用private方法我们取消安全检查 privateMethod.setAccessible(true); privateMethod.invoke(targetObject); } }
3、常用的方法
get:获取
set:设置
Constructor:构造方法
Parameter:参数
Field:成员变量
Modifiers:修饰符
Method:方法
Declared:私有的
参考文章: