文章目录
- 前言
- 一、反射
- 1.反射的定义
- 2.反射的作用
- 二、类信息的来源
- 1.类信息的来源
- 2.Class 对象
- 三、类信息的获取
- 1.获取 Class 对象的三种方式
- (1)通过类名获取:
- (2)通过对象获取:
- (3)通过类的全限定名获取:
- 2. 获取类的基本信息
- 1. 类名
- 2. 父类
- 3. 接口
- 4. 获取字段
- 5. 获取方法
- 6. 获取构造器
- 7. 获取特定字段和方法
- 8. 获取特定的构造器
- 四、如何使用类信息
- 1.创建对象
- 2.调用方法
- 3.访问属性
- 总结
前言
Java 反射(Reflection)是 Java 语言中一个强大而灵活的特性,它允许程序在运行时动态地获取类的信息并操作类的属性和方法。反射机制为 Java 提供了极大的灵活性,但也带来了一定的性能开销和复杂性。本文将深入探讨 Java 反射的核心概念、使用方法以及注意事项,帮助你全面掌握这一重要特性。
一、反射
1.反射的定义
- 反射是获取类信息的一种能力。
- 反射的核心在于Class类,它是Java反射API的基石。Class对象封装了关于类和接口的信息,包括类的成员变量、方法、构造器以及接口等。
- 通过Class对象,我们可以动态地获取类的内部结构,并在运行时进行相应的操作。
2.反射的作用
- 动态加载类:在运行时加载类,而不是在编译时。
- 动态创建对象:通过类名创建对象实例。
- 动态调用方法:在运行时调用对象的方法。
- 动态访问属性:在运行时访问或修改对象的属性。
- 实现通用框架:如 Spring 框架中的依赖注入(DI)和 AOP(面向切面编程)。
二、类信息的来源
1.类信息的来源
在 Java 中,每个类都有一个对应的 Class 对象,这个对象包含了类的所有信息(如类名、方法、属性、构造器等)。
类信息来源于以下两种方式:
- 编译时:Java 编译器将源代码编译为字节码(.class 文件),字节码中包含了类的所有信息。
- 运行时:JVM 加载字节码文件,并将其解析为 Class 对象,供程序使用。
2.Class 对象
Class 对象是反射的核心,它提供了以下功能:
- 获取类的名称、包名、父类、接口等信息。
- 获取类的构造器、方法和属性。
- 创建类的实例。
- 调用类的方法或访问类的属性。
三、类信息的获取
1.获取 Class 对象的三种方式
(1)通过类名获取:
Class clazz = Student.class;
(2)通过对象获取:
Student student = new Student();
Class clazz = person.getClass();
(3)通过类的全限定名获取:
Class clazz = Class.forName("com.example.Student");
2. 获取类的基本信息
通过 Class 对象,可以获取类的基本信息:
1. 类名
可以通过Class.getName()方法获取。
2. 父类
可以通过Class.getSuperclass()方法获取。
3. 接口
可以通过Class.getInterfaces()方法获取类实现的接口。
4. 获取字段
// getDeclaredFields():获取类中声明的所有字段,包括私有字段。 Field[ ] fields =clazz.getDeclaredFields();System.out.println(Arrays.toString(fields));
// getFields():获取类中所有可访问的公共字段Field[ ] fields1 =clazz.getFields();System.out.println(Arrays.toString(fields1));
5. 获取方法
//getDeclaredMethods():获取类中声明的所有方法,包括私有方法。Method[] method=clazz.getDeclaredMethods();System.out.println(Arrays.toString(method));
//getMethods():获取类中所有可访问的公共方法,包括从超类继承的方法。 Method[] method1=clazz.getMethods();System.out.println(Arrays.toString(method1));
6. 获取构造器
//getDeclaredConstructors():获取类中声明的所有构造器。Constructor[] declaredConstructors=clazz.getDeclaredConstructors();System.out.println(Arrays.toString(declaredConstructors));
7. 获取特定字段和方法
//获取特定字段使用getDeclaredField(String name)//getDeclaredField(String name):这个方法用于获取类中声明的指定名称的字段,不考虑字段的访问修饰符(即可以获取私有、受保护、默认(包)访问和公共字段)。Field nameField= clazz.getDeclaredField( "name"); System. out.println(nameField);
//getField(String name):这个方法仅用于获取类中可访问的公共字段。如果尝试获取非公共字段,将会抛出NoSuchFieldException。Field ageField = clazz.getField( "age"); System.out.println(ageField);
// 获取特定方法getDeclaredMethod(String name, Class<?>... parameterTypes)Method runMethod = clazz.getDeclaredMethod( "run"); System. out.println(runMethod); Method runMethod1=clazz.getDeclaredMethod("run",String.class, int.class); System.out.println(runMethod1);
8. 获取特定的构造器
//通过getDeclaredConstructor(Class<?>... parameterTypes)可以根据参数类型获取特定的构造器。Constructor constructor1 = clazz.getDeclaredConstructor(String.class,int.class,double.class,char.class);System.out.println(constructor1);Constructor constructor2 = clazz.getDeclaredConstructor(int.class,double.class,char.class);System.out.println(constructor2);
四、如何使用类信息
1.创建对象
通过反射可以动态创建类的实例:
Constructor constructor =clazz.getDeclaredConstructor();
Student student = (Student) constructor.newInstance();// 调用无参构造器创建对象
如果类没有无参构造器,可以通过 Constructor 对象创建有参实例:
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Student student1=(Student)constructor1.newInstance('张三',25);
private修饰的数据是在其他类当中访问不到的,要想访问到我们就要用到暴力反射。
暴力反射是指通过 setAccessible(true) 方法绕过 Java 的访问控制检查,访问类的私有成员(属性、方法、构造器等)。示例:
Constructor constructor2= clazz.getDeclaredConstructor(char.class); constructor2.setAccessible(true);//暴力反射--------->针对的就是private修饰的数据Student student2=(Student)constructor2.newInstance('女');
2.调用方法
通过反射可以动态调用类的方法:
Method run = clazz.getDeclaredMethod("run");run.setAccessible(true); run.invoke(student); //获取了一个无参的run方法Method getNameString = clazz.getDeclaredMethod("getNameString", String.class);String name = (String) getNameString.invoke(student, "aaaaa");System.out.println(name);//获取了名为getNameString的带有一个String参数的方法,并用参数"aaaaa"调用了student对象上的该方法。然后,接收了返回的String值并打印了它。
3.访问属性
通过反射可以动态访问或修改类的属性:
//对属性的赋值、取值Field nameField= clazz.getDeclaredField( "name"); //赋值nameField.setAccessible(true);//暴力反射nameField.set(student,"张三");//setO需要两个参数分别是对象和值System.out.println(nameField.get(student));//赋值Field ageField=clazz.getField( "age");ageField.set(student,18); System.out.println(ageField.get(student));
总结
Java 反射是一个强大的工具,它为程序提供了动态操作类的能力。通过反射,我们可以在运行时获取类的信息、创建对象、调用方法或访问属性。然而,反射也带来了一定的性能开销和复杂性,因此在实际开发中应谨慎使用。
掌握反射的核心概念和使用方法,能够帮助我们更好地理解 Java 的运行机制,并编写出更加灵活和通用的代码。希望本文能帮助你深入理解 Java 反射,并在实际项目中灵活运用!