Java反射机制
# 一、Java反射机制概述
# 1.1 反射机制简介
Java反射机制是Java语言中一个非常强大的特性,它允许程序在运行时动态地访问和修改类的属性、方法、构造函数等信息。通过反射,我们可以在运行时创建对象、调用方法、获取和设置字段值等,极大地提高了程序的灵活性和可扩展性。
# 1.2 反射机制的应用场景
- 框架设计:许多Java框架(如Spring、Hibernate等)都大量使用了反射机制,以实现依赖注入、对象关系映射等功能。
- 动态代理:Java的动态代理机制(如JDK动态代理)也是基于反射实现的。
- 配置文件驱动:在一些应用中,可以通过配置文件来指定类名和方法名,然后在程序运行时通过反射动态地加载和调用这些类和方法。
# 二、Java反射机制的创建模式和常用方法
# 2.1 获取Class对象的三种方式
要使用反射机制,首先需要获取到代表类的Class对象。Java提供了三种获取Class对象的方式:
通过对象的getClass()方法:这种方式需要先创建一个类的对象,然后调用对象的getClass()方法来获取Class对象。例如:
Student student = new Student(); Class stuClass = student.getClass();
1
2通过类名的.class属性:这种方式直接通过类名的.class属性来获取Class对象,是获取Class对象最简单的方式之一。例如:
Class stuClass = Student.class;
1通过Class类的forName()方法:这种方式通过Class类的静态方法forName()来获取Class对象,需要传入类的全限定名作为参数。例如:
Class stuClass = Class.forName("fanshe.Student");
1这种方式是最为常见和灵活的,因为它可以在运行时动态地加载指定的类。
# 2.2 获取类的构造器
通过Class对象,我们可以获取到类的构造器,从而在运行时创建类的对象。获取构造器的方法主要有以下几种:
getDeclaredConstructors():返回类中所有构造器的数组,包括私有的构造器。
Constructor[] constructors = stuClass.getDeclaredConstructors();
1getConstructors():返回类中所有公共构造器的数组。
Constructor[] constructors = stuClass.getConstructors();
1getConstructor(Class<?>... parameterTypes):返回类中指定参数类型的公共构造器。
Constructor constructor = stuClass.getConstructor(String.class);
1getDeclaredConstructor(Class<?>... parameterTypes):返回类中指定参数类型的构造器,包括私有的构造器。
Constructor constructor = stuClass.getDeclaredConstructor(String.class);
1获取到构造器后,可以通过调用构造器的newInstance()方法来创建类的对象。例如:
Student student = (Student) constructor.newInstance("张三");
1
# 2.3 获取类的成员变量
通过Class对象,我们还可以获取到类的成员变量,并对其进行操作。获取成员变量的方法主要有以下几种:
getFields():返回类中所有公共成员变量的数组。
Field[] fields = stuClass.getFields();
1getDeclaredFields():返回类中所有成员变量的数组,包括私有的成员变量。
Field[] fields = stuClass.getDeclaredFields();
1getField(String name):返回类中指定名称的公共成员变量。
Field field = stuClass.getField("name");
1getDeclaredField(String name):返回类中指定名称的成员变量,包括私有的成员变量。
Field field = stuClass.getDeclaredField("age");
1获取到成员变量后,可以通过调用成员变量的get()和set()方法来获取和设置成员变量的值。例如:
Object value = field.get(student); field.set(student, "李四");
1
2
# 2.4 获取类的方法
通过Class对象,我们可以获取到类的方法,并在运行时调用这些方法。获取方法的方法主要有以下几种:
getMethods():返回类中所有公共方法的数组,包括继承自父类的方法。
Method[] methods = stuClass.getMethods();
1getDeclaredMethods():返回类中所有方法的数组,包括私有的方法。
Method[] methods = stuClass.getDeclaredMethods();
1getMethod(String name, Class<?>... parameterTypes):返回类中指定名称和参数类型的公共方法。
Method method = stuClass.getMethod("study", String.class);
1getDeclaredMethod(String name, Class<?>... parameterTypes):返回类中指定名称和参数类型的方法,包括私有的方法。
Method method = stuClass.getDeclaredMethod("eat", String.class);
1获取到方法后,可以通过调用方法的invoke()方法来执行该方法。例如:
method.invoke(student, "Java");
1
# 三、Java反射机制的源码分析
# 3.1 Class.forName()方法的源码分析
Class.forName()方法是获取Class对象最常用的方式之一,其源码实现主要分为以下几个步骤:
- 获取调用者的类加载器:通过Reflection.getCallerClass()方法获取调用者的类信息,从而获取当前的类加载器。
- 调用native方法获取类信息:调用forName0()方法,该方法是一个native方法,由JVM实现,用于获取类的字节码信息。
- 加载类:通过调用ClassLoader的loadClass()方法来加载类。loadClass()方法会先检查类是否已经被加载,如果已经被加载,则直接返回;否则,会调用findClass()方法来查找并加载类。
# 3.2 Constructor.newInstance()方法的源码分析
Constructor.newInstance()方法用于通过构造器创建类的对象,其源码实现主要分为以下几个步骤:
- 权限检测:检查是否有权限调用该构造器,如果没有权限,则抛出异常。
- 查找无参构造器:通过getConstructor0()方法查找类的无参构造器,并将其缓存起来。
- 调用无参构造器:通过调用ConstructorAccessor的newInstance()方法来调用无参构造器,从而创建类的对象。
# 3.3 Method.invoke()方法的源码分析
Method.invoke()方法用于调用类的方法,其源码实现主要分为以下几个步骤:
- 权限检测:检查是否有权限调用该方法,如果没有权限,则抛出异常。
- 获取MethodAccessor:通过acquireMethodAccessor()方法获取MethodAccessor对象,该对象用于执行方法调用。
- 执行方法调用:通过MethodAccessor的invoke()方法来执行方法调用。在第一次调用时,会生成一个代理Accessor来执行方法调用,后续调用则直接使用生成的Accessor。