一. 反射概述
Java反射是Java语言的一种特性,它允许程序在运行时自我检查并对内部成员进行操作。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
优点:
- 灵活性:反射允许程序在运行时动态地访问对象的信息和操作,这增加了程序的灵活性。
- 通用性:可以编写更通用的代码,例如编写一个方法,它可以接受任何对象作为参数并调用其方法。
- 框架和库开发:许多Java框架和库(如Spring框架)广泛使用反射来处理依赖注入、事件监听等。
缺点:
- 安全性问题:反射可能导致安全漏洞,例如恶意代码可以利用它来访问或修改不应被访问的系统内部信息
- 性能开销:反射操作通常比直接代码调用要慢,因为它涉及到类型信息的动态解析。在性能敏感的应用中,过度使用反射可能会导致性能问题。
- 可读性和维护性:使用反射编写的代码通常比直接代码更难理解和维护,因为它增加了代码的复杂性和间接性。
二. 使用反射
在Java编程语言中,Class类是一个特殊的类,它用于表示JVM运行时的类或接口的信息。你可以把它看作是一个普通的类,但它描述的是所有的类的公共特性。
每个类在Java中都对应着一个Class对象,这个对象保存了该类的结构信息,如类名、字段、方法等。换句话说,Class类是一个反射工具,能提供很多方法用于获取类的各种信息,比如获取类名、判断该类是否是一个接口还是普通类等等。
1. 获取Class对象
- Class.forName(“全类名”)
- 类名.class
- 对象名.getClass()
先新建一个Student测试类
package org.example.reflect;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Student {
private String name;
private int age;
private Student() {
}
public Student(String name) {
this.name = name;
}
public Student(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
private void eat(String food) {
System.out.println("I am eating " + food);
}
}
下面演示如何获取Class对象
package org.example.reflect;
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c1 = Class.forName("org.example.reflect.Student");
Class<Student> c2 = Student.class;
Student student = new Student("zhangsan");
Class<? extends Student> c3 = student.getClass();
System.out.println(c1 == c2);
System.out.println(c2 == c3);
}
}
运行结果:
true
true
2. 获取构造方法
public Constructor<?>[] getConstructors() //获取公开的构造方法
public Constructor<?>[] getConstructors() //获取所有的公开的构造方法
public Constructor<?>[] getDeclaredConstructors() //获取所有的构造方法,包括私有
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //获取指定包括私有,不包括继承的Constructor对象
下面演示如何获取Student类的构造方法
package org.example.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> clazz = Class.forName("org.example.reflect.Student");
// 获取public 构造方法
System.out.println("===== public构造方法 =====");
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor constructor: constructors) {
System.out.println(constructor);
}
System.out.println("===== 所有构造方法 =====");
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor constructor: declaredConstructors) {
System.out.println(constructor);
}
// 不传参数表示获取空参构造函数
System.out.println("===== 获取单个构造方法 =====");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(declaredConstructor);
// 获取构造函数参数
System.out.println("===== 获取构造函数参数 =====");
Parameter[] parameters = declaredConstructor.getParameters();
for (Parameter parameter: parameters) {
System.out.println(parameter);
}
System.out.println("===== 实例化对象 =====");
declaredConstructor.setAccessible(true);
Object instance = declaredConstructor.newInstance("chenli", 30);
System.out.println(instance);
}
}
运行结果:
===== public构造方法 =====
public org.example.reflect.Student(java.lang.String,int)
public org.example.reflect.Student(int)
public org.example.reflect.Student(java.lang.String)
===== 所有构造方法 =====
public org.example.reflect.Student(java.lang.String,int)
public org.example.reflect.Student(int)
public org.example.reflect.Student(java.lang.String)
private org.example.reflect.Student()
===== 获取单个构造方法 =====
public org.example.reflect.Student(java.lang.String,int)
===== 获取构造函数参数 =====
java.lang.String arg0
int arg1
===== 实例化对象 =====
Student(name=chenli, age=30)
3. 获取成员变量
public Field[] getFields() //获取所有公开的成员变量,包括继承变量
public Field[] getDeclaredFields() //获取本类定义的成员变量,包括私有,但不包括继承的变量
public Field getField(String name) //获取指定公共属性的Field对象
public Field getDeclaredField(String name) //获取指定包括私有,不包括继承的Field对象
下面演示如何获取Student类的成员变量
package org.example.reflect;
import java.lang.reflect.Field;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("org.example.reflect.Student");
System.out.println("===== 获取所有属性 =====");
Field[] fields = clazz.getDeclaredFields();
for (Field field: fields) {
System.out.println(field);
}
System.out.println("===== 获取属性信息 =====");
Field nameField = clazz.getDeclaredField("name");
String name = nameField.getName();
Class<?> type = nameField.getType();
System.out.println("name: " + name + ", type: " + type);
// 修改field的值
System.out.println("===== 修改对象的属性 =====");
Student s = new Student("zhangsan", 20);
System.out.println(s);
nameField.setAccessible(true);
nameField.set(s, "lisi");
System.out.println(s);
}
}
运行结果:
===== 获取所有属性 =====
private java.lang.String org.example.reflect.Student.name
private int org.example.reflect.Student.age
===== 获取属性信息 =====
name: name, type: class java.lang.String
===== 修改对象的属性 =====
Student(name=zhangsan, age=20)
Student(name=lisi, age=20)
4. 获取成员方法
public Method[] getMethods() //获取所有可见的方法,包括继承的方法
public Method getMethod(String name, Class<?>... parameterTypes) //获取指定方法的Method对象
public Method[] getDeclaredMethods() //获取本类定义的的方法,包括私有,不包括继承的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) //获取指定包括私有,不包括继承的Method对象
下面演示如何获取Student类的成员方法
package org.example.reflect;
import java.lang.reflect.Method;
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("org.example.reflect.Student");
System.out.println("===== 获取所有方法 =====");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method: declaredMethods) {
System.out.println(method);
}
System.out.println("===== 获取某个方法 =====");
Method method = clazz.getDeclaredMethod("eat", String.class);
String name = method.getName();
Class<?> returnType = method.getReturnType();
Class<?>[] parameterTypes = method.getParameterTypes();
System.out.println("name: " + name + ", returntype: " + returnType
+ "parameterTypes: " + parameterTypes);
System.out.println("===== 调用方法 =====");
Student s = new Student("kkk", 30);
method.setAccessible(true);
method.invoke(s, "apple");
}
}
运行结果:
===== 获取所有方法 =====
public java.lang.String org.example.reflect.Student.toString()
public java.lang.String org.example.reflect.Student.getName()
public void org.example.reflect.Student.setName(java.lang.String)
private void org.example.reflect.Student.eat(java.lang.String)
public int org.example.reflect.Student.getAge()
public void org.example.reflect.Student.setAge(int)
===== 获取某个方法 =====
name: eat, returntype: voidparameterTypes: [Ljava.lang.Class;@5cad8086
===== 调用方法 =====
I am eating apple