Java进阶之反射

简介: Java进阶之反射

Java进阶之反射
我们知道Java在编译期的时候,代码中new对象时候,对象的类型就确定了下来,然后编译后的代码进行运行。而要在代码运行期的时候动态的去操作对象,就需要用Java的反射。
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种在代码运行中动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
那么我们今天来细细研究下到底什么是反射呢?首先先看名字,反射,有反肯定对应就有正。
正就是我们正常的Java代码开发过程:导入类所在的包、通过类中的构造方法实例化对象、再使用实例化的对象去调用类中的方法。
那反的过程就是通过实例化的对象,反向推算出该对象的类型。
正: 类---new--->对象
反: 对象-getClass()->类
这里的getClass()方法是在Object中存在,要知道万物皆是对象,Java中的所有类都是默认继承自Object的,所以Object是所有类的父类,所有类都有这个方法。

  Object类位于java.lang包中,这个包在编译Java程序时会自动导入。因此,Object类的方法可以被所有的Java类使用。
  Object类提供了一些基本的方法,包括:
  hashCode():返回对象的哈希码值,这个值通常用于哈希表中,比如 HashMap。
  equals(Object obj):用于比较两个对象是否相等。
  toString():返回对象的字符串表示形式。
  getClass():返回对象的运行时类。
  clone():创建并返回对象的一个副本。
  finalize():当垃圾收集器确定不再有对该对象的引用时,由垃圾收集器在对象上调用此方法。
  这些方法可以被其他类覆盖,以提供特定的实现。

  所以这里我们就可以通过getClass()来反射获取到对象的运行时类。
  反射所有的技术支持都来源于Class类
  Java反射机制可以让我们在代码运行时动态地获取类的信息,创建对象,调用方法,访问和修改字段等。也就是说不需要new关键字,也能实例化类对象!
  反射的原理
  Java反射机制的实现主要依赖于Java类库中的一组类和接口,这些类和接口位于java.lang.reflect包中:
  Class类:反射的核心类,可以获取对象的属性、方法等信息。
  Field类:表示类的成员变量,可以用来获取和设置类之中的字段信息。
  Method类:代表类的方法,可以用来获取类中的方法信息或者执行类和对象的方法。
  Constructor类:代表类的构造方法。
  当我们编写并编译一个Java程序时,Java编译器会将.java文件转换成.class文件,这些.class文件包含了类的所有信息,如字段、方法、构造函数等。
  在运行时,JVM会加载这些.class文件,并通过反射机制将这些信息暴露给我们。
  Java反射机制主要提供以下功能:
  获得Class对象
  方法有三种:
  1.使用Class类的forName静态方法:
  Class<?> clazz = Class.forName("java.lang.String");
  Object obj = clazz.newInstance();
  2.直接获取某一个对象的 class
  Class<?> clazz = String.class;
  Object obj = clazz.newInstance();
  3.调用某个对象的getClass()方法,比如:
  StringBuilder str = new StringBuilder("123");
  Class<?> clazz = str.getClass();
  Object obj = clazz.newInstance();
  在运行时判断任意一个对象所属的类。
  Object obj = new String("Hello, World!");
  Class<?> clazz = obj.getClass();
  System.out.println("输出类名: " + clazz.getName());
  // 使用isInstance()方法判断obj是否是String类的实例
  boolean isInstanceOfString = clazz.isInstance(obj);
  在运行时构造任意一个类的对象。
  创建对象有​两种方法:
  1.使用Class对象的newInstance()方法
  Class<?> clazz = Class.forName("java.lang.String");
  Object obj = clazz.newInstance();
  2.先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来构造
  //获取String所对应的Class对象
  Class<?> c = String.class;
  //获取String类带一个String参数的构造器
  Constructor constructor = c.getConstructor(String.class);
  //根据构造器创建实例
  Object obj = constructor.newInstance("创建对象");
  System.out.println(obj);
  在运行时判断任意一个类所具有的成员变量和方法。
  Class<?> clazz = Class.forName("java.lang.String");
  Field[] fields = clazz.getDeclaredFields();
  Method[] methods = clazz.getDeclaredMethods();
  System.out.println("Fields:");
  for (Field field : fields) {
      System.out.println(field);
  }
  System.out.println("Methods:");
  for (Method method : methods) {
      System.out.println(method);
  }
  在运行时获取泛型信息。
  Class<?> clazz = Class.forName("java.util.ArrayList");
  Type genericType = clazz.getGenericSuperclass();
  if (genericType instanceof ParameterizedType) {
      Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
      System.out.println("The actual type argument is: " + actualTypeArguments[0]);
  }
  在运行时调用任意一个对象的成员变量和方法。
  Object obj = new String("Hello, World!");
  Class<?> clazz = obj.getClass();
  // 调用方法
  Method method = clazz.getDeclaredMethod("toUpperCase");
  String result = (String) method.invoke(obj);
  System.out.println("Uppercase: " + result);
  // 访问字段
  Field field = clazz.getDeclaredField("value");
  field.setAccessible(true);
  char[] value = (char[]) field.get(obj);
  System.out.println("Value: " + new String(value));
  在运行时处理注解。
  Class<?> clazz = Class.forName("MyClass");
  Annotation[] annotations = clazz.getAnnotations();
  for (Annotation annotation : annotations) {
      if (annotation instanceof MyCustomAnnotation) {
          MyCustomAnnotation myAnnotation = (MyCustomAnnotation) annotation;
          System.out.println("Name: " + myAnnotation.name());
          System.out.println("Value: " + myAnnotation.value());
      }
  }
  生成动态代理。
  InvocationHandler handler = new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          // 在这里添加预处理和后处理逻辑
          System.out.println("Method called: " + method.getName());
          return method.invoke(target, args);
      }
  };
  MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
      MyInterface.class.getClassLoader(),
      new Class<?>[]{MyInterface.class},
      handler
  );
  proxy.myMethod();
  上面示例创建一个实现了MyInterface接口的代理对象,当调用myMethod方法时,会执行InvocationHandler中的逻辑。
  单元测试
  在单元测试中,通过反射模拟外部依赖的行为,从而实现单元测试。
  // 使用反射模拟外部依赖的方法
  Class<?> clazz = Class.forName("MyClass");
  Method method = clazz.getDeclaredMethod("externalMethod");
  method.setAccessible(true);
  method.invoke(obj);

  序列化和反序列化
  反射也可以访问和修改对象的私有字段,比如在序列化和反序列化过程中。
  ObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.ser"));
  Class<?> clazz = in.readObject().getClass();
  Field field = clazz.getDeclaredField("name");
  field.setAccessible(true);
  Object obj = in.readObject();
  String name = (String) field.get(obj);
  如果全类名或者方法错误,可能出现ClassNotFoundException、NoSuchMethodException等异常,注意捕捉处理。
  私有字段和方法尽量不访问和修改。而且反射会影响性能。
  通过反射,我们可以突破Java语言的封装性,实现一些常规编程无法实现的功能。但是还是优先使用常规编程,最终不行再考虑反射!

  日常开发中,ide软件通过.就可以提示出可调用的方法,这也是反射的应用。
  以后web框架中的通过配置文件去定义Java bean,根据不同的配置文件就可以构建出不同的对象,调用对应的方法等等,都是反射的应用。
  还有其他一些运行时动态加载需要加载的对象,都是反射实现的。

  END
