JAVA反射机制
转自:http://blog.csdn.net/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 | 目标类是否为成员类 |
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(被反射的类)
1 package com.stevenhu.field; 2 3 public class FieldBeReflected 4 { 5 private static String name; 6 private static String name1; 7 private boolean mBoolean = true; 8 private final byte mByte = 111; 9 private static final short mShort = 22; 10 protected static int mInt; 11 protected static long mLong; 12 protected static float mFloat; 13 protected static double mDouble; 14 public static char mChar; 15 16 }
2). ReflectField.java(执行反射调用的类)
1 package com.stevenhu.reflection.test; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Type; 6 7 import com.stevenhu.field.FieldBeReflected; 8 9 public class ReflectField 10 { 11 12 public static void main(String[] args) 13 { 14 /*1.Class<?> clazz = Class.forName("com.stevenhu.field.FieldBeReflected"); 15 *2.FieldBeReflected mFieldBeReflected = new FieldBeReflected(); 16 * Class<?> clazz = mFieldBeReflected.getClass(); 17 */ 18 Class<?> clazz = FieldBeReflected.class; 19 20 try { 21 Field fName = clazz.getDeclaredField("name"); 22 Field fBoolean = clazz.getDeclaredField("mBoolean"); 23 Field fByte = clazz.getDeclaredField("mByte"); 24 Field fShort = clazz.getDeclaredField("mShort"); 25 Field fInt = clazz.getDeclaredField("mInt"); 26 Field fLong = clazz.getDeclaredField("mLong"); 27 Field fFloat = clazz.getDeclaredField("mFloat"); 28 Field fDouble = clazz.getDeclaredField("mDouble"); 29 Field fChar = clazz.getDeclaredField("mChar"); 30 31 /* 32 * 参数为true,只要是在类中声明的目标属性均可访问, 33 * 为false,则被反射类和反射类在同一个包中时,private目标属性不可访问, 34 * 不在同一个包中时,private、protected目标属性均不可访问 35 */ 36 fName.setAccessible(true); 37 38 /*给目标属性设置值(private属性不能访问,但可以通过先调用setAccessible(true)实现访问), 39 * 由于ReflectField类中的name属性是静态的(static),所以方法的第一个实参传入的是 40 * 目标属性所在类对应的Class对象clazz,也可以是类的实例clazz.newInstance(); 41 */ 42 fName.set(clazz, "reflection"); 43 //得到目标属性的值(private属性不能访问,但可以通过调用setAccessible(true)实现访问) 44 String name = (String) fName.get(clazz); 45 System.out.println(name); 46 47 fBoolean.setAccessible(true); 48 /*得到目标属性的布尔值,由于ReflectField类中的mBoolean属性是非静态的, 49 * 所以此处的传入实参为目标属性所在类的实例clazz.newInstance() 50 */ 51 boolean mBoolean = fBoolean.getBoolean(clazz.newInstance()); 52 System.out.println(mBoolean); 53 54 fByte.setAccessible(true); 55 //得到目标属性的Byte类型值 56 byte mByte = fByte.getByte(clazz.newInstance()); 57 System.out.println(mByte); 58 59 fShort.setAccessible(true); 60 //得到目标属性的short整型值 61 short mShort = fShort.getShort(clazz); 62 System.out.println(mShort); 63 64 fInt.setAccessible(true); 65 //给目标属性设置整型值 66 fInt.setInt(clazz, 222); 67 //得到目标属性的整型值 68 int mInt = fInt.getInt(clazz); 69 System.out.println(mInt); 70 71 fLong.setAccessible(true); 72 //给目标属性设置Long整型值 73 fLong.setLong(clazz, 2222); 74 //得到目标属性的Long整型值 75 Long mLong = fLong.getLong(clazz); 76 System.out.println(mLong); 77 78 fFloat.setAccessible(true); 79 //给目标属性设置float类型值 80 fFloat.setFloat(clazz, 22222); 81 //得到目标属性的float类型值 82 float mFloat = fFloat.getFloat(clazz); 83 System.out.println(mFloat); 84 85 fDouble.setAccessible(true); 86 //给目标属性设置double类型值 87 fDouble.setDouble(clazz, 222.222); 88 //得到目标属性的double类型值 89 double mDouble = fDouble.getDouble(clazz); 90 System.out.println(mDouble); 91 92 //给目标属性设置字符值(private、protected属性不能访问) 93 fChar.setChar(clazz, \'a\'); 94 //得到目标属性的字符值(private、protected属性不能访问) 95 char mChar = fChar.getChar(clazz); 96 System.out.println(mChar); 97 98 //目标属性的名字,不局限于修饰符,只要是类中声明的属性 99 String name1 = fName.getName(); 100 System.out.println(name1); 101 //目标属性的类型,不局限于修饰符 102 Type type = fName.getGenericType(); 103 System.out.println(type); 104 //目标属性的类型对应的Class对象 105 Class<?> clazz1 = fName.getType(); 106 System.out.println(clazz1); 107 //目标属性所在类对应的Class对象 108 Class<?> clazz2 = fName.getDeclaringClass(); 109 System.out.println(clazz2); 110 //目标属性的权限修饰值(private为2、protected为4、public为1) 111 int modifier = fName.getModifiers(); 112 int modifier1 = fByte.getModifiers(); 113 int modifier2 = fShort.getModifiers(); 114 System.out.println(modifier); 115 System.out.println(modifier1); 116 System.out.println(modifier2); 117 118 System.out.println(fName.isAccessible()); 119 System.out.println(fChar.isAccessible()); 120 121 } catch (NoSuchFieldException e) { 122 // TODO Auto-generated catch block 123 e.printStackTrace(); 124 } catch (SecurityException e) { 125 // TODO Auto-generated catch block 126 e.printStackTrace(); 127 } catch (IllegalArgumentException e) { 128 // TODO Auto-generated catch block 129 e.printStackTrace(); 130 } catch (IllegalAccessException e) { 131 // TODO Auto-generated catch block 132 e.printStackTrace(); 133 } catch (InstantiationException e) { 134 // TODO Auto-generated catch block 135 e.printStackTrace(); 136 } 137 } 138 139 }
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(被反射的类)
1 package com.stevenhu.method; 2 3 public class MethodBeReflected 4 { 5 6 private static String mName; 7 private static int mAge; 8 private static float mWeight; 9 10 private String getmName() 11 { 12 return mName; 13 } 14 15 protected void setmName(String mName) 16 { 17 this.mName = mName; 18 } 19 20 protected static int getmAge() 21 { 22 return mAge; 23 } 24 25 private static void setmAge(int age) 26 { 27 mAge = age; 28 } 29 30 private float getmWeight() throws Exception, NoSuchMethodException, SecurityException 31 { 32 return mWeight; 33 } 34 35 protected void setmWeight(float mWeight) 36 { 37 this.mWeight = mWeight; 38 } 39 40 private void setAllValues(String name, int age, float weight) 41 { 42 this.mName = name; 43 this.mAge = age; 44 this.mWeight = weight; 45 } 46 }
2)ReflectMethod.java(执行反射的类)
1 package com.stevenhu.reflection.test; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Type; 6 7 import com.stevenhu.method.MethodBeReflected; 8 9 public class ReflectMethod 10 { 11 12 /** 13 * @param args 14 */ 15 public static void main(String[] args) 16 { 17 // TODO Auto-generated method stub 18 19 Class<?> clazz = MethodBeReflected.class; 20 21 try 22 { 23 //第一个实参为方法名,第二个实参为方法参数类型对应的class对象 24 Method nameMethod = clazz.getDeclaredMethod("setmName", String.class); 25 Method ageMethod = clazz.getDeclaredMethod("setmAge", int.class); 26 Method weightMethod = clazz.getDeclaredMethod("setmWeight", float.class); 27 Method allValuesMethod = clazz.getDeclaredMethod("setAllValues", new Class[]{String.class, int.class, float.class}); 28 29 nameMethod.setAccessible(true); 30 //调用setmName方法,给ReflectMethod类中的属性mName赋值为"stevenhu" 31 nameMethod.invoke(clazz.newInstance(), "lisa"); 32 nameMethod = clazz.getDeclaredMethod("getmName", null); 33 nameMethod.setAccessible(true); 34 //调用getmName方法,得到mName的值 35 String name1 = (String) nameMethod.invoke(clazz.newInstance(), null); 36 System.out.println(name1); 37 38 ageMethod.setAccessible(true); 39 /*调用setmAge方法设置年龄,由于该方法是静态方法,所以第一个实参可为类的Class对象clazz, 40 * 也可以是类的对象clazz.newInstance(); 41 */ 42 ageMethod.invoke(clazz, 21); 43 ageMethod = clazz.getDeclaredMethod("getmAge", null); 44 ageMethod.setAccessible(true); 45 //调用getmAge方法,得到之前设置的年龄 46 int age1 = (Integer) ageMethod.invoke(clazz, null); 47 System.out.println(age1); 48 49 weightMethod.setAccessible(true); 50 //调用setmWeight方法,设置体重 51 weightMethod.invoke(clazz.newInstance(), new Float(50.5)); 52 weightMethod = clazz.getDeclaredMethod("getmWeight",null); 53 weightMethod.setAccessible(true); 54 //调用getmWeight方法,得到之前设置的体龄 55 float weight1 = (Float) weightMethod.invoke(clazz.newInstance(), null); 56 System.out.println(weight1); 57 58 allValuesMethod.setAccessible(true); 59 /*调用ReflectMethod的setAllValues方法赋值 60 * 注:此处不能直接传入实参63.5;浮点型必须创建Float对象 61 * 整型和字符串可创建Integer、String对象,也可以不创建 62 */ 63 //allValuesMethod.invoke(clazz.newInstance(), new String("stevenhu"), new Integer(23), new Float(63.5)); 64 allValuesMethod.invoke(clazz.newInstance(), "stevenhu", 23, new Float(63.5)); 65 66 nameMethod = clazz.getDeclaredMethod("getmName", null); 67 nameMethod.setAccessible(true); 68 String name2 = (String) nameMethod.invoke(clazz.newInstance(), null); 69 System.out.println(name2); 70 71 ageMethod = clazz.getDeclaredMethod("getmAge", null); 72 ageMethod.setAccessible(true); 73 int age2 = (Integer) ageMethod.invoke(clazz.newInstance(), null); 74 System.out.println(age2); 75 76 weightMethod = clazz.getDeclaredMethod("getmWeight", null); 77 weightMethod.setAccessible(true); 78 float weight2 = (Float) weightMethod.invoke(clazz.newInstance(), null); 79 System.out.println(weight2); 80 81 //得到目标方法所在类对应的Class对象 82 Class<?> clazz1 = weightMethod.getDeclaringClass(); 83 84 //得到目标方法抛出的异常类型对应的Class对象 85 Class<?>[] clazzs1 = weightMethod.getExceptionTypes(); 86 for (Class cl : clazzs1) 87 { 88 System.out.println(cl); 89 } 90 //得到目标方法抛出的异常类型对应的Type对象 91 Type[] types1 = weightMethod.getGenericExceptionTypes(); 92 //得到目标方法返回类型对应的Class对象 93 Class<?> clazz2 = nameMethod.getReturnType(); 94 //得到目标方法返回类型对应的Type对象 95 Type type = nameMethod.getGenericReturnType(); 96 //得到目标方法各参数类型对应的Class对象 97 Class<?>[] clazzs2 = allValuesMethod.getParameterTypes(); 98 //得到目标方法各参数类型对应的Type对象 99 Type[] types2 = allValuesMethod.getGenericParameterTypes(); 100 //得到目标方法修饰符的值 101 int modifier = ageMethod.getModifiers(); 102 System.out.println(modifier); 103 //得到目标方法的名字 104 String methodName = nameMethod.getName(); 105 System.out.println(nameMethod.isVarArgs()); 106 107 } catch (NoSuchMethodException e) 108 { 109 // TODO Auto-generated catch block 110 e.printStackTrace(); 111 } catch (SecurityException e) 112 { 113 // TODO Auto-generated catch block 114 e.printStackTrace(); 115 } catch (IllegalAccessException e) { 116 // TODO Auto-generated catch block 117 e.printStackTrace(); 118 } catch (IllegalArgumentException e) { 119 // TODO Auto-generated catch block 120 e.printStackTrace(); 121 } catch (InvocationTargetException e) { 122 // TODO Auto-generated catch block 123 e.printStackTrace(); 124 } catch (InstantiationException e) { 125 // TODO Auto-generated catch block 126 e.printStackTrace(); 127 } 128 } 129 130 }
有关反射知识点的介绍到此结束,实例代码下载链接地址如下: