反射是获取类信息的一种能力
类信息包括属性、方法、构造器、父类、接口等
类信息的来源
来自类的加载器,这是从.class文件到内存中的java虚拟器(JVM)中间的一个阶段(如下图)

类的加载器里,用Field数组存储成员变量,用method数组存储方法,用constructor存储构造器(如上图)。
Java运行流程分为三个阶段,其中第一个阶段在磁盘,第二三阶段(Class类对象阶段、Runtime运行时阶段)在内存(如上图)
三个阶段获取信息方式不同,第一阶段通过Class.forName("全类名"),第二阶段通过类名.class,第三个阶段通过对象名.getClass(),如下代码:
java
Class clazz1 = Class.forName("xxx");
Class clazz2 = Student.class;
Student student = new Student();
Class clazz3 = student.getClass();
上面代码里的clazz1、clazz2、clazz3指向相同地址,其是一个对象
类信息的获取
通过Class.forName("Test20250218.Student")
获取到Student
类的Class
对象。这一步是反射的基础,它允许程序在运行时动态地加载类。Test20250218.Student
是类的全限定名,即包括包名和类名。接着,使用clazz.getDeclaredFields()
获取Student
类声明的所有字段,包括私有字段。这些字段被封装在Field
数组中返回。然后,通过System.out.println(Arrays.toString(fields))
将这些字段信息打印出来。随后,clazz.getFields()
方法被调用,它返回的是类中所有可访问的公共字段。与getDeclaredFields()
不同,getFields()
只返回公共字段,忽略私有字段和受保护字段。同样,这些字段信息也被打印出来。紧接着,代码通过clazz.getDeclaredMethods()
获取Student
类中声明的所有方法,包括私有方法。这些方法被封装在Method
数组中返回。然后,打印出这些方法的信息。clazz.getMethods()
方法被调用,返回的是类中所有可访问的公共方法,包括从父类继承的公共方法。与getDeclaredMethods()
不同,getMethods()
不仅返回类自身的方法,还包括继承的公共方法,并且忽略私有方法和受保护方法。同样,这些信息也被打印出来。最后,通过clazz.getDeclaredConstructors()
获取Student
类中声明的所有构造器,这些构造器被封装在Constructor
数组中返回。然后,打印出这些构造器的信息。clazz.getConstructors()
方法返回的是类中所有可访问的公共构造器。与getDeclaredConstructors()
不同,getConstructors()
只返回公共构造器,忽略私有构造器和受保护构造器。这些构造器的信息也被打印出来。

没有Declared只能获取public的数据,而加上Declared可以获得所有修饰符修饰的数据
单独获取某个属性
下面代码通过Class.forName("Test20250218.Student")
加载Student
类并获取其Class
对象,随后利用反射API动态地访问并展示了该类的字段和方法信息。具体地,它使用getField
和getDeclaredField
方法分别获取了公共字段age
和任意访问修饰符的字段height
、sex
的Field
对象,并打印了这些信息;同时,它使用getDeclaredMethod
方法获取了无参方法run
、带有String
和int
参数的方法run
、无参方法getAge
以及带有一个String
参数的方法getNameString
的Method
对象,并同样打印了这些信息

下面代码首先通过Class.forName("Test20250218.Student")
加载了Test20250218.Student
类,并获取其Class
对象clazz
。接着,利用反射API中的getDeclaredConstructor
方法,分别获取了Student
类中声明的四个不同参数列表的构造方法:第一个构造方法接受String
、int
、double
、char
四个参数;第二个构造方法接受int
、double
、char
三个参数;第三个构造方法接受double
、char
两个参数;第四个构造方法仅接受一个char
参数。每个获取的构造方法都被封装在Constructor
对象中,并立即通过System.out.println
方法打印出来,展示了Student
类中声明的这些构造方法的信息。

类信息的使用
下面代码首先通过Class.forName("Test20250218.Student")
加载了Test20250218.Student
类,并获取其Class
对象clazz
。接着,利用反射API中的getDeclaredConstructor
方法,首先获取了Student
类中声明的无参构造方法,并通过调用newInstance
方法创建了Student
类的一个实例对象student
。然后,获取了接受double
和char
两个参数的构造方法,并通过调用newInstance
方法并传入参数185.5
和'男'
创建了另一个Student
实例对象student1
。最后,获取了仅接受一个char
参数的构造方法,由于该构造方法可能受到访问修饰符(如private
)的限制,因此通过调用setAccessible(true)
方法忽略了Java的访问控制检查(即进行了暴力反射),随后调用newInstance
方法并传入参数'女'
创建了第三个Student
实例对象student2
。

private修饰的数据是在其他类当中访问不到的,所以只能忽略访问权限修饰符的安全检查,
暴力反射针对的就是private修饰的数据