目录
相关文章
|
1天前
|
云安全 数据采集 人工智能
古茗联名引爆全网,阿里云三层防护助力对抗黑产
阿里云三层校验+风险识别,为古茗每一杯奶茶保驾护航!
古茗联名引爆全网,阿里云三层防护助力对抗黑产
|
5天前
|
Kubernetes 算法 Go
Kubeflow-Katib-架构学习指南
本指南带你深入 Kubeflow 核心组件 Katib,一个 Kubernetes 原生的自动化机器学习系统。从架构解析、代码结构到技能清单与学习路径,助你由浅入深掌握超参数调优与神经架构搜索,实现从使用到贡献的进阶之旅。
275 139
|
5天前
|
人工智能 中间件 API
AutoGen for .NET - 架构学习指南
《AutoGen for .NET 架构学习指南》系统解析微软多智能体框架,涵盖新旧双架构、核心设计、技术栈与实战路径,助你从入门到精通,构建分布式AI协同系统。
290 142
|
16天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
11天前
|
缓存 并行计算 PyTorch
144_推理时延优化:Profiling与瓶颈分析 - 使用PyTorch Profiler诊断推理延迟,优化矩阵运算的独特瓶颈
在2025年的大模型时代,推理时延优化已经成为部署LLM服务的关键挑战之一。随着模型规模的不断扩大(从数亿参数到数千亿甚至万亿参数),即使在最先进的硬件上,推理延迟也常常成为用户体验和系统吞吐量的主要瓶颈。
356 147
|
5天前
|
人工智能 移动开发 自然语言处理
阿里云百炼产品月刊【2025年9月】
本月通义千问模型大升级,新增多模态、语音、视频生成等高性能模型,支持图文理解、端到端视频生成。官网改版上线全新体验中心,推出高代码应用与智能体多模态知识融合,RAG能力增强,助力企业高效部署AI应用。
290 1
|
11天前
|
机器学习/深度学习 存储 缓存
92_自我反思提示:输出迭代优化
在大型语言模型(LLM)应用日益普及的今天,如何持续提升模型输出质量成为了业界关注的核心问题。传统的提示工程方法往往依赖一次性输入输出,难以应对复杂任务中的多轮优化需求。2025年,自我反思提示技术(Self-Reflection Prompting)作为提示工程的前沿方向,正在改变我们与LLM交互的方式。这项技术通过模拟人类的自我反思认知过程,让模型能够对自身输出进行评估、反馈和优化,从而实现输出质量的持续提升。
425 136
|
14天前
|
存储 人工智能 搜索推荐
终身学习型智能体
当前人工智能前沿研究的一个重要方向:构建能够自主学习、调用工具、积累经验的小型智能体(Agent)。 我们可以称这种系统为“终身学习型智能体”或“自适应认知代理”。它的设计理念就是: 不靠庞大的内置知识取胜,而是依靠高效的推理能力 + 动态获取知识的能力 + 经验积累机制。
414 135
|
14天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
542 133
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话