java提供的反射机制可以实现在程序运行时对用户输入的信息进行验证,还可以逆向控制程序的执行过程。
通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。java.lang.reflect包中提供了对反射功能的支持。
由于所有的类都继承了Object类,故都实现了getClass()方法。getClass()方法返回了一个类型为Class的对象,如Class classTest = test.getClass();
。使用Class类的对象可以对test对象中的各种描述信息进行访问。下面是Class类中的常用方法:
组成部分 | 访问方法 | 返回值类型 | 说明 |
---|---|---|---|
包路径 | getPackage() | Package对象 | 返回该类的存放路径 |
类名称 | getName() | String对象 | 获得该类的名称 |
继承类 | getSuperclass() | Class对象 | 获得该类继承的类 |
实现接口 | getInterfaces() | Class型数组 | 获得该类实现的所有接口 |
构造方法 | getConstructors() | Constructor型数组 | 获得所有权限为public的构造方法 |
getConstrutor(Class>…parameterTypes) | Constructor对象 | 获得指定构造方法 | |
getDeclaredConstructors() | Constructor型数组 | 获得所有构造方法,按声明顺序返回 | |
getDeclaredConstructor(Class>…parameterTypes) | Constructor对象 | 获得指定的构造方法 | |
方法 | getMethods() | Method数组 | 获得所有权限为public的方法 |
getMethod(String name , Class>…parameterTypes) | Method对象 | 获得权限为public的指定方法 | |
getDeclaredMethods() | Method数组 | 获得所有的方法,按声明顺序返回 | |
getDeclaredMethod(String name , Class> … parameterTypes) | Method对象 | 获得指定方法 | |
成员变量 | getFields() | Field数组 | 获取所有权限为public的成员变量 |
getField(String name) | Field对象 | 获取指定public成员变量 | |
getDeclaredFields() | Field数组 | 获取所有成员变量,按声明顺序返回 | |
getDeclaredField(String name) | Field对象 | 获取指定成员变量 | |
内部类 | getClasses() | Class数组 | 获取所有权限为public的内部类 |
getDeclaredClasses() | Class数组 | 获取所有内部类 | |
内部类的声明类 | getDeclaringClass() | Class对象 | 如果该类为内部类,则返回他的成员类,否则返回null |
注意:在使用getFields()方法和getMethods()方法时,将会包含从父类中继承得到的成员变量和成员方法;当使用getDeclaredFields()和getDecaleredMethods()方法时只是获得该类中定义的所有成员变量与方法。
由上可知,可以通过一些Class类中的方法访问特定对象的构造方法。这些方法将会返回Constructor对象或Constructor数组,每一个对象都对应着一个特定的构造方法。
getConstructors()
getConstrutor(Class>…parameterTypes)
getDeclaredConstructors()
getDeclaredConstructor(Class>...parameterTypes)
如访问一个入口参数类型依次是String类和int类的构造方法时,需要使用以下形式:
classObject.getDeclaredConstructor(String.class , int.class)
Constructor类中定义的方法有:
方法 | 说明 |
---|---|
isVarArgs() | 是否允许带有可变数量的参数,允许则返回true |
getParameterTypes() | 返回Class型数组,依次获得该构造函数的参数类型 |
getExceptionTypes() | 返回Class数组,获取该构造方法可能抛出异常的类型 |
newInstance(Object…initargs) | 通过该构造方法使用指定参数创建一个该类的对象,如果未设置参数则表示使用默认构造方法 |
setAccessible(boolean flag) | 如果该构造方法的权限为private,默认为不允许通过反射利用newInstance方法创建对象,如果先执行该方法,并将入口参数设置为true,则可以进行对象创建 |
getModifiers() | 获得可以解析出该构造方法所采用修饰符的整数 |
通过java.lang.reflect.Modifier类可以解析出getModifier()方法返回值所表示的修饰符信息,该类中定义的方法如下:
静态方法 | 说明 |
---|---|
isPublic(int mod) | 查看是否由public修饰 |
isPrivate(int mod) | 查看是否由private修饰 |
isProtected(int mod) | 查看是否由protected修饰 |
isStatic(int mod) | 查看是否由Static修饰 |
isFinal(int mod) | 查看是否由final修饰 |
toString(int mod) | 以字符串形式返回所有修饰符 |
下面使用实例对类的构造方法进行访问:
package com.mw01;
//创建基本类作为访问构造函数的实例类
public class Example_01 {
String string ;
int i,i2,i3;
private Example_01() {}
protected Example_01(String string, int i) {
super();
this.string = string;
this.i = i;
}
public Example_01(String ...strings) throws NumberFormatException{
if (0 < strings.length) {
i = Integer.valueOf(strings[0]);
}
if (1 < strings.length) {
i2 = Integer.valueOf(strings[1]);
}
if (2 < strings.length) {
i3 = Integer.valueOf(strings[2]);
}
}
public void print(){
System.out.println("string = " + string);
System.out.println("i = " + i);
System.out.println("i2 = " + i2);
System.out.println("i3 = " + i3);
}
}
package com.mw01;
import java.lang.reflect.Constructor;
public class Main_01 {
public static void main(String[] args) {
Example_01 example = new Example_01("example" , 1);
//创建实例类的对象作为研究对象
Class<? extends Example_01> exampleC = example.getClass();
Constructor[] declaredConstructors = exampleC.getDeclaredConstructors();
for (int i = 0; i < declaredConstructors.length; i++) {
System.out.println("查看是否带有可变数量的参数:" + declaredConstructors[i].isVarArgs());
System.out.println("该构造函数的入口参数类型分别为:");
Class[] parameterTypes = declaredConstructors[i].getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
System.out.println(parameterTypes[j]);
}
System.out.println("该构造方法可能抛出的异常类型为:");
Class[] exceptionsC = declaredConstructors[i].getExceptionTypes();
for (int j = 0; j < exceptionsC.length; j++) {
System.out.println(exceptionsC[j]);
}
Example_01 example2 = null; //创建对象引用用于后续newInstance方法使用
while (example2 == null) {
try {
if (i == 2) {
example2 = (Example_01) declaredConstructors[i].newInstance();
}
if (i == 1) {
example2 = (Example_01) declaredConstructors[i].newInstance("7" , 5);
}
else {
Object[] parameters = new Object[] {new String[] {"12","23","45"}};
example2 = (Example_01) declaredConstructors[i].newInstance(parameters);
}
} catch (Exception e) {
System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法。");
declaredConstructors[i].setAccessible(true);
}
}
if (example2 != null) {
example2.print();
System.out.println();
}
}
}
}
运行结果为:
查看是否带有可变数量的参数:true
该构造函数的入口参数类型分别为:
class [Ljava.lang.String;
该构造方法可能抛出的异常类型为:
class java.lang.NumberFormatException
string = null
i = 12
i2 = 23
i3 = 45
查看是否带有可变数量的参数:false
该构造函数的入口参数类型分别为:
class java.lang.String
int
该构造方法可能抛出的异常类型为:
string = 7
i = 5
i2 = 0
i3 = 0
查看是否带有可变数量的参数:false
该构造函数的入口参数类型分别为:
该构造方法可能抛出的异常类型为:
在创建对象时抛出异常,下面执行setAccessible()方法。
在创建对象时抛出异常,下面执行setAccessible()方法。
string = null
i = 0
i2 = 0
i3 = 0
在使用方法访问类的成员变量时,将返回Field类型的对象或对象数组,每个Field对象代表着一个成员变量,使用Field对象可以对成员变量进行操作。
getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)
访问指定的成员变量时,可以通过该成员变量的名称来完成,如:objectClass.getDeclaredField("name");
Field类中提供了一些常用的方法:
方法 | 说明 |
---|---|
getName() | 获得该成员变量的名称 |
getType() | 获得表示该成员变量类型的Class对象 |
get(Object object) | 获得指定对象object中成员变量的值,返回值为Object |
set(Object object , Object value) | 将指定对象object中的成员变量值设置为value |
getInt(Object object) | 获取object对象中类型为int的变量的值 |
setInt(Object object , int i) | 将object对象中的int类型变量设置为i |
getFloat(Object object) | 获取object对象中类型为float的变量的值 |
setFloat(Object object , float f) | 将object对象中的float类型变量设置为f |
getBoolean(Object object) | 获取object对象中类型为boolean的变量的值 |
setFloat(Object object , boolean b) | 将object对象中的boolean类型变量设置为b |
setAccessible(boolean flag) | 此方法可以设置是否忽略权限限制直接访问private等私有成员变量 |
getModifiers() | 获得可以解析出该成员变量所采用修饰符的整数 |
下面使用实例来进行介绍:
package com.mw02;
public class Example_02 {
int i ;
public float f;
protected boolean b ;
private String s;
}
package com.mw02;
import java.lang.reflect.*;
public class Main {
public static void main(String[] args) {
Example_02 example = new Example_02();
Class exampleC = example.getClass();
Field[] fields = exampleC.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println("变量名称为:" + fields[i].getName());
Class fieldType = fields[i].getType();
System.out.println("变量类型为:" + fieldType);
boolean isTurn = true;
while (isTurn) {
try {
isTurn = false;
System.out.println("修改前的变量值为:" + fields[i].get(example));
if (fields[i].getType().equals(int.class)) {
System.out.println("使用setInt方法修改变量的值。");
fields[i].setInt(example, 168);
}else if (fields[i].getType().equals(float.class)) {
System.out.println("使用setFloat方法修改变量的值。");
fields[i].setFloat(example, 99.99F);
}else if (fields[i].getType().equals(boolean.class)) {
System.out.println("使用setBoolean方法修改变量的值。");
fields[i].setBoolean(example, true);
}else if (fields[i].getType().equals(String.class)) {
System.out.println("使用set方法改变变量的值。");
fields[i].set(example, "MWQ");
}
System.out.println("修改后的变量值为:" + fields[i].get(example));
} catch (Exception e) {
System.out.println("在设置成员变量值时出现异常,下面执行setAccessible()方法!");
fields[i].setAccessible(true);
isTurn = true;
}
}
System.out.println();
}
}
}
运行结果为:
变量名称为:i
变量类型为:int
修改前的变量值为:0
使用setInt方法修改变量的值。
修改后的变量值为:168
变量名称为:f
变量类型为:float
修改前的变量值为:0.0
使用setFloat方法修改变量的值。
修改后的变量值为:99.99
变量名称为:b
变量类型为:boolean
修改前的变量值为:false
使用setBoolean方法修改变量的值。
修改后的变量值为:true
变量名称为:s
变量类型为:class java.lang.String
在设置成员变量值时出现异常,下面执行setAccessible()方法!
修改前的变量值为:null
使用set方法改变变量的值。
修改后的变量值为:MWQ
通过一系列方法访问类中的成员方法时,将会返回Method对象或者数组。每个Method对象代表一个方法,利用Method对象可以操纵相应的方法。
getMethods()
getMethod(String name , Class> ...parameterTypes)
getDeclaredMethods()
getDeclaredMethod(String name , Class>...parameterTypes)
如果需要访问特定的方法,需要根据该方法的名称和入口参数的类型来访问。例如访问一个名称为print,参数类型依次为String和int的 方法,可以通过以下方式实现:
objectClass.getDeclaredMethod("print" , String.class , int.class);
或者objectClass.getDeclaredMethod("print" , new Class[]{String.class , int.class});
Method类提供的常用方法有:
方法 | 说明 |
---|---|
getName() | 获得该成员方法的名称 |
getParameterTypes() | 按照声明顺序返回该成员方法参数类型的Class数组 |
getReturnType() | 返回表示该成员方法返回值类型Class对象 |
getExceptionTypes() | 以Class数组的方式返回该成员函数抛出的异常类型 |
invoke(Object object , Object…args) | 使用指定参数执行指定对象中的该成员参数,返回值为Object类型 |
isVarArgs() | 查看该构造方法是否允许带有可变数量的参数,允许则返回true |
getModifiers() | 返回可以解析出该方法修饰符的整数 |
下面使用实例来进行介绍:
package com.mw03;
//创建基本类并构建不同修饰符修饰的成员方法
public class Example_03 {
static void staticMethod(){
System.out.println("执行staticMethod()方法。");
}
public int publicMethod(int i) {
System.out.println("执行publicMethod()方法。");
return i*100;
}
protected int protectedMethod(String string , int i)throws NumberFormatException {
System.out.println("执行protectedMethod()方法。");
return Integer.valueOf(string) + i;
}
private String privateMethod(String...strings) {
System.out.println("执行privateMethod()方法。");
StringBuffer sb = new StringBuffer();
for (int i = 0; i < strings.length; i++) {
sb.append(strings[i]);
}
return sb.toString();
}
}
package com.mw03;
import java.lang.reflect.*;
public class Main {
public static void main(String[] args) {
Example_03 example = new Example_03();
Class exampleClass = example.getClass();
Method[] methods = exampleClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println("名称为:" + methods[i].getName());
System.out.println("是否允许带有可变数量的参数:" + methods[i].isVarArgs());
System.out.println("入口参数类型依次为:");
Class[] parameterTypes = methods[i].getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
System.out.println(" " + parameterTypes[j]);
}
System.out.println("返回值类型为:" + methods[i].getReturnType());
System.out.println("可能抛出的异常类型有:");
Class[] exceptionTypes = methods[i].getExceptionTypes();
for (int j = 0; j < exceptionTypes.length; j++) {
System.out.println(exceptionTypes[j]);
}
boolean isTurn = true ;
while (isTurn) {
try {
isTurn = false;
if ("staticMethod".equals(methods[i].getName())) {
methods[i].invoke(example);
}else if ("protectedMethod".equals(methods[i].getName())) {
System.out.println("返回值为:" + methods[i].invoke(example, "88",5));
}else if ("publicMethod".equals(methods[i].getName())) {
System.out.println("返回值为:" +methods[i].invoke(example, 168));
}else if ("privateMethod".equals(methods[i].getName())) {
Object[] parameters = new Object[]{new String[]{"125","whud","45"}};
System.out.println("返回值为:" + methods[i].invoke(example, parameters));
}
} catch (Exception e) {
System.out.println("在执行方法时抛出异常,下面执行setAccessible方法:");
methods[i].setAccessible(true);
isTurn = true;
}
}
System.out.println();
}
}
}
运行结果为:
名称为:publicMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
int
返回值类型为:int
可能抛出的异常类型有:
执行publicMethod()方法。
返回值为:16800
名称为:staticMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
返回值类型为:void
可能抛出的异常类型有:
执行staticMethod()方法。
名称为:protectedMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
class java.lang.String
int
返回值类型为:int
可能抛出的异常类型有:
class java.lang.NumberFormatException
执行protectedMethod()方法。
返回值为:93
名称为:privateMethod
是否允许带有可变数量的参数:true
入口参数类型依次为:
class [Ljava.lang.String;
返回值类型为:class java.lang.String
可能抛出的异常类型有:
在执行方法时抛出异常,下面执行setAccessible方法:
执行privateMethod()方法。
返回值为:125whud45
通过反射机制我们可以使用实例得到Class对象,并通过Class类中的一系列方法访问该实例中的构造方法,成员变量,成员方法等。为我们验证,控制实例提供了很大的方便。