Loading... ## 反射快速入门 ### 主程序: ```java import com.Dog; import java.io.FileInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Properties; /** * @code Description 通过外部配置文件,在不修改源码的情况下,来控制程序,符合设计模式ocp原则(开闭原则:在不修改源码,扩展功能) * @code author 本当迷 * @code date 2022/7/28-14:11 */ public class 反射快速入门 { public static void main(String[] args) throws Exception{ final Dog dog1 = new Dog(); // 创建对象 final Class<?> aClass = Class.forName("com.Dog"); // 创建对象实例 final Object dog = aClass.getConstructor().newInstance(); // 创建对象方法 final Method method = aClass.getMethod("eat"); // 通过方法调用对象,传统的方法对象掉方法(反射,反射,反着来) method.invoke(dog); // 创建对象属性 final Field name = aClass.getField("address"); // 设置私有属性可以被访问 name.setAccessible(true); // 传统写法:对象.成员变量 反射:成员变量.get(对象) final Object o = name.get(dog); System.out.println(o); // 创建对象构造器 注意:int.class 和 Integer.class不一样 final Constructor<?> constructor = aClass.getConstructor(String.class, int.class); System.out.println(constructor); final Object instance = constructor.newInstance("本当迷", 19); System.out.println(instance); } } ``` ### dog类: ```java package com; /** * @code Description * @code author 本当迷 * @code date 2022/7/28-14:11 */ public class Dog { private String name; private int age; public String address = "贵州"; public Dog(String name, int age) { this.name = name; this.age = age; } public Dog() { } public void eat(){ System.out.println("狗爱吃骨头!"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } ``` ## 反射原理图  ## 反射相关主要类: * java.lang.Class: 代表一个类,Class对象表示某个类加载后在堆中的对象 * java.lang.reflect.Method: 代表类的方法,Method对象表示某个类的方法 * java.lang.reflect.Filed: 代表类的成员变量,Field对象表示某个类的成员变量 * java.lang.reflect.Constructor: 代表类的构造方法,Constructor对象表示构造器 ## 反射机制: ### 优点: 可以动态的创建和使用对象(也是框架底层的核心),使用灵活,没有反射机制,框架的底层就失去了支撑 ### 缺点: 使用反射基本时解释执行的,对执行速度有影响 ### 反射调优优化--关闭访问检查 1. Method和field、Counstructor对象都有setAccessible()方法 2. setAccessible作用是启用和禁用访问安全检查的开关 3. 参数为true表示:反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查(私有属性、私有方法等私有权限修饰的都不能进行访问) ## Class类分析 * Class也是类,因为也继承Object类 * Class类对象不是new出来的,而是系统创建的 * 对于某个类的Class类对象,在内存中只有一份,因为**类只加载一次** * 每个类的实例都会记得自己是由哪个Class实例所生成 * 通过Class对象可以完整地得到一个类的完整结构 * Class对象是存放在堆中 * 类的字节码二进制数据,是放在方法区中,有的地方也称类的元数据(包括 方法代码、变量名、方法名、访问权限等等) ## 哪些类型有Class对象 * 外部类、成员内部类、静态内部类、局部内部类、匿名内部类 * interface接口 * 数组 * enum枚举 * annotation注解 * 基本数据类型 * void ## 类加载: ### 基本说明 反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。 1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强 2. 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类也不报错,降低了依赖性 ### 类加载时机 1. 当创建对象时(new) 2. 当子类被加载时,父类也加载 3. 通过类中静态成员时 4. 通过反射 ## 类加载流程图 ### 一:  ### 二:  ### 三: 1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行< clinit >()方法的过程 2. < clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有**静态变量**的赋值动作和**静态代码块**中的语句,并进行合并。 3. 虚拟机会保证一个类的< clinit>()方法在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的< clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行< clinit>()方法完毕 ## 通过反射获取类的结构信息(重点) <div class="tip inlineBlock success"> 1. getName:获取全类名 2. getSimpleName:获取简单类名 3. getFields:获取所有public修饰的属性,包含本类以及父类 4. getDeclaredFields:获取本类中的所有属性 5. getMethods:获取所有public修饰的方法,包含本类以及父类的 6. getDeclaredMethods:获取本类中所有的方法 7. getConstructors:获取所有public修饰的构造器,包含本类没有父类 8. getDeclaredConstructtor:获取本类中所有的构造器 9. getPackage:以Package形式返回包信息 10. getSuperClass:以Class形式返回父类信息 11. getInterfaces:以Class[]形式返回接口信息 12. getAnnotations:以Annotation[]形式返回注解信息 **可以说:如果我们拿到类的class对象,就可以拿到关于这个类的所有信息** </div> ## 通过反射创建对象 1. 调用类中的public修饰的无参构造器 2. 调用类中的指定构造器 3. Class类中的相关方法 * newInstance:调用类中的无参构造器,获取对应类的对象 * getConstructor(Class...clazz):根据参数列表,获取对应的public构造器对象 * getDecalaredConstructor(Class...clazz):根据参数列表,获取构造器对象 4. Constructor类的相关方法 * setAccessible(true):设置私有属性可以被操作 * newInstance(Object...obj):调用构造器 ## 通过反射访问类中成员 ### 访问属性 1. 根据属性名获取Field对象 Field f = clazz对象.getDeclaredField(属性名) 2. 爆破:f.setAccessible(ture); //f是field 3. 访问 f.set(o对象, 值) 4. 如果是静态属性,则set和get中参数o对象,可以写成null ### 访问方法 1. 根据方法名和参数列表获取Method方法对象:Method m = clazz.getDeclaredMethod(方法名, 形参类型.class) 2. 获取对象:Object o = clazz.newInstance(); 3. 爆破:m.setAccessible(true); 4. 访问:Object returnValue = m.invoke(o, 形参列表) 5. 注意:如果是静态方法,则invoke的参数o,可以写成null > 在反射中,如果有返回值,统一返回值类型为Object,但是它运行类型和方法定义的返回类型一致(典型的多态) 最后修改:2022 年 07 月 28 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 如果文章有用,请随意打赏。