反射
概述
反射机制
JAVA反射机制是在 运行状态中 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性
- 在反射中,可以把方法视为对象(万物皆对象)
- 传统方法:对象.方法()
- 反射机制:方法.invoke(对象)
反射提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
反射的优缺点
- 优点:可以动态的创建和使用对象,使用灵活
- 缺点:使用反射基本是解释执行,对执行速度有影响
原理
- 在不修改源码的情况下,来控制程序,增加功能,符合设计模式的ocp(开闭)原则
虚拟机加载Class文件过程
- 在我们启动一个类,或者其他方式加载一个类的时候,会通过类的全限定名获取该类的二进制流,然后将字节流所代表的的静态存储结构转化成方法区的运行时数据结构,然后会生成一个代表该类的java.lang.Class 对象,作为在方法区这个类的访问入口
- 只要完成了这一步骤,那么通过这个入口我们就可以访问里面的存储好的数据结构信息了
- 而且动态加载的时候,会先进行查找,该类是否存在,存在了就不会再加载了,保持一份
Class类分析
特点
- Class也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class对象可以完整地得到一个类的完整结构,通过一系列API
- Class对象是存放在堆的
- 类的字节码二进制数据,是放在方法区的,也称为类的元数据(包括方法代码、变量名、方法名、访问权限等)
常用方法
- forName(String className):返回与带有给定字符串名的类或接口相关联的 Class 对象
- forName(String name, boolean initialize, ClassLoader loader) :使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象
- getAnnotation(Class annotationClass):如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null
- getAnnotations():返回此元素上存在的所有注释
- getConstructor(Class<?>… parameterTypes):返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法
- getDeclaredField(String name):返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段
- getDeclaredMethod(String name, Class<?>… parameterTypes):返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法
获取反射的方法
编译阶段:
- Class.forName(“类的全类名”)
多用于配置文件,读取类全路径,加载类
加载阶段:
- 通过 类.class
最为安全可靠,程序性能最高
多用于参数传递,如:通过反射得到对应构造器对象 - 通过类加载器
运行阶段
- 对象已存在,通过对象.getClass()
基本数据按如下方式得到Class类对象
- Class cls = 基本数据类型.class
基本数据类型对应的包装类,通过.TYPE得到Class类对象
- Class cls = 包装类.TYPE
类加载
- 反射机制是java实现动态语言的关键,通过反射实现类动态加载
- 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
- 动态加载:运行时加载需要的类,如果运行时没有使用到该类,则不报错,降低了依赖性