java的反射
一. 反射的由来
编译阶段:将java文件编译成字节码文件。
加载过程:通过类加载器,在方法区中加载类的静态属性和静态方法,在堆中存放该类的反射类对象。
运行过程:执行方法。
二. 反射的用法
首先创建Dog类
public class Dog { public String name; public int age; public String color; public Dog(){} public Dog(String name, Integer age, String color) { this.name = name; this.age = age; this.color = color; } public void run(){ System.out.println(name + "在跑步"); } public void sleep(){ System.out.println(name + "在睡觉"); } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + ", color='" + color + '\'' + '}'; } }
反射对象的方法使用
public class Reflection03 { public static void main(String[] args) throws Exception{ Class<?> aClass = Class.forName("com.hspedu.Dog"); // class com.hspedu.Dog aClass引用指向的是Dog类的Class【反射对象】 System.out.println(aClass); // class java.lang.Class aClass对象的运行类型Class【反射类】 System.out.println(aClass.getClass()); // 1.获取类的路径 String name = aClass.getName(); System.out.println(name); // 2.获取包名 Package aPackage = aClass.getPackage(); System.out.println(aPackage); // 3.1 获取无参构造器 // public com.hspedu.Dog() Constructor<?> constructor1 = aClass.getConstructor(); System.out.println(constructor1); // 3.2 获取带参构造器 // public com.hspedu.Dog(java.lang.String,java.lang.Integer,java.lang.String) Constructor<?> constructor2 = aClass.getConstructor(String.class, Integer.class, String.class); System.out.println(constructor2); // 4 获取对象【无参】 Object o = aClass.newInstance(); // com.hspedu.Dog System.out.println(o.getClass()); // 5.设置属性 Field dogName = aClass.getField("name"); dogName.set(o,"Tom"); Field age = aClass.getField("age"); age.set(o,8); Field color = aClass.getField("color"); color.set(o,"白色"); System.out.println(o); // 6.调用方法 Method run = aClass.getMethod("run"); run.invoke(o); Method sleep = aClass.getMethod("sleep"); sleep.invoke(o); // 7.一次性得到反射对象的属性 Field[] fields = aClass.getFields(); for (Field field : fields) { System.out.println(field.getName()); } } }
三. 获取反射对象
public class Reflection04 { public static void main(String[] args) throws Exception{ // 获取反射对象 // 方式1:编译阶段,通过Class.forName(类的路径) Class<?> aClass = Class.forName("com.hspedu.Dog"); System.out.println(aClass.hashCode()); // 方式2:加载阶段,类名.class Class<Dog> dogClass = Dog.class; System.out.println(dogClass.hashCode()); // 方式3:类加载器 Class<?> aClass1 = ClassLoader.getSystemClassLoader().loadClass("com.hspedu.Dog"); System.out.println(aClass1.hashCode()); // 方式4:基本数据类型.class Class<Integer> integerClass = int.class; System.out.println(integerClass.hashCode()); // 方式5:包装类.TYPE Class<Integer> type = Integer.TYPE; System.out.println(type.hashCode()); } }
运行结果:
1554874502 1554874502 1554874502 1846274136 1846274136
说明同一个类的反射对象只有一个。
四. 类加载解读
1. 静态加载和动态加载
加载包括:静态加载和动态加载
静态加载:在编译阶段,加载所有的类,遇到没有import导入的类,编译异常;
动态加载:在运行阶段,加载所需要的类,如果没有,不出现编译异常,但是肯定有运行异常。
动态加载:反射【五种方式】;
静态加载:new ;调用静态成员;子类被加载时,父类也被加载。
2. 类加载的具体过程
类加载图解:
这里的初始化,是静态成员的初始化,静态成员随着类的加载而加载。
类加载三个阶段的主要任务:
五.综合案例,获取类的结构信息
public class Reflection06 { public static void main(String[] args) throws Exception{ Class<?> aClass = Class.forName("com.hspedu.Student"); // 1.获取本类及其父类的public修饰的属性 Field[] fields = aClass.getFields(); for (Field field : fields) { System.out.println("本类及其父类的public修饰的属性: " + field.getName()); } // 2.获取父类的public修饰的属性 Class<?> superclass3 = aClass.getSuperclass(); Field[] fields1 = superclass3.getFields(); for (Field field : fields1) { System.out.println("父类的public修饰的属性: "+field.getName()); } // 3.获取本类中的所有属性 Field[] declaredFields1 = aClass.getDeclaredFields(); for (Field declaredField : declaredFields1) { System.out.println("本类的所有属性: " + declaredField.getName()); } // 4.获取父类的所有属性 Class<?> superclass = aClass.getSuperclass(); Field[] declaredFields2 = superclass.getDeclaredFields(); for (Field field : declaredFields2) { System.out.println("父类的所有属性: " + field.getName()); } // 5.获取本类以及父类的public修饰的方法 Method[] methods = aClass.getMethods(); for (Method method : methods) { System.out.println("本类以及父类的public修饰的方法: " + method.getName()); } // 6.获取父类的public修饰的方法 Class<?> superclass1 = aClass.getSuperclass(); Method[] methods1 = superclass1.getMethods(); for (Method method : methods1) { System.out.println("父类的public修饰的方法: " + method.getName()); } // 7.获取本类的所有方法 Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类的所有方法: " + declaredMethod.getName()); } // 8.获取父类的所有方法 Class<?> superclass2 = aClass.getSuperclass(); Method[] declaredMethods1 = superclass1.getDeclaredMethods(); for (Method method : declaredMethods1) { System.out.println("父类的所有方法: " + method.getName()); } // 9.获取本类的public修饰的无参构造器 Constructor<?>[] constructors = aClass.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("本类的public修饰的无参构造器: " + constructor.getName()); } // 获取本类指定的带参构造器 Constructor<?> constructor1 = aClass.getConstructor(String.class, String.class); System.out.println(constructor1); // 10.获取父类的public修饰的无参构造器 Class<?> superclass4 = aClass.getSuperclass(); Constructor<?>[] constructors1 = superclass4.getConstructors(); for (Constructor<?> constructor : constructors1) { System.out.println("父类的public修饰的无参构造器: " + constructor.getName()); } // 获取父类指定的带参构造器 Constructor<?> constructor = superclass4.getConstructor(String.class, int.class); System.out.println(constructor); // 11.获取本类所有的构造器 Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } // 12.获取父类的所有构造器 Class<?> superclass5 = aClass.getSuperclass(); Constructor<?>[] declaredConstructors1 = superclass5.getDeclaredConstructors(); for (Constructor<?> constructor2 : declaredConstructors1) { System.out.println(constructor2); } // 13.获取本类的实现的接口 Class<?>[] interfaces = aClass.getInterfaces(); for (Class<?> anInterface : interfaces) { System.out.println(anInterface); } } } interface i1 { } interface i2 { } class Person { private String name; int age; protected String nation; public String gender; public Person() {} public Person(String name,int age){ this.name = name; this.age = age; } private Person(String name, String nation) { this.name = name; this.nation = nation; } public void p1(){ } protected void p2(){ } void p3(){ } private void p4(){ } } class Student extends Person implements i1,i2{ private String stuId; String hobby; protected String job; public int height; public Student(){} public Student(String stuId,String hobby){ this.stuId = stuId; this.hobby = hobby; } private Student(String stuId,int height){ this.height = height; this.stuId = stuId; } public void s1(){ } protected void s2(){ } void s3(){ } private void s4(){ } }
运行结果:

本类及其父类的public修饰的属性: height 本类及其父类的public修饰的属性: gender 父类的public修饰的属性: gender 本类的所有属性: stuId 本类的所有属性: hobby 本类的所有属性: job 本类的所有属性: height 父类的所有属性: name 父类的所有属性: age 父类的所有属性: nation 父类的所有属性: gender 本类以及父类的public修饰的方法: s1 本类以及父类的public修饰的方法: p1 本类以及父类的public修饰的方法: wait 本类以及父类的public修饰的方法: wait 本类以及父类的public修饰的方法: wait 本类以及父类的public修饰的方法: equals 本类以及父类的public修饰的方法: toString 本类以及父类的public修饰的方法: hashCode 本类以及父类的public修饰的方法: getClass 本类以及父类的public修饰的方法: notify 本类以及父类的public修饰的方法: notifyAll 父类的public修饰的方法: p1 父类的public修饰的方法: wait 父类的public修饰的方法: wait 父类的public修饰的方法: wait 父类的public修饰的方法: equals 父类的public修饰的方法: toString 父类的public修饰的方法: hashCode 父类的public修饰的方法: getClass 父类的public修饰的方法: notify 父类的public修饰的方法: notifyAll 本类的所有方法: s4 本类的所有方法: s3 本类的所有方法: s1 本类的所有方法: s2 父类的所有方法: p4 父类的所有方法: p3 父类的所有方法: p1 父类的所有方法: p2 本类的public修饰的无参构造器: com.hspedu.Student 本类的public修饰的无参构造器: com.hspedu.Student public com.hspedu.Student(java.lang.String,java.lang.String) 父类的public修饰的无参构造器: com.hspedu.Person 父类的public修饰的无参构造器: com.hspedu.Person public com.hspedu.Person(java.lang.String,int) private com.hspedu.Student(java.lang.String,int) public com.hspedu.Student(java.lang.String,java.lang.String) public com.hspedu.Student() private com.hspedu.Person(java.lang.String,java.lang.String) public com.hspedu.Person(java.lang.String,int) public com.hspedu.Person() interface com.hspedu.i1 interface com.hspedu.i2
六.通过反射对象,创建实例
public class Reflection07 { public static void main(String[] args) throws Exception{ Class<?> aClass = Class.forName("com.hspedu.AA"); // 通过反射对象,创建实例 // 方式1: Object a1 = aClass.newInstance(); System.out.println(a1); // 方式2: Constructor<?> constructor = aClass.getConstructor(); Object a2 = constructor.newInstance(); System.out.println(a2); // 方式3: Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class); Object a3 = constructor1.newInstance("jack", 20); System.out.println(a3); // 方式4: // getConstructor()只能访问public属性的构造器 // getDeclaredConstructor()可以访问私有的构造器 Constructor<?> constructor2 = aClass.getDeclaredConstructor(String.class); // 爆破,可以访问private的构造器/属性/方法 constructor2.setAccessible(true); Object a4 = constructor2.newInstance("white"); System.out.println(a4); // 使用爆破,调用私有属性和方法 // getField() 访问public修饰的属性 // getDeclaredField() 可以访问private修饰的属性 Field name = aClass.getDeclaredField("name"); Field height = aClass.getField("height"); System.out.println("a4的height: " + height.get(a4)); // 使用属性.set修改public修饰的属性的值 height.set(a4,180.00); // 修改私有属性的值 // 方式1: 利用爆破,访问私有属性,修改private属性的值 name.setAccessible(true); name.set(a4,"jhon"); // 方式2: 通过反射调用public修饰的set()方法,修改private属性的值 Method setName = aClass.getMethod("setName", String.class); setName.invoke(a4,"zwGitOne"); System.out.println(a4); // 访问私有方法 // getMethod() 访问public修饰的方法 // getDeclaredMethod() 可以访问private修饰的方法 Method run = aClass.getDeclaredMethod("run"); run.setAccessible(true); run.invoke(a4); } } class AA { private String name = "tom"; int age = 10; protected String gender = "男"; public double height = 100.0; public void setName(String name) { this.name = name; } public AA(){} public AA(String name,int age){ this.name = name; this.age = age; } private AA(String name){ this.name = name; } private void run(){ System.out.println(name + " is running"); } @Override public String toString() { return "AA{" + "name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", height=" + height + '}'; } }
运行结果:
AA{name='tom', age=10, gender='男', height=100.0} AA{name='tom', age=10, gender='男', height=100.0} AA{name='jack', age=20, gender='男', height=100.0} AA{name='white', age=10, gender='男', height=100.0} a4的height: 100.0 AA{name='zwGitOne', age=10, gender='男', height=180.0} zwGitOne is running
总结:
// getField() 访问public修饰的属性 // getDeclaredField() 可以访问private修饰的属性 // getMethod() 访问public修饰的方法 // getDeclaredMethod() 可以访问private修饰的方法 // getConstructor()只能访问public属性的构造器 // getDeclaredConstructor()可以访问私有的构造器
declared,可以得到所有的属性/方法/构造器【但是不能对其进行修改,传参操作】,如果没有declared,则只能访问public修饰的属性/方法/构造器。
如果想要修改,传参,则必须 private属性.setAccessible(true)【爆破】,此时便能访问到属性/方法/构造器,自然能够进行修改和传参操作。
// 爆破私有构造器 constructor2.setAccessible(true); Object a4 = constructor2.newInstance("white"); // 爆破私有属性 name.setAccessible(true); name.set(a4,"jhon"); // 爆破私有方法 Method run = aClass.getDeclaredMethod("run"); run.setAccessible(true); run.invoke(a4);
分类:
java学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现