• Java 反射


    一、基本介绍

    Java 反射是一种强大的特性,它允许在运行时动态地获取和操作类、对象、字段和方法的信息,可以说是强化版的自省(有点类似于 Python 的自省)。说简单点,就是可以在调用某个类的时候,能够获取和修改这个类一些东西。这也是 Java 被认为是半静态半动态语言的重要原因。

    优点

    • 动态性:反射允许在运行时动态地获取和操作类的信息,而不需要在编译时知道类的具体细节。这使得编写通用的、可扩展的代码变得更加容易。
    • 灵活性:反射提供了一种灵活的方式来处理类、对象、字段和方法。它可以用于实现一些复杂的功能,如依赖注入、ORM(对象关系映射)等。
    • 框架和工具支持:许多框架和工具(如 Spring、Hibernate 等)使用反射来实现它们的功能。反射使得这些框架和工具能够在运行时自动地处理和操作类的信息。

    缺点

    • 性能开销:反射通常比直接调用代码更慢。由于反射涉及到动态解析和调用,它需要更多的时间和资源。因此,在性能敏感的应用程序中,过度使用反射可能会导致性能下降。
    • 安全性问题:反射可以绕过访问控制,访问和修改私有成员。这可能会导致安全漏洞,因此在使用反射时需要谨慎处理,并确保只有授权的代码可以访问敏感信息。
    • 可读性和维护性:由于反射允许在运行时动态地操作类和对象,它可能导致代码更加复杂和难以理解。使用反射的代码可能会缺乏清晰的结构和可读性,从而增加了维护的难度。

    反射是一项强大的特性,但在使用时需要权衡其优点和缺点,并根据具体情况进行选择。在某些情况下,反射是必需的,但在其他情况下,应该谨慎使用以避免潜在的性能和安全问题。简单说,就是用的好,能大大提高程序质量,用的不好,会浪费大量性能且产生安全隐患。

    二、反射相关类

    反射机制里面相关类有 Class、Field、Methods、Paramter 等,这里给出几个做讲解。

    2.1 Class 对象

    Class 类位于 java.lang.Class,不需要我们手动进行导入。得到一个类的 Class 对象的方法有三种,这三种方法得到的 Class 对象是同一个东西。

    2.1.1 类的 getClass 方法

    这种方法适用于已经有对象实例的情况,可以通过对象实例来获取其所属类的 Class 对象。

    1. String str = "Java";
    2. Class cls = str.getClass();
    2.1.2 类的 class 字段

    这种方法适用于已知类名的情况,可以直接在代码中获取该类的 Class 对象。

    1. String str = "Java";
    2. Class cls = String.class;
    2.1.3 Class 的 forName 方法

    这种方法最常用,适用于在运行时动态加载类的情况,可以通过类的全限定名来获取 Class 对象,这样可以在运行时根据需要加载不同的类,但是有可能会抛出 ClassNotFoundException 的异常。

    Class cls = Class.forName("java.lang.String");

    下面的代码分别展示了三种方法,且得到的 Class 对象是同一个东西:

    1. String str = "Java";
    2. Class cls2 = str.getClass(); // 实例的 getClass 方法
    3. Class cls1 = String.class; // 类的 class 属性
    4. Class cls3 = Class.forName("java.lang.String"); // Class 的 forName 方法
    5. System.out.println(cls1 == cls2); // Output: true
    6. System.out.println(cls2 == cls3); // Output: true

    2.2 Field 类

    Field 位于 java.lang.reflect.Field,是需要我们手动导入的,它可以用来获取字段。

    下面是该类的基本方法:

    方法描述
    get(Object obj)返回 obj 对象该字段的值
    set(Object obj, Object value)修改 obj 对象该字段的值为 value
    setAccessible(boolean flag)将该字段的访问修改为 flag(true 可访问,false 不可访问)
    getName()返回该字段的名称
    getType()返回该字段的类型
    getModifiers()返回该字段的修饰符类(不是直接返回修饰符)

    2.3 Method 类

    Method 位于 java.lang.reflect.Method,也是需要我们手动导入的,它可以用来获取方法。

    下面是该类的基本方法:

    方法描述
    getName()返回该方法的方法名
    setAccessible(boolean flag)将该方法的访问修改为 flag(true 可访问,false 不可访问)
    getReturnType()返回该方法的返回类型
    getModifiers()返回该方法的修饰符类(不是直接返回修饰符)
    getParameterTypes()以数组形式返回该方法的参数类型的 Class 对象

    2.4 Modifier 类

    Modifier 位于 java.lang.reflect.Modifier,同上,它可以用来获取修饰符。

    下面是该类的基本方法:

    方法描述
    toString(int mod)通过 mod 值来返回对应的修饰符
    isPublic(int modifiers)判断给定的修饰符是否是 public
    isStatic(int modifiers)判断给定的修饰符是否是 static
    isFinal(int modifiers)判断给定的修饰符是否是 final
    isAbstract(int modifiers)判断给定的修饰符是否是 abstract
    isInterface(int modifiers)判断给定的修饰符是否是 interface

    三、基本使用方法

    3.1 获取

    下面是 Class 对象部分用于获取的方法:

    方法描述
    getName()返回类的全限定名
    getSimpleName()返回类的简单名称
    getFields()返回类的 public 类型的字段
    getDeclaredFields()返回类的所有字段,包括 private 声明的和继承类的
    getMethod(String name, Class[] parameterTypes)返回类特定的方法
    getMethods()返回类的 public 类型的方法
    getDeclaredMethods()返回类的所有方法,包括 private 声明的和继承类的
    getPackage()返回类所在的包
    getSuperclass()返回类的父类
    getInterfaces()返回类实现的接口
    getDeclaredFields()返回类声明的所有字段
    getConstructors()返回类的 public 类型的构造函数
    getDeclaredConstructors()返回类声明的所有构造函数
    getDeclaredAnnotations()返回类声明的所有注解
    getInterfaces()返回类的接口

    示例:

    1. import java.lang.reflect.*; // 反射相关的类在这个包中
    2. interface Interface {} // 接口
    3. class Father {} // 父类
    4. class Son extends Father implements Interface { // 子类
    5. public String var_public = "str";
    6. private String var_private;
    7. Son() {};
    8. public void method_public(Integer param) {};
    9. private void method_private(Double param) {};
    10. }
    11. public class Test {
    12. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
    13. Son son = new Son();
    14. Class cls = son.getClass();
    15. // 获取类名
    16. System.out.println(cls.getName()); // Output: Son
    17. // 获取接口(返回一个数组)
    18. for (Class aClass: cls.getInterfaces()) System.out.println(aClass.getName()); // Output: Interface
    19. // 获取父类
    20. System.out.println(cls.getSuperclass().getName()); // Output: Father
    21. // 获取修饰符(需要用到 java.lang.reflect.Modifier)
    22. // 类 Son 没有修饰符,输出将为空,故此处用类 Test 来代替
    23. System.out.println(Modifier.toString(Test.class.getModifiers())); // Output: public
    24. // 获取属性(需要用到 java.lang.reflect.Field)
    25. System.out.println(cls.getField("var_public").get(son)); // Output: str
    26. // 获取方法(返回一个数组)(此处只获取声明的方法,不然太多了)
    27. for (Method method: cls.getDeclaredMethods()) System.out.println(method.getName()); // Output: method_public \n method_private
    28. // 获取方法的返回类型
    29. System.out.println(cls.getMethod("method_public", Integer.class).getReturnType()); // Output: void
    30. // 获取方法的参数类型(返回一个数组)
    31. for (Class aClass: cls.getMethod("method_public", Integer.class).getParameterTypes()) System.out.println(aClass.getSimpleName()); // Output: Integer
    32. }
    33. }

    3.2 修改

    下面反射机制中用于修改的示例:

    1. import java.lang.reflect.*;
    2. interface Interface {}
    3. class Father {}
    4. class Son extends Father implements Interface {
    5. public String var_public = "str";
    6. private String var_private;
    7. Son() {};
    8. public void method_public(Integer param) {};
    9. private void method_private(Double param) {};
    10. }
    11. public class Test {
    12. public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    13. Son son = new Son();
    14. Class cls = son.getClass();
    15. Field field = cls.getDeclaredField("var_public");
    16. // 让该属性能够被访问(当属性为 private 的时候,需要用此修改其访问修饰符)
    17. field.setAccessible(true); // 当然,也可以根据需要修改为 false
    18. // 修改属性 var_public 的值之前
    19. System.out.println(field.get(son)); // Output: str
    20. // 修改值
    21. field.set(son, "new");
    22. // 修改属性 var_public 的值之后
    23. System.out.println(field.get(son)); // Output: new
    24. }
    25. }
  • 相关阅读:
    【COS 加码福利】COS 用户实践有奖征文,等你来投稿!
    Python数据分析实战-applymap、apply、map有什么区别?(附源码和实现效果)
    经济小常识
    php操作服务器中json文件 进行读写操作用ajax交互
    Java开发学习(十)----基于注解开发定义bean 已完成
    计算机体系结构:1.1.系统加速比计算例题
    【ASP.NET Core】自定义Session的存储方式
    vue+elementUI 使用腾讯地图
    数据分析-numpy1
    Phoenix安装教程
  • 原文地址:https://blog.csdn.net/weixin_62651706/article/details/132910967