暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java反射机制:突破封装的魔法

课程导言:看不见的力量

"反射是Java的X光透视——它让你看到类的内部结构,甚至操作私有成员,就像拥有了超能力。"

反射的日常类比

  • 类如蓝图:普通方式只能按蓝图建房(创建对象)

  • 反射如施工队:能查看蓝图细节(类结构),甚至修改未公开部分(私有成员)

Ⅰ. 反射基础:Class对象入口

1.1 获取Class对象的三种方式

    // 1. 类名.class (最安全,编译时检查)
    Class<String> stringClass = String.class;
    // 2. 对象.getClass() (已有对象实例时)
    String s = "Hello";
    Class<?> strClass = s.getClass();
    // 3. Class.forName() (动态加载,可能抛出ClassNotFoundException)
    Class<?> arrayListClass = Class.forName("java.util.ArrayList");

    1.2 基本类型与数组的Class

      Class<Integer> intClass = int.class// 注意:不是Integer.class
      Class<int[]> intArrayClass = int[].class;
      Class<String[][]> twoDStringArrayClass = String[][].class;

      Ⅱ. 深入类结构:解剖Java类

      2.1 获取类信息

        Class<ArrayList> arrayListClass = ArrayList.class;
        // 获取类名
        String className = arrayListClass.getName(); // java.util.ArrayList
        String simpleName = arrayListClass.getSimpleName(); // ArrayList
        // 获取修饰符
        int modifiers = arrayListClass.getModifiers();
        boolean isPublic = Modifier.isPublic(modifiers);
        boolean isAbstract = Modifier.isAbstract(modifiers);
        // 获取父类
        Class<?> superClass = arrayListClass.getSuperclass(); // AbstractList
        // 获取接口
        Class<?>[] interfaces = arrayListClass.getInterfaces(); // [List, RandomAccess, ...]

        2.2 字段操作:查看与修改

          class Person {
              private String name;
              public int age;
          }
          // 获取字段
          Field[] fields = Person.class.getDeclaredFields(); // 获取所有字段(包括私有)
          Field nameField = Person.class.getDeclaredField("name"); // 获取指定字段
          // 访问私有字段(突破封装!)
          Person p = new Person();
          nameField.setAccessible(true); // 关键步骤:关闭访问检查
          nameField.set(p, "Alice"); // 设置字段值
          String nameValue = (String) nameField.get(p); // "Alice"

          2.3 方法操作:调用任意方法

            class Calculator {
                private int add(int a, int b) {
                    return a + b;
                }
            }
            // 获取方法
            Method addMethod = Calculator.class.getDeclaredMethod("add"int.classint.class);
            // 调用私有方法
            Calculator calc = new Calculator();
            addMethod.setAccessible(true);
            int result = (int) addMethod.invoke(calc, 53); // 8

            Ⅲ. 构造对象:超越new关键字

            3.1 使用构造器创建实例

              // 获取构造器
              Constructor<String> stringConstructor = String.class.getConstructor(String.class);
              // 创建实例
              String str = stringConstructor.newInstance("Hello Reflection");
              System.out.println(str); // "Hello Reflection"

              3.2 突破单例限制(演示,慎用)

                class Singleton {
                    private static Singleton instance = new Singleton();
                    private Singleton() {}


                    public static Singleton getInstance() {
                        return instance;
                    }
                }
                // 反射攻击单例
                Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
                constructor.setAccessible(true);
                Singleton newInstance = constructor.newInstance(); // 创建新实例,破坏单例

                Ⅳ. 反射与泛型:保留类型信息

                4.1 获取泛型类型

                  class GenericClass<T> {
                      private List<String> stringList = new ArrayList<>();


                      public List<TgetData() {
                          return new ArrayList<>();
                      }
                  }
                  // 获取字段的泛型类型
                  Field stringListField = GenericClass.class.getDeclaredField("stringList");
                  Type genericType = stringListField.getGenericType(); // java.util.List<java.lang.String>
                  // 获取方法的泛型返回类型
                  Method getDataMethod = GenericClass.class.getMethod("getData");
                  Type returnType = getDataMethod.getGenericReturnType(); // java.util.List<T>

                  Ⅴ. 反射实战:框架设计核心

                  5.1 简易依赖注入容器

                    class DIContainer {
                        private Map<Class<?>, Object> instances = new HashMap<>();


                        public void register(Class<?> clazz) throws Exception {
                            Constructor<?> constructor = clazz.getDeclaredConstructor();
                            constructor.setAccessible(true);
                            instances.put(clazz, constructor.newInstance());
                        }


                        public <T> resolve(Class<T> clazz) {
                            return clazz.cast(instances.get(clazz));
                        }
                    }
                    // 使用
                    DIContainer container = new DIContainer();
                    container.register(UserService.class);
                    UserService service = container.resolve(UserService.class);

                    5.2 注解处理器

                      @Retention(RetentionPolicy.RUNTIME)
                      @interface Table {
                          String name();
                      }
                      @Table(name = "users")
                      class UserEntity {}
                      // 处理注解
                      Class<UserEntity> entityClass = UserEntity.class;
                      Table tableAnnotation = entityClass.getAnnotation(Table.class);
                      System.out.println("表名: " + tableAnnotation.name()); // "users"

                      Ⅵ. 反射的代价与安全

                      6.1 性能考量

                        // 反射调用 vs 直接调用(性能测试)
                        long start = System.nanoTime();
                        // 直接调用100万次: 约5ms
                        // 反射调用100万次: 约500ms (慢100倍!)

                        6.2 安全限制

                          // 安全管理器阻止反射访问
                          System.setSecurityManager(new SecurityManager() {
                              @Override
                              public void checkPermission(Permission perm) {
                                  if (perm instanceof ReflectPermission) {
                                      throw new SecurityException("反射操作被禁止!");
                                  }
                              }
                          });
                          // 尝试访问私有字段将抛出SecurityException
                          Field field = String.class.getDeclaredField("value");
                          field.setAccessible(true); // 抛出异常

                          反射最佳实践:安全使用指南

                          1. 缓存反射对象

                            private static final Field NAME_FIELD;
                            static {
                                try {
                                    NAME_FIELD = Person.class.getDeclaredField("name");
                                    NAME_FIELD.setAccessible(true);
                                } catch (NoSuchFieldException e) {
                                    throw new ExceptionInInitializerError(e);
                                }
                            }
                            1. 优先接口而非反射


                            2. 避免突破封装:仅在框架开发等特殊场景访问私有成员

                            课程总结:反射的三大能力

                            1. 内省(Introspection)

                              • 查看类结构

                              • 获取注解信息

                            2. 操作(Manipulation)

                              • 修改字段值

                              • 调用私有方法

                            3. 动态(Dynamics)

                              • 运行时加载类

                              • 动态创建对象



                            课后挑战

                            1. 对象转Map工具

                              public static Map<StringObjecttoMap(Object obj) {
                                  // 返回对象所有字段名和值的映射(包括私有字段)
                              }
                              1. 方法调用日志代理

                                class LoggingProxy {
                                    public static <T> T create(Class<T> interfaceClass, T realObject) {
                                        // 返回代理对象,在每次方法调用前后打印日志
                                    }
                                }
                                1. 简易ORM框架

                                  class MiniORM {
                                      public <T> void save(T entity) {
                                          // 通过反射读取@Entity注解,生成SQL插入语句
                                      }
                                  }

                                  下节课预告:《Java注解:元数据的力量》

                                  你将学到:

                                  1. 内置注解与自定义注解

                                  2. 注解的保留策略与目标类型

                                  3. 注解处理器开发

                                  4. 运行时注解与编译时注解

                                  5. 注解在框架中的实战应用

                                  6. 元注解的深度解析

                                  "反射是Java的元编程能力,它赋予你在运行时修改程序行为的力量。但记住:能力越大,责任越大——谨慎使用这把双刃剑!"


                                  新关注福利:送你知识星球100元优惠券,真能省!✨

                                  文章转载自让天下没有难学的编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                  评论