1

面试官:说说反射的底层实现原理? - 磊哥|www.javacn.site

 2 months ago
source link: https://www.cnblogs.com/vipstone/p/18072885
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
172074-20240314150209976-166723784.jpg

反射是 Java 面试中必问的面试题,但只有很少人能真正的理解“反射”并讲明白反射,更别说能说清楚它的底层实现原理了。所以本文就通过大白话的方式来系统的讲解一下反射,希望大家看完之后能真正的理解并掌握“反射”这项技术。

1.什么是反射?

反射在程序运行期间动态获取类和操纵类的一种技术。通过反射机制,可以在运行时动态地创建对象、调用方法、访问和修改属性,以及获取类的信息。

2.反射的应用有哪些?

反射在日常开发中使用的地方有很多,例如以下几个:

  1. 动态代理:反射是动态代理的底层实现,即在运行时动态地创建代理对象,并拦截和增强方法调用。这常用于实现 AOP 功能,如日志记录、事务管理等。
  2. Bean 创建:Spring/Spring Boot 项目中,在项目启动时,创建的 Bean 对象就是通过反射来实现的。
  3. JDBC 连接:JDBC 中的 DriverManager 类通过反射加载并注册数据库驱动,这是 Java 数据库连接的标准做法。

3.反射实现

反射的关键实现方法有以下几个:

  1. 得到类:Class.forName("类名")
  2. 得到所有字段:getDeclaredFields()
  3. 得到所有方法:getDeclaredMethods()
  4. 得到构造方法:getDeclaredConstructor()
  5. 得到实例:newInstance()
  6. 调用方法:invoke()

具体使用示例如下:

// 1.反射得到对象
Class<?> clazz = Class.forName("User");
// 2.得到方法
Method method = clazz.getDeclaredMethod("publicMethod");
// 3.得到静态方法
Method staticMethod = clazz.getDeclaredMethod("staticMethod");
// 4.执行静态方法
staticMethod.invoke(clazz);

反射执行私有方法代码实现如下:

// 1.反射得到对象
Class<?> clazz = Class.forName("User");
// 2.得到私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
// 3.设置私有方法可访问
privateMethod.setAccessible(true);
// 4.得到实例
Object user = clazz.getDeclaredConstructor().newInstance();
// 5.执行私有方法
privateMethod.invoke(user);

4.底层实现原理

从上述内容可以看出,对于反射来说,操纵类最主要的方法是 invoke,所以搞懂了 invoke 方法的实现,也就搞定了反射的底层实现原理了。

invoke 方法的执行流程如下:

  1. 查找方法:当通过 java.lang.reflect.Method 对象调用 invoke 方法时,Java 虚拟机(JVM)首先确认该方法是否存在并可以访问。这包括检查方法的访问权限、方法签名是否匹配等。
  2. 安全检查:如果方法是私有的或受保护的,还需要进行访问权限的安全检查。如果当前调用者没有足够的权限访问这个方法,将抛出 IllegalAccessException。
  3. 参数转换和适配:invoke 方法接受一个对象实例和一组参数,需要将这些参数转换成对应方法签名所需要的类型,并且进行必要的类型检查和装箱拆箱操作。
  4. 方法调用:对于非私有方法,Java 反射实际上是通过 JNI(Java Native Interface,Java 本地接口)调用到 JVM 内部的 native 方法,例如 java.lang.reflect.Method.invoke0()。这个 native 方法负责完成真正的动态方法调用。对于 Java 方法,JVM 会通过方法表、虚方法表(vtable)进行查找和调用;对于非虚方法或者静态方法,JVM 会直接调用相应的方法实现。
  5. 异常处理:在执行方法的过程中,如果出现任何异常,JVM 会捕获并将异常包装成 InvocationTargetException 抛出,应用程序可以通过这个异常获取到原始异常信息。
  6. 返回结果:如果方法正常执行完毕,invoke 方法会返回方法的执行结果,或者如果方法返回类型是 void,则不返回任何值。

通过这种方式,Java 反射的 invoke 方法能够打破编译时的绑定,实现运行时动态调用对象的方法,提供了极大的灵活性,但也带来了运行时性能损耗和安全隐患(如破坏封装性、违反访问控制等)。

5.优缺点分析

反射的优点如下:

  1. 灵活性:使用反射可以在运行时动态加载类,而不需要在编译时就将类加载到程序中。这对于需要动态扩展程序功能的情况非常有用。
  2. 可扩展性:使用反射可以使程序更加灵活和可扩展,同时也可以提高程序的可维护性和可测试性。
  3. 实现更多功能:许多框架都使用反射来实现自动化配置和依赖注入等功能。例如,Spring 框架就使用反射来实现依赖注入。

反射的缺点如下:

  1. 性能问题:使用反射会带来一定的性能问题,因为反射需要在运行时动态获取类的信息,这比在编译时就获取信息要慢。
  2. 安全问题:使用反射可以访问和修改类的字段和方法,这可能会导致安全问题。因此,在使用反射时需要格外小心,确保不会对程序的安全性造成影响。

为什么反射的执行效率比较低?动态代理的实现除了反射之外,还有没有其他的实现方法?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK