java反射
反射
利用反射机制,可以通过外部文件配置,在不修改源码的情况下控制程序,符合设计模型中OCP原则
- 反射机制允许程序在执行期间借助于
Reflection
API取得任何类的内部信息(成员变量、构造器、成员方法等),并能操作对象的属性及方法。 - 加载类之后,在堆中产生了一个
Class
类型的对象,这个对象包括了类的完整结构信息。这个对象就像一面镜子,通过这个镜子看到类的结构,所以称之为:反射 - 反射可以做到的事:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
- 使用反射后,程序的执行速度会受到影响
反射相关的类
常用的反射相关的类都在java.lang
包中
- Class:代表一个类,表示某个类加载后在堆中的对象
- reflect.Method:类的方法
- reflect.Field:类的成员变量,不能得到private属性
- reflect.Constructor:构造器
Class类
- Class类也是继承Object的类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class对象,在内存中只有一份,因为类只加载一次(比如在使用反射加载类对象之前已经实例化过一次该类,就不会再调用loadClass方法)
- Class对象存放在堆中
- 类的字节码二进制数据存放在方法区,称为类的元数据
常用方法
方法名 | 功能 |
---|---|
static Class forName() | 返回指定类名的Class对象 |
Object newInstance() | 返回Class对象的一个实例 |
String gatName() | 返回Class对象所表示的实体(类,接口,基本类型等)的名称 |
Class getSuperClass() | 返回其父类 |
Constructor[] getConstructors() | 返回本类的构造器 |
ClassLoader getClassLoader() | 返回类的加载器 |
Field[] getFields() | 返回所有public修饰的属性,包括本类及父类 |
Field[] getDeclaredFields() | 返回本类所有属性 |
Method[] getMethods() | 返回所有public修饰的方法,包括本类及父类 |
Method[] getDeclaredMethods() | 返回本类所有方法 |
获取Class对象
- 若已知一个类的完整路径“包名.类名”,可以通过Class类的
forName()
获取。应用场景:配置文件,读取类全路径,加载类 - 若已知具体的类,可以通过
类.class
获取,该方式也可以获取基本数据类型的Class对象。应用场景:用于参数传递,如通过反射的对应构造器对象。 - 如果已经有该类的实例,可以通过
对象.getClass()
获取Class对象 - 通过类加载器获取:
ClassLoader classLoader = test.getClass().getClassLoader();
Class cls = classLoader.loadClass(classAllPath); // classAllPath为类的完整路径
- 基本数据类型的包装类(Integer,Boolean等)可以通过
.TYPE
获取Class对象
类加载
类加载分为静态加载和动态加载。
静态加载:编译时加载相关的类,如果没有则报错,哪怕不一定会用到这个类,也会加载
动态加载:运行时加载需要的类,如果运行时不用该类就不会报错,反射使用的就是动态加载方案
public class Test{ |
类加载的过程
大体流程如下图所示。
首先对源码进行编译,生成字节码文件,在运行时进入类加载,由类加载器将类的class文件读入内存,并创建一个Class对象。
然后进入连接阶段,把二进制数据合并到JRE中,验证:对文件安全性进行验证,准备:对静态变量进行默认初始化并分配空间,解析:把符号引用转成直接引用(地址引用)。最后进行初始化,由JVM负责,执行<clinit>()
方法。
<clinit>()
方法是由编译器按照语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并。虚拟机会保证一个类的<clinit>()
方法在多线程环境中被正确的加锁,同步。如果多个线程同时去初始化一个类,同一时间内只允许一个线程执行此方法。
Field类常用方法
方法名 | 功能 |
---|---|
getModifiers() | 以int形式返回修饰符 |
getType() | 以Class形式获取返回类型 |
getName() | 返回属性名 |
getParameterTypes() | 以Class[] 返回参数类型数组 |
注:在getModifiers()
方法中,返回的int形式为:默认是0,public是1,private是2,protected是4,static是8,final是16。如果有多个修饰符就代数相加。
反射暴破
使用反射机制访问private属性、方法、构造器,称为暴破(暴力破解),可以破坏封装特性。
示例
public class Test{ |