在Java中,反射是指程序在运行时动态地获取类的信息、调用方法和访问属性的能力。
通过反射,可以在运行时获取类的构造函数、方法和字段
等信息,并且可以在运行时动态地创建对象、调用方法和访问属性
,而不需要在编译时知道类的具体信息。
反射提供了一种机制,使得编写通用的、灵活的代码成为可能,但同时也会增加代码的复杂性和性能开销。
反射允许对封装类的字段(成员变量),方法(成员方法)和构造函数(构造方法)的信息进行编程访问。
①
Class.forName("全类名");
//全类名:包名+类名
Class clazz1 = Class.forName("case11.Student");//最常用
②
类名.class
//一般当作参数进行传递
Class clazz2 = Student.class;
③
对象.getClass();
Student s = new Student();
Class clazz3 = s.getClass();
创建一个Student类:定义多种构造方法
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
protected Student(int age) {
this.age = age;
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
}
主函数:演示反射获取构造方法的各种函数
public class Main{
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取class字节码文件对象
Class clazz = Class.forName("case11.Student");
//获取public构造方法
Constructor[] cons = clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("-------------------------");
//获取所有构造方法
Constructor[] con1 = clazz.getDeclaredConstructors();
for (Constructor constructor : con1) {
System.out.println(constructor);
}
System.out.println("-------------------------");
//获取空参构造方法
Constructor con2 = clazz.getDeclaredConstructor();
System.out.println(con2);
System.out.println("-------------------------");
//获取带参数的构造方法
System.out.println(clazz.getDeclaredConstructor(String.class));
System.out.println(clazz.getDeclaredConstructor(int.class));
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
System.out.println("------------------------");
//获取构造方法的权限修饰符
int modifiers = con3.getModifiers();
System.out.println(modifiers);
//获取构造方法的参数
Parameter[] parameters = con3.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//暴力反射:临时取消权限的校验
con3.setAccessible(true);
//创建对象
Student student = (Student) con3.newInstance("张三", 123);
System.out.println(student);
}
}
①Class类中用于获取成员变量的方法:
Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields(): 返回所有成员变量对象的数组
Field getField(String name): 返回单个公共成员变量对象
Field getDeclaredField(String name): 返回单个成员变量对象
②Field类中用于创建对象的方法:
void set(Object obj,Object value): 赋值
Object get(Object obj) 获取值。
创建一个Student类:
public class Student {
private String name;
private int age;
public String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
主函数:利用反射修改成员变量
public class Main{
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//获取class字节码文件的对象
Class<?> clazz = Class.forName("case12.Student");
//获取公共的成员变量
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);//public java.lang.String case12.Student.gender
}
//获取所有的成员变量
Field[] fields1 = clazz.getDeclaredFields();
//获取单个的成员变量
Field gender = clazz.getField("gender");
//获取私有的成员变量
Field name = clazz.getDeclaredField("name");
//获取权限修饰符
int modifiers = name.getModifiers();
//获取成员变量名name的值
String n = name.getName();
//获取成员变量数据类型
Class<?> type = name.getType();
System.out.println(type);//class java.lang.String
//获取成员变量记录的值
Student s = new Student("zhangsan", 23, "男");
//临时取消访问权限
name.setAccessible(true);
Object value = name.get(s);
System.out.println(value);//zhangsan
//修改对象里面记录的值
name.set(s, "lisi");
System.out.println(s);//Student{name = lisi, age = 23, gender = 男}
}
}
①class类中用于获取成员方法的方法:
Method[] getMethods(): 返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods(): 返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes): 返回单个公共成员方法对象 Method getDeclaredMethod(String name, Class<?>… parameterTypes): 返回单个成员方法对象
②Method类中用于创建对象的方法:
Object invoke(Object obj, Object… args): 运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写
返回值:方法的返回值(如果没有就不写)
定义一个Student类:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public void sleep() {
System.out.println("睡觉");
}
private void eat(String something) throws IOException, NullPointerException, ClassCastException {
System.out.println("在吃" + something);
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
主函数:演示反射获取成员方法
public class Main{
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//获取class字节码文件对象
Class<?> clazz = Class.forName("case13.Student");
//获取公共的所有的方法对象
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);//包含了父类中的所有的公共方法
}
//获取所有的方法但不能获取父类的方法,但可以获取本类中私有方法
Method[] methods1 = clazz.getDeclaredMethods();
//获取私有的单个方法
Method m = clazz.getDeclaredMethod("eat", String.class);
//获取方法的修饰符
int modifiers = m.getModifiers();
//获取方法的名字
String name = m.getName();
//获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);//java.lang.String arg0
}
//获取方法抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
//运行方法
//定义方法的调用者
Student s = new Student();
//临时取消私有方法的访问权限
m.setAccessible(true);
m.invoke(s, "汉堡包");//在吃汉堡包
}
}
①获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
②结合配置文件,动态的创建对象并调用方法
在Java中,反射可以用于获取和操作类的信息,包括类的属性、方法、构造函数等。
动态获取类的信息
:使用反射可以在运行时动态获取类的信息,例如获取类的属性、方法、构造函数等,并可以通过反射来创建类的实例。动态创建对象
:通过反射可以在运行时动态创建一个类的对象,而无需在编译时提前知道需要创建哪个类的对象。调用对象的方法
:通过反射可以调用一个类的方法,包括公有方法和私有方法。这使得我们可以在运行时根据需要动态调用不同的方法。修改私有属性
:通过反射可以修改一个类的私有属性的值,即使这个属性没有提供公开的set方法。- 扩展应用:反射还可以用于实现一些框架和工具,例如注解处理器、对象序列化、单元测试等。
需要注意的是,反射使用起来较为复杂,在性能上也比直接调用方法要慢。因此,在使用反射时应该谨慎,并在必要的情况下才使用。