Java反向概述
反射(Reflection)机制是 Java 语言特性之一,是 Java被视为动态(或准动态)语言的一个关键特性。
Java反射有以下3个动态特性
- 运行时创建实例
- 运行期间调用方法
- 运行时更改属性
Java程序的执行过程
Person.java——》 | 编译器——》 | Person.class——》 | Java虚拟机——》 | 运行程序 |
Java反射可以实现的功能
- 在运行时探知任意一个实例所属的类
- 在运行时构造任意一个类的实例
- 在运行时探知任意一个类所真有的方法和属性
- 在运行时调用任意一个实例的方法
Java反射常用的API
使用Java反射技术常用的类
- java.lang.Class<T>类:反射的核心类,反射所有的操作都围绕该类来生成的。
- java.lang.reflect.Constructor<T>类:表示类的构造方法。
- java.lang.reflect.Field 类:表示类的属性,可以获取和设置类中属性的值。
- java.lang.reflect.Method 类:表示类的方法,可以用来获取类中方法的信息或执行方法。
反射的应用
在 Java 程序中使用反射的基本步骤如下
- 导入java.lang.reflect 包中的相关类。
- 获得需要操作的类的 Class 实例。
- 调用Class 实例的方法获取 Field、Method等实例。
- 使用反射 API操作实例成员。
获取对应类型基本信息的方法
方法 | 说明 |
String getName() | 以字符串形式返回该类型的名称 |
String getSimpleName() | 以字符串形式返回该类型的简称(类名) |
Package getPackage() | 获取该类型所在的包 |
Class getSuperclass() | 获取该类型的超类的 Class 实例 |
Class[] getinterfaces() | 返回该类型所实例的全部接口的 Class 实例 |
int getModifiers() | 返回该类型的所有修饰符,由public、protected、private、final、static、abstract等对应的int常量组成,返回的整数应使用Modifier 工具类来解码,才可以判断修饰符的构成。 |
Class[]getDeclaredClasses() | 返回该类型中包含的全部内部类的 Class 实例 |
Class getDeclaringClass() | 返回该类型所在的外部类的 Class 实例 |
获取对应类型所含构造方法的方法
方法 | 说明 |
Constructor getConstructor(Class... params) | 返回该类型指定参数列表的public 构造方法,构造方法的参数列表与params所指定的类型列表所匹配 |
Constructorl]getConstructors() | 返回该类型的所有public 构造方法 |
Constructor getDeclaredConstructor( Class... params) | 返回该类型的指定参数列表的构造方法,访问级别不限 |
Constructor[]getDeclaredConstructors() | 返回该类型的所有构造方法,访问级别不限 |
ConstructorgetDeclaredConstructor() | 获取该类型的无参构造函数 |
获取对应类型所含属性的方法
方法 | 说明 |
Field getField(String name) | 返回该类型中指定名称的public属性,name参数用于指定属性名称。例如:clz.getField("age");//clz为某 Class对象,age 为属性名 |
Field[] getFields() | 返回该类型中所有public属性 |
Field getDeclaredField(String name) | 返回该类型中指定名称的属性,与属性的访问级别无关 |
Field[] getDeclaredFields() | 返回该类型中的全部属性,与属性的访问级别无关 |
访问类包含方法的方法
方法 | 说明 |
Method getMethod( String name, Class... params) | 返回该实例中指定的public方法,name参数用于定方法名称,params参数指定参数列表 |
Method[] getMethods() | 返回该实例中所有public方法 |
Method getDeclaredMethod( String name, Class... params) | 返回该实例中指定的方法,与方法的访问级别无关 |
Method[lgetDeclaredMethods() | 返回该实例中的全部方法,与方法的访问级别无关 |
通过反射来创建 Java 类型的实例有如下两种方式
通过反射来创建 Java 类型的实例有如下两种方式
- 使用 Class 实例的 newinstance()方法创建相关类型的实例。
- 使用 Constructor 实例创建相关类型的实例。
构造方法来创建Java对象的步骤
- 获取与该类型相关的 Class 实例。
- 调用 Class 实例的方法获取表示指定构造方法的 Construetor 实例。
- 调用Constructor 实例的 newinstance()方法来创建相关类型的实例。
注意:
受访问修饰符的限制,使用反射方式访问超出访问范围的构造方法、属性、方法时,会引发 java.lang.legalAccessException 异常。若要禁止 Java 语言访问检查强行访问,需要设置相关实例为可访问,语法如下。
c3.setAccessible(true);// 通过构造方法/属性/方法实例调用
当然此种做法会破坏封装,需谨慎使用
访问属性的方法
方法 | 说明 |
xxx getXxx(Object obj) | xx表示8种基本数据类型之一,如int getInt(0bjectobj).obj 为该属性所在类的实例。假设instance 表示A类的实例,field 表示A类中的属性 a,则 field.getInt(instance)表示 以int类型返回 instance中属性a的值。若 Field 实例表示的是一个静态属性,则obj可以设置为 null |
Object get(object obj) | 以 object 类型返回 obj 中相关属性的值 |
void setXxx(Object obj, xxx val) | 将 obj中相关属性的值设置为val。xxx为8种基本数据类型之一 |
void set(Object obj, Object val) | 将 obj中相关属性的值设置为 val |
void setAccessible(boolean flag) | 对相关属性设置访问权限。设置为true可以禁止Java语言访问检查 |
知识扩展:
在 java.lang.reflect包下还提供了一个 Array 类,Array 实例可以代表一个数组。程序可以使用 Array 类来动态地创建数组及操作数组元素等。
类的部分常用方法
方法 | 说明 |
static Object newinstance(ClasscomponentType, int length) | 创建元素类型为componentType,长度为length的数组 |
static Obiect newinstance(ClasscomponentType,int...dimensions) | 创建多维数组,元素类型是 componentType,维数是 dimensions.length,dimensions 中的每一个元素决定每一维的长度 |
static int getLength(Object arr) | 返回数组 arr 的长度 |
static xxx getXxx(Object arr int index) | xx表示8种基本数据类型之一,以基本数据返回数组 arr 的长度类型返回数组 arr中索引为index的元素 |
static Object get(Object arr int index) | 以object 类型返回数组 arr 中索引为index 的元素 |
static void setXxx(Object arr, int index, xxx val) | 将 val 赋值给数组 arr 中索引为 index 的元素,xxx为8种基本数据类型之一 |
static void set(Object arr, int index, Object val) | 将 val赋值给数组 arr 中索引为index的元素 |
如下的代码中,创建了数组 arr,并为元素赋值。
//创建一个元素类型为String,长度为10的数组Object arr = Array.newinstance(String. class, 10);//为数组 arr中index为5的元素赋值
Array.set(arr , 5,"Jack");
//取出数纽arr 中index为5的元素的值Object o= Array .get(arr ,5);
使用 Array 类可以动态灵活地创建和操作数组,Array 类的更多方法可以在使用时査看’Java API。
注意:
使用反射虽然会很大程度上提高代码的灵活性,但是不能滥用反射,因为通过反射创建和访问实例时性能要稍微低一些,且反射可能会破坏封装。实际上,只有当程序需要动态创建类的实例时才会考虑使用反射通常,在通用性较广的框架、基础平台中反射技术会有大量的运用。类似于实战任务4所实现的数据动态处理能力,在很多Java 框架中都有更完善、更强大的实现,如将请求数据自动封装到 JavaBean、对JavaBean 中的属性值进行格式校验、将 SQL 查询结果封装到JavaBean、将 JavaBean 属性值赋值给 SQL查询条件等,都需要程序能够动态创建和操作 Java实例,这就必须使用反射技术。理解Java 反射机制,对以后学习框架技术会有很大的帮助。