注:本文参考自:https://blog.youkuaiyun.com/stevenhu_223/article/details/9286121
我们知道,类和类的成员变量及方法都是要求有权限控制的(public、protected、private);而当类中的信息封装为私有时,外部对该类中私有的信息是没有访问权限的,也就是说当该类里的内容信息均受private权限控制时,外部想要获取和处理该类里的私有信息是几乎不可能的;但是,有时候这种需求是有的,而当我们非得需要去动用别的类里封装的私有信息时,java的反射机制就起到了非常关键的作用了;
java反射机制的实现主要由三个类来主导:它们分别是 Class、Field、Method;
1. Class
java在编译和运行时,会将需要被编译和运行的所有类加载进类加载器,每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到java虚拟机中的这个类,进而在运行时对这个被访问的类进行信息的获取和处理(当然,不管被访问的这个类里的信息是否私有的);通俗的讲,Class对象间接代表了它对应的类,通过这个Class对象,我们就可以大刀阔斧地去执行反射机制的实现;
获取Class对象主要有三种方式:
-
1) 调用
Class
类的forName(String name)
静态方法,参数name为Class对应的类的全名(包括包名);比如我们要创建
Gesture
这个类对应的Class
对象:Class<Gesture> mClass = Class.forName("android.gesture.Gesture");
android.gesture
为Gesture
的包名,Class<Gesture>
中的Gesture
表示得到的是Gesture
类型对应的Class
对象,<>
中的Gesture
也可为通配符?
表示,如:Class<?>mClass = Class.forName("android.gesture.Gesture");
-
2)调用类的
class
属性得到类对应的Class
对象。如:Class<?>mClass = Gesture.class;
(一般建议用这种方式得到Class
对象) -
3)调用类的实例化对象的
getClass()
方法。特别说明的是,getClass()
是java类的始祖Object
类的方法,所以,所有java对象都可以调用该方法;如mGesture
是Gesture
类型的对象,Class<?> mClass = mGesture.getClass()
得到的是Gesture
类对应的Class
对象
那么在得到对应类的Class对象对应后,我们就可以通过该Class对象得到它所对应的类的一些信息,比如该类的构造函数、成员(属性)、方法(函数);
Class类提供的相关接口介绍:(注:在表中,Class对象对应的类,姑且称为目标类)
方法名 | 返回类型 | 接口功能实现 |
---|---|---|
getPackage() | Package | 得到目标类的包名对应的 Package 对象 |
getCanonicalName() | String | 得到目标类的全名(包名+类名) |
getName() | String | 同 getCanonicalName() |
getClassLoader() | ClassLoader | 得到加载目标类的 ClassLoader 对象 |
getClasses() | Class<?>[] | 得到目标类中的所有的 public 内部类以及 public 内部接口所对应的 Class 对象 |
getDeclaredClasses() | Class<?>[] | 同 getClasses(),但不局限于 public 修饰,只要是目标类中声明的内部类和接口均可 |
getConstructors() | Constructor<?>[] | 得到目标类的所有 public 构造函数对应的 Constructor 对象 |
getDeclaredConstructors() | Constructor<?>[] | 同 getConstructors(),但不局限于 public 修饰,只要是目标类中声明的构造函数均可 |
getField(String arg) | Field | 得到目标类中指定的某个 public 属性对应的 Field 对象 |
getDeclaredField(String arg) | Field | 同 getField,但不局限于 public 修饰,只要是目标类中声明的属性均可 |
getFields() | Field[] | 得到目标类(包括父类)中所有的 public 属性对应的 Field 对象 |
getDeclaredFields() | Field[] | 同 getFields(),但不局限于 public 修饰的属性,只能获取自身类中的(不包括父类) |
getMethod(String arg0, Class<?>… arg1) | Method | 得到目标类(包括父类)中指定的某个 public 方法对应的 Method 对象 |
getDeclaredMethod(String arg0, Class<?>… arg1) | Method | 同 getMethod,但不局限于 public 修饰的方法,只能获取自身类中的(不包括父类) |
getMethods() | Method[] | 得到目标类(包括父类)中所有的 public 方法对应的 Method 对象 |
getDeclaredMethods() | Method[] | 同 getMethods(),但不局限于 public 修饰的方法,只能获取自身类中的(不包括父类) |
getEnclosingClass() | Class | 得到目标类所在的外围类的 Class 对象 |
getGenericInterfaces() | Type[] | 得到目标类实现的接口对应的 Type 对象 |
getGenericSuperclass() | Type | 得到目标类继承的父类所对应的 Type 对象 |
getInterfaces() | Class<?>[] | 得到目标类实现的接口所对应的 Class 对象 |
getSuperclass() | Class | 得到目标类继承的父类所对应的 Class 对象 |
isMemberClass() | boolean | 目标类是否为成员类 |
isAnonymousClass() | boolean | 目标类是否为匿名类 |
2. Field
我们知道一般类里包含有属性(成员)和方法(函数),竟然Class是描述类的信息,那么类其它部分应该会对应有描述它们的东东,而Field类型的对象就是描述Class对象对应类的属性(包括public、protected、private
属性);一个Field
对象对应描述一个类的属性;
通过上文对Class的介绍,我们知道Class提供了四种接口函数可以得到对应属性的Field:
- 1)
getField(String name)
:返回类型为Field
,name
为类中的属性名,得到的是描述类中的一个public
属性对应的Field
对象;如Field mField =mClass.getField("mGestureID")
得到的是Gesture
类中的一个public
属性mGestureID
对应的Field
对象; - 2)
getFields()
:返回类型为Field
类型数组,得到的是描述类中的所有public
属性对应的所有Field
对象; - 3)
getDeclaredField(String name)
:同getField(String name)
,只不过得到的Field
对象描述的不只是public
属性,还包括protected、private
属性,也是说只要是在类中声明的属性; - 4)
getDeclaredFields()
:得到的是描述类中声明的所有属性(public、protected、private
)对应的Field
对象;
Field类提供的相关接口介绍:(注:在表中,Field对象对应的属性,姑且称为目标属性)
方法名 | 返回类型 | 接口功能实现 |
---|---|---|
setAccessible(boolean flag) | void | 参数为 true,只要是在类中声明的目标属性均可访问,为 false,只有 public 目标属性可访问 |
set(Object object, Object value) | void | 给目标属性设置值(private、protected 属性均不能访问,但可以通过先调用 setAccessible(true) 实现访问),第一个参数为目标属性所在类的对象,第二个参数为传入的值 |
get(Object object) | Object | 得到目标属性的值(private、protected 属性均不能访问,但可以通过调用 setAccessible(true) 实现访问),参数为目标属性所在类的对象 |
setBoolean(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 boolean |
getBoolean(Object object) | boolean | 同 get(Object object),只不过得到的数据类型为 boolean |
setByte(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 byte |
getByte(Object object) | byte | 同 get(Object object),只不过得到的数据类型为 byte |
setShort(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 short |
getShort(Object object) | short | 同 get(Object object),只不过得到的数据类型为 short |
setInt(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 int |
getInt(Object object) | int | 同 get(Object object),只不过得到的数据类型为 int |
setLong(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 long |
getLong(Object object) | long | 同 get(Object object),只不过得到的数据类型为 long |
setFloat(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 float |
getFloat(Object object) | float | 同 get(Object object),只不过得到的数据类型为 float |
setDouble(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 double |
getDouble(Object object) | double | 同 get(Object object),只不过得到的数据类型为 double |
setChar(Object object, boolean value) | void | 同 set(Object object, Object value),只不过操作的数据类型为 char |
getChar(Object object) | char | 同 get(Object object),只不过得到的数据类型为 char |
getName() | String | 得到目标属性的名字,不局限于 private 修饰符,只要是类中声明的属性 |
getGenericType() | Type | 得到目标属性的类型,不局限于 private 修饰符 |
getType() | Class<?> | 得到目标属性的类型对应的 Class 对象 |
getModifiers() | int | 得到目标属性的修饰符值(private 为 2、protected 为 4、public 为 1、static 为 8、final 为 16) |
getDeclaringClass() | Class<?> | 得到目标属性所在类对应的 Class 对象 |
下面就以一个示例代码来验证Field表中的函数接口的实现,如下:
1) FieldBeReflected.java
(被反射的类)
package com.stevenhu.field;
public class FieldBeReflected {
private static String name;
private static String name1;
private boolean mBoolean = true;
private final byte mByte = 111;
private static final short mShort = 22;
protected static int mInt;
protected static long mLong;
protected static float mFloat;
protected static double mDouble;
public static char mChar;
}
2)ReflectField.java
(执行反射调用的类)
package com.stevenhu.reflection.test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import com.stevenhu.field.FieldBeReflected;
public class ReflectField {
public static void main(String[] args) {
Class<?> clazz = FieldBeReflected.class;
try {
// 获取类的字段
Field fName = clazz.getDeclaredField("name");
Field fBoolean = clazz.getDeclaredField("mBoolean");
Field fByte = clazz.getDeclaredField("mByte");
Field fShort = clazz.getDeclaredField("mShort");
Field fInt = clazz.getDeclaredField("mInt");
Field fLong = clazz.getDeclaredField("mLong");
Field fFloat = clazz.getDeclaredField("mFloat");
Field fDouble = clazz.getDeclaredField("mDouble");
Field fChar = clazz.getDeclaredField("mChar");
// 设置私有字段可访问
fName.setAccessible(true);
// 设置和获取字段的值
fName.set(clazz, "reflection");
String name = (String) fName.get(clazz);
System.out.println(name);
fBoolean.setAccessible(true);
boolean mBoolean = fBoolean.getBoolean(clazz.newInstance());
System.out.println(mBoolean);
fByte.setAccessible(true);
byte mByte = fByte.getByte(clazz.newInstance());
System.out.println(mByte);
fShort.setAccessible(true);
short mShort = fShort.getShort(clazz);
System.out.println(mShort);
fInt.setAccessible(true);
fInt.setInt(clazz, 222);
int mInt = fInt.getInt(clazz);
System.out.println(mInt);
fLong.setAccessible(true);
fLong.setLong(clazz, 2222);
Long mLong = fLong.getLong(clazz);
System.out.println(mLong);
fFloat.setAccessible(true);
fFloat.setFloat(clazz, 22222);
float mFloat = fFloat.getFloat(clazz);
System.out.println(mFloat);
fDouble.setAccessible(true);
fDouble.setDouble(clazz, 222.222);
double mDouble = fDouble.getDouble(clazz);
System.out.println(mDouble);
fChar.setAccessible(true);
fChar.setChar(clazz, 'a');
char mChar = fChar.getChar(clazz);
System.out.println(mChar);
// 获取字段的其他信息
String name1 = fName.getName();
System.out.println(name1);
Type type = fName.getGenericType();
System.out.println(type);
Class<?> clazz1 = fName.getType();
System.out.println(clazz1);
Class<?> clazz2 = fName.getDeclaringClass();
System.out.println(clazz2);
int modifier = fName.getModifiers();
int modifier1 = fByte.getModifiers();
int modifier2 = fShort.getModifiers();
System.out.println(modifier);
System.out.println(modifier1);
System.out.println(modifier2);
System.out.println(fName.isAccessible());
System.out.println(fChar.isAccessible());
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException |
IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
3. Method
同Field一样,一个Method对象对应描述一个类的方法;
Class对象也提供了四种接口函数得到对应方法的Method对象,如下:
- 1)
getMethod(String name, Class<?>... parameterTypes)
:返回类型为Method
,第一个参数name
为类中的方法名,第二个参数为可变参数,传入的是参数类型对应的Class
对象(方法的参数可能为多个的情况);该函数得到的是描述类中的一个public
方法对应的Method
对象; - 2)
getMethods()
:返回类型为Method
类型数组,得到的是描述类中的所有public
方法对应的Method
对象; - 3)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
:同getMethod(String name, Class<?>... parameterTypes)
,只不过得到的Method
对象描述的不只是public
方法, 还包括
protected、private
方法,也是说只要是在类中声明的方法;
4)getDeclaredMethods()
:得到的是描述类中声明的所有方法(public、protected、private
)对应的Method
对象;
Method类提供的相关接口介绍:(注:在表中,Method对象对应的方法,姑且称为目标方法)
方法名 | 返回类型 | 接口功能实现 |
---|---|---|
setAccessible(boolean flag) | void | 参数为 true,只要是在类中声明的目标方法均可访问,为 false,只有 public 目标方法可访问 |
invoke(Object receiver, Object… args) | Object | 动态执行调用目标方法,第一个参数为 Class 对象或者类的实例,第二个参数为可变实参的对象(多个实参) |
getDeclaringClass() | Class<?> | 得到目标方法所在类对应的 Class 对象 |
getExceptionTypes() | Class<?> | 得到目标方法抛出的异常类型对应的 Class 对象 |
getGenericExceptionTypes() | Type[] | 得到目标方法抛出的异常类型对应的 Type 对象 |
getReturnType() | Class<?> | 得到目标方法返回类型对应的 Class 对象 |
getGenericReturnType() | Type | 得到目标方法返回类型对应的 Type 对象 |
getParameterTypes() | Class<?>[] | 得到目标方法各参数类型对应的 Class 对象 |
getGenericParameterTypes() | Type[] | 得到目标方法各参数类型对应的 Type 对象 |
getModifiers() | int | 得到目标方法修饰符的值 |
getName() | String | 得到目标方法的名字 |
下面就以一个示例代码来验证Method表中的函数接口的实现,如下:
1)MethodBeReflected.java
(被反射的类)
package com.stevenhu.method;
public class MethodBeReflected {
private static String mName;
private static int mAge;
private static float mWeight;
private String getmName() {
return mName;
}
protected void setmName(String mName) {
this.mName = mName;
}
protected static int getmAge() {
return mAge;
}
private static void setmAge(int age) {
mAge = age;
}
private float getmWeight() throws Exception, NoSuchMethodException, SecurityException {
return mWeight;
}
protected void setmWeight(float mWeight) {
this.mWeight = mWeight;
}
private void setAllValues(String name, int age, float weight) {
this.mName = name;
this.mAge = age;
this.mWeight = weight;
}
}
2)ReflectMethod.java
(执行反射的类)
package com.stevenhu.reflection.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import com.stevenhu.method.MethodBeReflected;
public class ReflectMethod {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Class<?> clazz = MethodBeReflected.class;
try {
// 第一个实参为方法名,第二个实参为方法参数类型对应的 class 对象
Method nameMethod = clazz.getDeclaredMethod("setmName", String.class);
Method ageMethod = clazz.getDeclaredMethod("setmAge", int.class);
Method weightMethod = clazz.getDeclaredMethod("setmWeight", float.class);
Method allValuesMethod = clazz.getDeclaredMethod("setAllValues", String.class, int.class, float.class);
nameMethod.setAccessible(true);
// 调用 setmName 方法,给 ReflectMethod 类中的属性 mName 赋值为 "stevenhu"
nameMethod.invoke(clazz.newInstance(), "lisa");
nameMethod = clazz.getDeclaredMethod("getmName", null);
nameMethod.setAccessible(true);
// 调用 getmName 方法,得到 mName 的值
String name1 = (String) nameMethod.invoke(clazz.newInstance(), null);
System.out.println(name1);
ageMethod.setAccessible(true);
/* 调用 setmAge 方法设置年龄,由于该方法是静态方法,所以第一个实参可为类的 Class 对象 clazz,
* 也可以是类的对象 clazz.newInstance();
*/
ageMethod.invoke(clazz, 21);
ageMethod = clazz.getDeclaredMethod("getmAge", null);
ageMethod.setAccessible(true);
// 调用 getmAge 方法,得到之前设置的年龄
int age1 = (Integer) ageMethod.invoke(clazz, null);
System.out.println(age1);
weightMethod.setAccessible(true);
// 调用 setmWeight 方法,设置体重
weightMethod.invoke(clazz.newInstance(), new Float(50.5));
weightMethod = clazz.getDeclaredMethod("getmWeight", null);
weightMethod.setAccessible(true);
// 调用 getmWeight 方法,得到之前设置的体龄
float weight1 = (Float) weightMethod.invoke(clazz.newInstance(), null);
System.out.println(weight1);
allValuesMethod.setAccessible(true);
/* 调用 ReflectMethod 的 setAllValues 方法赋值
* 注:此处不能直接传入实参 63.5;浮点型必须创建 Float 对象
* 整型和字符串可创建 Integer、String 对象,也可以不创建
*/
allValuesMethod.invoke(clazz.newInstance(), "stevenhu", 23, new Float(63.5));
nameMethod = clazz.getDeclaredMethod("getmName", null);
nameMethod.setAccessible(true);
String name2 = (String) nameMethod.invoke(clazz.newInstance(), null);
System.out.println(name2);
ageMethod = clazz.getDeclaredMethod("getmAge", null);
ageMethod.setAccessible(true);
int age2 = (Integer) ageMethod.invoke(clazz.newInstance(), null);
System.out.println(age2);
weightMethod = clazz.getDeclaredMethod("getmWeight", null);
weightMethod.setAccessible(true);
float weight2 = (Float) weightMethod.invoke(clazz.newInstance(), null);
System.out.println(weight2);
// 得到目标方法所在类对应的 Class 对象
Class<?> clazz1 = weightMethod.getDeclaringClass();
// 得到目标方法抛出的异常类型对应的 Class 对象
Class<?>[] clazzs1 = weightMethod.getExceptionTypes();
for (Class cl : clazzs1) {
System.out.println(cl);
}
// 得到目标方法抛出的异常类型对应的 Type 对象
Type[] types1 = weightMethod.getGenericExceptionTypes();
// 得到目标方法返回类型对应的 Class 对象
Class<?> clazz2 = nameMethod.getReturnType();
// 得到目标方法返回类型对应的 Type 对象
Type type = nameMethod.getGenericReturnType();
// 得到目标方法各参数类型对应的 Class 对象
Class<?>[] clazzs2 = allValuesMethod.getParameterTypes();
// 得到目标方法各参数类型对应的 Type 对象
Type[] types2 = allValuesMethod.getGenericParameterTypes();
// 得到目标方法修饰符的值
int modifier = ageMethod.getModifiers();
System.out.println(modifier);
// 得到目标方法的名字
String methodName = nameMethod.getName();
System.out.println(nameMethod.isVarArgs());
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
补充:
class.getInterfaces()
返回当前类直接实现的接口类数组,没有泛型参数,Class<?>[]
class.getGenericInterfaces()
返回当前类直接实现的接口类数组,包含泛型参数,Type[]
可参考: