基本概念
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?
答案是肯定的。
这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。
JAVA反射机制是指:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
Java反射机制主要提供了以下功能:
1.在运行时判断任意一个对象所属的类。
2.在运行时构造任意一个类的对象。
3.在运行时判断任意一个类所具有的成员变量和方法。
4.在运行时调用任意一个对象的方法。
Reflection是Java被视为动态(或准动态)语言的一个关键性质。
这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息。
包括其modifiers(诸如public、static等)、 superclass(例如Object)、实现了的 interfaces (例如Serializable)、也包括其fields和methods的所有信息,并可于运行时改变fields内容或调用methods。
动态语言
动态语言的定义“程序运行时,允许改变程序结构或者变量类型,这种语言称为动态语言”。
从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是:反射、映像、倒影,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
这种“看透”class的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。
Java Reflection API简介
在JDK中,主要由以下类来实现Java反射机制,这些类(除了第一个)都位于java.lang.reflect包中
Class类:代表一个类,位于java.lang包下。
Field类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
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 | 目标类是否为成员类 |
cisAnonymousClass() |
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():getFields(),得到的是描述类中声明的所有属性(public、protected、private)对应的Field对象;
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.Method;
- import java.lang.reflect.Type;
- import com.stevenhu.field.FieldBeReflected;
- public class ReflectField
- {
- public static void main(String[] args)
- {
- /*1.Class<?> clazz = Class.forName("com.stevenhu.field.FieldBeReflected");
- *2.FieldBeReflected mFieldBeReflected = new FieldBeReflected();
- * Class<?> clazz = mFieldBeReflected.getClass();
- */
- 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");
- /*
- * 参数为true,只要是在类中声明的目标属性均可访问,
- * 为false,则被反射类和反射类在同一个包中时,private目标属性不可访问,
- * 不在同一个包中时,private、protected目标属性均不可访问
- */
- fName.setAccessible(true);
- /*给目标属性设置值(private属性不能访问,但可以通过先调用setAccessible(true)实现访问),
- * 由于ReflectField类中的name属性是静态的(static),所以方法的第一个实参传入的是
- * 目标属性所在类对应的Class对象clazz,也可以是类的实例clazz.newInstance();
- */
- fName.set(clazz, "reflection");
- //得到目标属性的值(private属性不能访问,但可以通过调用setAccessible(true)实现访问)
- String name = (String) fName.get(clazz);
- System.out.println(name);
- fBoolean.setAccessible(true);
- /*得到目标属性的布尔值,由于ReflectField类中的mBoolean属性是非静态的,
- * 所以此处的传入实参为目标属性所在类的实例clazz.newInstance()
- */
- boolean mBoolean = fBoolean.getBoolean(clazz.newInstance());
- System.out.println(mBoolean);
- fByte.setAccessible(true);
- //得到目标属性的Byte类型值
- byte mByte = fByte.getByte(clazz.newInstance());
- System.out.println(mByte);
- fShort.setAccessible(true);
- //得到目标属性的short整型值
- 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);
- //给目标属性设置Long整型值
- fLong.setLong(clazz, 2222);
- //得到目标属性的Long整型值
- Long mLong = fLong.getLong(clazz);
- System.out.println(mLong);
- fFloat.setAccessible(true);
- //给目标属性设置float类型值
- fFloat.setFloat(clazz, 22222);
- //得到目标属性的float类型值
- float mFloat = fFloat.getFloat(clazz);
- System.out.println(mFloat);
- fDouble.setAccessible(true);
- //给目标属性设置double类型值
- fDouble.setDouble(clazz, 222.222);
- //得到目标属性的double类型值
- double mDouble = fDouble.getDouble(clazz);
- System.out.println(mDouble);
- //给目标属性设置字符值(private、protected属性不能访问)
- fChar.setChar(clazz, 'a');
- //得到目标属性的字符值(private、protected属性不能访问)
- 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对象
- Class<?> clazz1 = fName.getType();
- System.out.println(clazz1);
- //目标属性所在类对应的Class对象
- Class<?> clazz2 = fName.getDeclaringClass();
- System.out.println(clazz2);
- //目标属性的权限修饰值(private为2、protected为4、public为1)
- 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 e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (SecurityException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
3. Method:
同Fiel一样,一个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():getMethods(),得到的是描述类中声明的所有方法(public、protected、private)对应的FMethod对象;
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", new Class[]{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(), new String("stevenhu"), new Integer(23), new Float(63.5));
- 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();
- }
- }
- }
转载:http://blog.csdn.net/stevenhu_223/article/details/9286121
转载:http://blog.csdn.net/ritterliu/article/details/7764849