一、Java反向概述
反射(Reflection)机制是Java语言特性之一,是Java被视为动态(或准动态)语言的一个关键特性。
1. 什么是反射
在计算机领域,反射指一种能力,能够自描述和自控制,即在运行状态中,动态获取类信息以及动态调用实例方法的能力。
Java反射有以下三个动态特性:
运行时创建实例
运行期间调用方法
运行时更改属性
如何理解 Java 的反射机制昵?首先来回顾一下 Java 程序的执行过程,如图下所示。Java程序要想运行,Java 类必须被Java 虚拟机加载。
从左到右的执行过程:
Person.java ----- > 编辑器 -----> Person.class ----- > Java虚拟机 -----> 运行结果
之前我们所运行的程序都是在编译时就已经链接了所有所需的类,而 Java 反射机制则允许程序在运行时再加载、探知、使用那些在编译时完全未知的类。
反射机制允许 Java 程序加载一个运行时才得知其名称的类,获悉其完整 API信息,包括其修饰符(诸如 public、static 等)、超类、实现的接口,也包括属性和方法的所有信息,并可生成其实例、对其属性赋值或调用其方法。通过Java 反射可以实现以下功能:
在运行时探知任意一个实例所属的类
在运行时构造任意一个类的实例
在运行时探知任意一个类所真有的方法和属性
在运行时调用任意一个实例的方法
2. Java 反射常用的 API
使用 Java 反射技术常用的类如下:
java.lang.Class<T>类:反射的核心类,反射所有的操作都围绕该类来生成的。通过 Class类可以获得类的属性、方法等内容信息
java.lang.reflect.Constructor<T>类:表示类的构造方法
java.lang.reflect.Field 类:表示类的属性,可以获取和设置类中属性的值
java.lang.reflect.Method 类:表示类的方法,可以用来获取类中方法的信息或执行方法
3. 反射的应用
在 Java 程序中使用反射的基本步骤如下:
1.导入java.lang.reflect 包中的相关类
2.获得需要操作的类的 Class 实例
3.调用 Class 实例的方法获取 Field、Method 等实例
4.使用反射 API操作实例成员
二、获取类的信息
一个类或接口被加载后,从系统中都能获得一个代表该类或接口的 class 类型的实例,通
过该实例就可以访问到Java 虚拟机中的这个类或接口。
1. 获得 Class 实例
Java 程序中获得 Class 实例通常有如下3种方式:
1.调用类或接口实例的 getclass()方法:
2.getClass()方法是 java.lang.0bject 类中的一个方法,所有类和接口的实例都可以调用该方法该方法会返回该实例的所属类型所对应的 class 实例。
3.调用类或接口的 class 属性:
在某些类或接口没有实例或无法创建实例的情况下,可以通过其 class 属性获取所对应的Class 实例,这种方式需要在编译期就知道类或接口的名称。
1.使用 Class.forName()方法:
若编码时无法确认具体类型,需要程序在运行时根据情况灵活加载,可以使用Class类的forName()方法。该方法是静态方法,需要传入字符串参数,该字符串参数的值是某个类的完全限定类名,即包含包名的完整类名。
2. 从 Class 实例获取信息
在获得了某个类型对应的Class实例之后,就可以调用Class实例的方法来获取该类型的信Class 类提供了大量实例方法来获取对应类型的详细信息。
获取对应类型基本信息的常用方法:
方法 | 说明 |
String getName() | 以字符串形式返回该类型的名称 |
String getSimpleName() | 以字符串形式返回该类型的简称(类名) |
Package getPackage() | 获取该类型所在的包 |
Class getSuperclass() | 获取该类型的超类的 Class 实例 |
Class[] getlnterfaces() | 返回该类型所实例的全部接口的 Class 实例 |
int getModifiers() | 返回该类型的所有修饰符,由public、protected、private、final、static、abstract等对应的int 常量组成,返回的整数应使用Modifier 工具类来解码,才可以判断修饰符的构成。 |
Class[] getDeclaredClasses() | 返回该类型中包含的全部内部类的Class 实例 |
Class getDeclaringClass() | 返回该类型所在的外部类的 Class 实例 |
获取对应类型所含构造方法的常用方法:
Constructor getConStructor(Class... params) 返回该类型指定参数列表的 public 构造方法,构造方法的参数列表与 params 所指定的类型列表所匹配
Constructor[] 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[l getDeclaredMethods() 返回该实例中的全部方法,与方法的访问级别无关
3. 通过反射来创建 Java 类型的实例有如下两种方式。
通过反射来创建Java 类型的实例有如下两种方式:
使用 Class 实例的 newInstance()方法创建相关类型的实例
使用 Constructor 实例创建相关类型的实例
如果创建Java 实例时, 需要使用指定的构造方法,则可以利用 Constructor 实例,每个 Constructor 实例对应一个构造方法,指定构造方法来创建Java 对象的步骤如下。
1.获取与该类型相关的 Class 实例
2.调用 Class 实例的方法获取表示指定构造方法的 Constructor 实例
3.调用 Constructor 实例的 newlnstance()方法来创建相关类型的实例
注意:受访问修饰符的限制,使用反射方式访问超出访问范围的构造方法、属性、方法时,会引发 java.lang.legalAccessException 异常。若要禁止 Java 语言访问检查强行访问,需要设置相关实例为可访问,语法如下。
c3.setAccessible(true);// 通过构造方法/属性/方法实例调用
当然此种做法会破坏封装,需谨慎使用。