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
目录
相关文章
|
2月前
|
安全 Java 测试技术
Burp Suite使用及BruteForc_test靶场实战
Burp Suite 是一款用于Web应用安全测试的集成平台,包含多个协同工具,支持请求拦截、漏洞扫描、暴力破解等功能,适用于渗透测试,提升安全测试效率。
386 0
Burp Suite使用及BruteForc_test靶场实战
|
11月前
|
机器学习/深度学习 存储 并行计算
Ascend上的PageAttention
PageAttention旨在解决大型语言模型(LLM)服务中的内存管理低效问题,如内存碎片化、利用率低及缺乏灵活的内存共享机制。通过借鉴操作系统中的虚拟内存和分页技术,PageAttention实现了块级别的内存管理和灵活的KV cache共享机制,显著提高内存利用率,降低延迟,提升模型处理速度和性能。相比传统注意力机制,PageAttention通过分段处理序列,有效解决了长序列处理时的计算效率低下和内存过度使用问题。
|
Web App开发 算法
基于simulink的交流电机SPWM调速系统建模与动态仿真
基于simulink的交流电机SPWM调速系统建模与动态仿真
448 0
基于simulink的交流电机SPWM调速系统建模与动态仿真
正整数分解质因数
# 题目:将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。 # 程序分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成: # (1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。
1215 0
|
5天前
|
云安全 人工智能 安全
AI被攻击怎么办?
阿里云提供 AI 全栈安全能力,其中对网络攻击的主动识别、智能阻断与快速响应构成其核心防线,依托原生安全防护为客户筑牢免疫屏障。
|
15天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
9天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
586 212