反射
在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法;并且对于任意一个对象,都能调用它的任意一个方法;这种动态获取信息及动态调用对象方法的功能称为Java语言的反射机制。
类的执行过程
类的执行过程可以分为4个部分:编译、加载、连接、初始化。
(1)编译。就是将源文件编译成字节码文件的过程,即将.java文件编译成.class文件。
(2)加载。就是把.class文件通过虚拟机加载到内存中。
(3)连接。这个过程分为三个阶段。
验证阶段:主要检验.class文件的格式是否规范。
准备阶段:正式的给类变量(static变量),分配内存,并给内存中的变量赋原值。
解析阶段:将栈内存中的引用变量指向堆内存中的数据,并分配内存地址。
(4)初始化。及new实例化类的对象或反射实例化对象。
而类在加载过程中的步骤为:
(1)JVM将A.class文件读入内存方法区(运行时内存)
(2)JVM将A.class创建唯一的Class类的对象(在堆内存中创建)
此处的Class是一个实实在在的类,不是一个类关键词class。
public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type,AnnotatedElement{}
反射的定义
通过Class类的对象可以反向做很多事,如:
(1)获取类的属性、方法
(2)生成类的实例
(3)调用实例的方法、属性
反射通过操作Class类的对象,实现对类的操作以及对对象的操作
反射使我们在运行时看清一个类的运行情况并使用。
反射是Java被视为动态或准动态语言的关键特性。
反射允许程序在运行时加载、探查、使用一个在编译期可能未知的类。
编译时无法预知对象或类属于什么类型,需要依靠运行时信息来发现真实信息(完整结构、创建实例、操作属性和方法等),此时需要使用反射。
基于反射获取类信息
需要用到一些Reflection API:
java.lang包中的Class类
是反射的核心类,可获取类的属性、方法等信息,生成类的实例。
java.lang.reflect包中的Field类
表示类的成员变量,可以用来获取和设置类的属性值。
java.lang.reflect包中的Method类
表示类的方法,可用来获取类中的方法信息或者执行方法。
java.lang.reflect包中的Constructor类
表示类的构造方法
使用反射的步骤:
(1)获取想要操作的类的Class对象
(2)调用Class类中的方法
(3)使用反射API来操作这些信息
(1)获取Class对象
1.通过Class类的静态方法Class.forName(className) (比较常用的方式)
2.调用对象实例的getClass()方法
3.调用某个类的class属性
(2)Class类中常用的方法
1.获取属性的方法(返回Field类)
getFields() 所有可访问的公共字段(public修饰的字段)
getDeclaredFields() 所有字段
getField(String name) 返回一个特定的公共字段对象
2.获取方法(返回Method类)
getMethods() 所有公共方法,包括从超类(父类)和超接口继承的声明
getDeclaredMethods() 所有方法,但不包括继承的方法
getMethod(String name,Class[]parameterTypes) 返回一个方法对象
(String name 代表方法名,Class[]parameterTypes代表参数类型,无参写null)
getDeclaredMethod(String name,Class[]parameterTypes) 从所有方法中选择特定方法,如果要选用私有方法,需要结合setAccessible(true)(允许私有方法调用)使用。
(3)获取构造方法
getConstructor(Class[]parameterTypes) 返回一个构造方法对象
通过Constructor的newInstance(Object[]initargs)可生成类的实例
通过Method的invoke(Object obj,Object[]args),可在具有指定参数的方法对象上调用此方法对象表示的基础方法。
示例:
//1.将类的信息装载到jvm中
Class cla = Class.forName("cn.ref.ChildrenDayPS");
//2.获取无参构造方法
Constructor constructor =cla.getConstructor();
//3.使用反射实例化对象
Object ps =constructor.newInstance();
//4.获取打折的方法
Method method =cla.getMethod("promoteSales",String.class);
//5.调用实例对象的打折方法
Double discount = (Double)method.invoke(ps,"1");
使用反射的优缺点
优点:
(1)运行期类型的判断,动态类加载
(2)提高了程序的灵活性、扩展性,降低耦合性
(3)提高自适应能力,无需提前硬编码目标类
缺点:
(1)性能问题
(2)安全限制
(3)内部暴露
反射应用场景:
(1)反射机制是目前众多Java框架实现的基础,如:
JDBC
Hibernate
Spring AOP.IoC
分布式微服务
(2)实现项目安装插件功能
基于反射,架构师搭建项目框架,自行封装框架,使得项目更加组件化和通用化。