上述代码合集:
java
package Test20250218;
public class Student {
//属性
private String name;
public int age;
double height;
protected char sex;
//方法
private void run(){
System.out.println("学生跑的很快....");
}
public int getAge(){
return this.age;
}
String getNameString(String name) {
return name;
}
protected void run(String a,int b) {
System.out.println(a+""+b);
}
Student(String name,int age,double height,char sex){
this.name = name;
this.age = age;
this.height = height;
this.sex = sex;
}
public Student(int age,double height,char sex){
this.age = age;
this.height = height;
this.sex = sex;
}
protected Student(double height,char sex){
this.height = height;
this.sex = sex;
}
private Student(char sex){
this.sex = sex;
}
Student(){
}
}
java
package Test20250218;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// //获取类对象
Class clazz=Class.forName("Test20250218.Student");
//
// 1
// Field[] fields =clazz.getDeclaredFields();
// System.out.println(Arrays.toString(fields));
//
// Field[] fields1 = clazz.getFields();
// System.out.println(Arrays.toString(fields1));
//
// //获取方法
// Method[] methods = clazz.getDeclaredMethods();
// System.out.println(Arrays.toString(methods));
//
// Method[] methods1 = clazz.getMethods();
// System.out.println(Arrays.toString(methods1));
//
// //获取构造器
// Constructor[] declaredConstructors=clazz.getDeclaredConstructors();
// System.out.println(Arrays.toString(declaredConstructors));
//
// Constructor[] declaredConstructors1=clazz.getConstructors();
// System.out.println(Arrays.toString(declaredConstructors1));
// 2
// //age是public类型修饰的,那么我们使用getField可以获取到数据,也可以使用
// //getDeclaredField获取数据
// Field ageField = clazz.getField("age");
// System.out.println(ageField);
//
// Field heightField = clazz.getDeclaredField("height");
// System.out.println(heightField);
//
// Field sexField = clazz.getDeclaredField("sex");
// System.out.println(sexField);
//
// Method runMethod = clazz.getDeclaredMethod("run");
// System.out.println(runMethod);
//
// Method runMethod1 = clazz.getDeclaredMethod("run",String.class,int.class);
// System.out.println(runMethod1);
//
// Method getAge = clazz.getDeclaredMethod("getAge");
// System.out.println(getAge);
//
// Method getNameString = clazz.getDeclaredMethod("getNameString", String.class);
// System.out.println(getNameString);
// System.out.println("--------------------------------");
//
// 3
// 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);
//
// Constructor constructor3 = clazz.getDeclaredConstructor(double.class,char.class);
// System.out.println(constructor3);
//
// Constructor constructor4 = clazz.getDeclaredConstructor(char.class);
// System.out.println(constructor4);
// 4
// Constructor constructor=clazz.getDeclaredConstructor();
// Student student=(Student)constructor.newInstance();
//
// Constructor constructor1=clazz.getDeclaredConstructor(double.class,char.class);
// Student student1=(Student)constructor1.newInstance(185.5,'男');
//
// Constructor constructor2=clazz.getDeclaredConstructor(char.class);
// //private修饰的数据是在其他类当中访问不到的
// //所以只能忽略访问权限修饰符的安全检查
// constructor2.setAccessible(true);//暴力反射---------》针对的就是private修饰的数据
// Student student2=(Student)constructor2.newInstance('女');
// 5
// Constructor constructor=clazz.getDeclaredConstructor();
// Student student=(Student)constructor.newInstance();
// //对属性的赋值、取值
// Field nameField=clazz.getDeclaredField("name");
// //赋值
// nameField.setAccessible(true);//暴力反射
// nameField.set(student,"张三");//set()需要两个参数分别是对象和值
// System.out.println(nameField.get(student));
// Field ageField = clazz.getField("age");
// ageField.set(student,18);
// System.out.println(ageField.get(student));
// Field heightField = clazz.getDeclaredField("height");
// heightField.set(student,185.5);
// System.out.println(heightField.get(student));
// Field sexField = clazz.getDeclaredField("sex");
// sexField.set(student,'女');
// System.out.println(sexField.get(student));
// 6
Constructor constructor =clazz.getDeclaredConstructor();
Student student=(Student)constructor.newInstance();
Method run =clazz.getDeclaredMethod("run");
run.setAccessible(true);
run.invoke(student);
Method getAge =clazz.getDeclaredMethod("getAge");
getAge.invoke(student);
Method getStingName = clazz.getDeclaredMethod("getNameString",String.class);
String name =(String)getStingName.invoke(student,"aaaaa");
System.out.println(name);
Method run1=clazz.getDeclaredMethod("run",String.class, int.class);
run1.invoke(student, "bbbb",99);
}
}