Java 反射机制

目录

一、Java 反射机制

什么是反射

反射的原理

反射的基本使用

获取 Class 对象的四种方式

反射的优缺点

项目中哪里用到了泛型


Spring中的反射是指通过Java的反射机制来动态地获取、操作和调用对象的属性和方法。反射是一种强大的机制,它允许我们在运行时检查和操作类、接口、字段和方法的信息,而不需要在编译时就知道它们的具体信息。

在Spring中,反射主要用于实现依赖注入(DI)和AOP(面向切面编程)等功能。通过反射,Spring可以在运行时动态地创建、管理和调用对象,从而实现了灵活的组装和配置。反射在Spring框架中扮演着重要的角色,为开发者提供了更强大和灵活的功能。这样,我们可以在不修改代码的情况下,动态地添加、删除或替换对象,实现灵活的配置和组装。

一、Java 反射机制

什么是反射

反射(Reflection)是Java中的一个强大特性,它允许程序在运行时访问和操作类、方法、字段等信息。Spring框架广泛使用反射,以实现依赖注入、动态代理等功能。

Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

反射允许Java程序在运行时获取类的详细信息,包括:

  • 类的名称
  • 类的属性(字段)
  • 类的方法
  • 类的构造函数
  • 访问修饰符(public、private、protected等)

反射的原理

首先需要知道一点,Class这个类才是反射的源头。Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。

  • 正常方式:通过完整的类名—>通过new实例化—>取得实例化对象
  • 反射方式:实例化对象—>getClass()方法—>通过完整的类名

他的工作原理是这样的:当一个宇节码文件加载到内存的时候,jvm会对该宇节码进行解剖,然后创建一个对象的Class对象,jvm把字节码文件的信息全部都存储到该Class对象中,我们只要获取到Class对象,我们就可以使用该对象设置对象的属性或者调用对象的方法等操作。

下图是类的正常加载过程、反射原理与class对象。

反射的基本使用

在使用反射时,我们可以通过以下步骤来获取、操作和调用对象的属性和方法。

  1. 获取Class对象:通过对象的getClass()方法或类名.class,可以获得对象的Class对象。Class对象是反射的入口点,它包含了类的完整信息。

  2. 获取字段信息:通过Class对象的getField()、getDeclaredField()等方法,可以获得类的公共字段或私有字段的信息。可以通过Field对象来获取和修改字段的值。

  3. 获取方法信息:通过Class对象的getMethod()、getDeclaredMethod()等方法,可以获得类的公共方法或私有方法的信息。可以通过Method对象来调用方法。

  4. 实例化对象:通过Class对象的newInstance()方法,可以创建类的实例。也可以通过Constructor对象来创建类的实例。

  5. 调用方法:通过Method对象的invoke()方法,可以调用类的方法。

获取 Class 对象的四种方式

如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。

Java 提供了四种方式获取 Class 对象。

1. 知道具体类的情况下可以使用:

通过类名.class,可以获得对象的Class对象。Class对象是反射的入口点,它包含了类的完整信息。

Class alunbarClass = TargetObject.class;

但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象,通过此方式获取 Class 对象不会进行初始化。

2. 通过 Class.forName()传入类的全路径获取:

Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");

3. 通过对象实例instance.getClass()获取:

通过对象的getClass()方法,可以获得对象的Class对象。Class对象是反射的入口点,它包含了类的完整信息。

TargetObject o = new TargetObject();
Class alunbarClass2 = o.getClass();

4. 通过类加载器xxxClassLoader.loadClass()传入类路径获取:

ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");

通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行。

反射的优缺点

优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

  • 以动态地获取类的信息,不需要在编译时就知道类的信息。
  • 可以动态地创建对象,不需要在编译时就知道对象的类型。
  • 可以动态地调用对象的属性和方法,可以在运行时动态地改变对象的行为。

缺点:

  • 由于反射是动态的,所以它的运行效率较低,不如直接调用方法或属性。
  • 由于反射是动态的,所以它会破坏Java的封装性,可能会使代码变得复杂和不稳定。
  • 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
  • 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射。

项目中哪里用到了泛型

像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。

像 Java 中的一大利器 注解 的实现也用到了反射。为什么你使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?这些都是因为你可以基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后,就可以做进一步的处理。

在Spring框架中,反射被广泛应用于依赖注入、AOP和数据库ORM等功能的实现。在Spring中,反射主要用于以下几个方面:

(1)依赖注入(DI)

Spring框架通过反射机制实现了依赖注入功能。在依赖注入中,Spring框架通过反射来解析类的注解或配置信息,然后动态地创建类的实例,并自动注入依赖的对象。

(2)AOP(面向切面编程)

Spring框架通过反射实现了AOP功能。在AOP中,Spring框架通过拦截器和代理对象来实现方法的增强和切面的织入。通过反射,Spring可以动态地创建代理对象,并在方法调用前后执行额外的操作。

(3)资源加载

Spring框架可以通过反射来加载和管理各种资源,如配置文件、模板文件等。通过反射,Spring可以根据配置信息动态地加载资源,并提供统一的访问接口。

(4)数据库ORM(对象关系映射)

Spring框架中的ORM功能(如JPA、Hibernate等)通常使用反射来实现,通过反射来解析实体类的注解或配置信息,并将Java对象映射到数据库中的表。

(5)动态代理

Spring框架中的代理对象通常是通过反射来创建的。动态代理可以使用反射机制在运行时动态地创建代理对象,而不需要在编译时就知道接口的实现类。

通过反射,Spring可以动态地生成代理对象,并在运行时拦截方法调用,从而实现各种功能,如事务管理、性能监控等。Junit等单元测试框架可以使用反射机制在运行时动态地获取类和方法的信息,实现自动化测试。

总之,反射是Java中的一个强大特性,提供了在运行时动态访问和操作类、方法和字段的能力。虽然反射带来了灵活性和扩展性,但也有性能和安全性等缺点。在Spring框架中,反射被广泛应用于依赖注入和动态代理等功能,使得框架能够以更加灵活的方式管理对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值