反射相關的類,最基本的固然是Class類。html
獲取了Class對象以後,就能夠接着生成對象實例、調用方法、查看字段等等。java
字段(Field)、方法(Method)和構造方法(Constructor<T>)各有相應的類來表示,它們共同繼承於java.lang.reflect.AccessibleObject類:apache
這三個類共同實現的還有Member接口:api
獲取字段、方法和構造方法時,須要調用Class類的getXXX()和getDeclearedXXX()方法,須要注意兩者區別。數組
好比對於方法:oracle
getMethods();//獲取public (包括父類中的) getDeclaredMethods();//獲取本類聲明(包括各類修飾符public、private)
相關博文:Java中的反射機制(一)app
API 文檔:http://docs.oracle.com/javase/7/docs/api/ide
利用反射,能夠訪問一些SDK、API中的私有方法。工具
相關博文:Java中的反射機制(四) 利用反射訪問私有測試
訪問私有方法有一個關鍵點:
setAccessible(true); // 抑制Java對修飾符的檢查
這個方法是AccessibleObject類中的。
前面說過,它是Field、Method和Constructor<T>的共同基類。
正常狀況下,調用isAccessible()返回的都是false,不管你的方法是public仍是private。
這是由於這個accessible的flag是JVM用來限制是否能夠直接訪問,默認狀況下是須要進行訪問修飾符的檢查的,因此flag爲false,即不能直接訪問。
當這個flag設置爲true,代表能夠直接訪問,不通過訪問修飾符的檢查。
輔助類中用於調用私有方法的接口:
/** * 調用私有方法 * * @param obj * 調用類對象 * @param methodName * 方法名 * @param paramTypes * 參數類型 * @param params * 參數 * @return * @throws Exception */ public static Object invokePrivateMethod(Object obj, String methodName, Class<?>[] paramTypes, Object[] params) throws Exception { Object value = null; Class<?> cls = obj.getClass(); // 注意不要用getMethod(),由於getMethod()返回的都是public方法 Method method = cls.getDeclaredMethod(methodName, paramTypes); method.setAccessible(true);// 抑制Java的訪問控制檢查 value = method.invoke(obj, params); return value; }
對訪問修飾符的獲取能夠經過Member接口的getModifiers()方法,該方法返回一個整型值,整型值是一系列的修飾符位操做組合的結果。
用Modifier類能夠解析這個整型值中包含的修飾符信息。
/** * 獲取修飾符信息 * * @param member * @return */ private static String getModifiersInfo(Member member) { StringBuilder sBuilder = new StringBuilder(); int modifiers = member.getModifiers(); sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 獲得修飾符編碼 sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", "); sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", "); sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", "); sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", "); sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers)); return sBuilder.toString(); }
相關博文: Java 包裝類 自動裝箱和拆箱
寫了一個調用靜態方法的輔助類,我原本是這麼寫的:
/* * wrong: * public static Object invokePublicStaticMethod(String className, * String methodName, Object[] params) throws Exception { * * Class<?> cls = Class.forName(className); * Class<?>[] paramTypes = new Class<?>[params.length]; * for (int i = 0; i < params.length; ++i) { * paramTypes[i] = params[i].getClass(); * * } * Method method = cls.getMethod(methodName, paramTypes); * Object value = null; * if (isPublicStatic(method)) { * value = method.invoke(null, params); * } * * return value; * } */
意圖是隻傳入參數數組,在內部本身根據參數獲取類型數組,能夠少傳點參數,可是這樣遇到了問題。
在Example類裏寫了這麼三個測試方法:
public static void printSomething(String line) { System.out.println(line); } public static int add(int a, int b) { return a + b; } public static double getPi() { return 3.14159d; }
測試的時候發現參數是String類型的時候能夠正常執行,可是參數若是是原生數據類型(int類型),用這個方法調用時就跑出了異常:
java.lang.NoSuchMethodException: com.mengdd.reflect.Example.add(java.lang.Integer, java.lang.Integer)
測試了一下:
Object[] array = new Object[] { 1, 2 }; System.out.println("getClass(): " + array[0].getClass()); System.out.println("Integer.TYPE: " + Integer.TYPE);
輸出:
getClass(): class java.lang.Integer Integer.TYPE: int
而那個用於測試的add()方法:
getReturnType: int getParameterTypes: [int, int]
可見Integer和int被認爲是兩種類型,因此調用方法的時候,類型參數也仍是從外部傳入比較科學。
修改後的調用方法以下:
public static Object invokePublicStaticMethod(String className, String methodName, Class<?>[] paramTypes, Object[] params) throws Exception { Class<?> cls = Class.forName(className); Method method = cls.getMethod(methodName, paramTypes); Object value = null; if (isPublicStatic(method)) { value = method.invoke(null, params); } return value; }
測試代碼:
Object result1 = ReflectUtils.invokePublicStaticMethod( "com.mengdd.reflect.Example", "add", new Class<?>[] { int.class, Integer.TYPE }, new Object[] { 1, 2 }); // int.class和Integer.TYPE都行 Assert.assertEquals(3, result1);
ReflectUtils類完整代碼以下:
package com.mengdd.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; /** * * @ClassName ReflectUtils * @Description Reflection Helper class * * @author mengdandan * @Date 2014年5月13日上午10:40:32 * */ public class ReflectUtils { /** * 建立類的實例,調用類的無參構造方法 * * @param className * @return */ public static Object newInstance(String className) { Object instance = null; try { Class<?> clazz = Class.forName(className); instance = clazz.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { // if this Class represents an abstract class, an interface, an // array class, a primitive type, or void; or if the class has no // nullary constructor; or if the instantiation fails for some other // reason. e.printStackTrace(); } catch (IllegalAccessException e) { // if the class or its nullary constructor is not accessible e.printStackTrace(); } return instance; } /** * 獲取全部的public構造方法的信息 * * @param className * @return */ public static String getPublicConstructorInfo(String className) { StringBuilder sBuilder = new StringBuilder(); try { Class<?> clazz = Class.forName(className); Constructor<?>[] constructors = clazz.getConstructors(); sBuilder.append(getConstructorInfo(constructors)); } catch (ClassNotFoundException e) { e.printStackTrace(); } return sBuilder.toString(); } /** * 獲得本類內聲明的構造方法信息 * * @param className * @return */ public static String getDeclearedConstructorInfo(String className) { StringBuilder sBuilder = new StringBuilder(); try { Class<?> clazz = Class.forName(className); Constructor<?>[] constructors = clazz.getDeclaredConstructors(); sBuilder.append(getConstructorInfo(constructors)); } catch (ClassNotFoundException e) { e.printStackTrace(); } return sBuilder.toString(); } /** * 獲取public的字段信息 * * @param className * @return */ public static String getPublicFieldInfo(String className) { StringBuilder sBuilder = new StringBuilder(); try { Class<?> clazz = Class.forName(className); Field[] fields = clazz.getFields(); sBuilder.append(getFieldInfo(fields)); } catch (ClassNotFoundException e) { e.printStackTrace(); } return sBuilder.toString(); } /** * 獲取本類內聲明的字段信息 * * @param className * @return */ public static String getDecleardFieldInfo(String className) { StringBuilder sBuilder = new StringBuilder(); try { Class<?> clazz = Class.forName(className); Field[] fields = clazz.getDeclaredFields(); sBuilder.append(getFieldInfo(fields)); } catch (ClassNotFoundException e) { e.printStackTrace(); } return sBuilder.toString(); } /** * 獲得全部public方法信息 * * @param className * @return */ public static String getPublicMethodInfos(String className) { StringBuilder sBuilder = new StringBuilder(); try { Class<?> clazz = Class.forName(className); Method[] methods = clazz.getMethods();// 獲得全部的public方法,包括從基類繼承的 sBuilder.append(getMethodInfo(methods)); } catch (ClassNotFoundException e) { e.printStackTrace(); } return sBuilder.toString(); } /** * 獲得類內聲明的方法信息 * * @param className * @return */ public static String getDeclaredMethodInfos(String className) { StringBuilder sBuilder = new StringBuilder(); try { Class<?> clazz = Class.forName(className); Method[] methods = clazz.getDeclaredMethods();// 獲得本類聲明的全部方法,包括私有方法 // clazz.getMethods(); 會返回全部public的方法,可是包括基類Object的方法 sBuilder.append(getMethodInfo(methods)); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return sBuilder.toString(); } /** * 獲得構造器信息 * * @param constructor * @return */ private static String getConstructorInfo(Constructor<?> constructor) { StringBuilder sBuilder = new StringBuilder(); sBuilder.append("name: " + constructor.getName()); sBuilder.append("\ngetParameterTypes: " + Arrays.toString(constructor.getParameterTypes())); return sBuilder.toString(); } /** * 將一組構造器的信息組成一個字符串返回 * * @param constructors * @return */ private static String getConstructorInfo(Constructor<?>[] constructors) { StringBuilder sBuilder = new StringBuilder(); int i = 0; for (Constructor<?> c : constructors) { sBuilder.append("method: " + ++i + " : "); sBuilder.append("\n" + getConstructorInfo(c)); sBuilder.append("\n"); } return sBuilder.toString(); } /** * 獲取字段信息,組成一個字符串返回 * * @param field * @return */ private static String getFieldInfo(Field field) { StringBuilder sBuilder = new StringBuilder(); sBuilder.append("name: " + field.getName()); sBuilder.append("\ngetType: " + field.getType()); sBuilder.append(getModifiersInfo(field)); return sBuilder.toString(); } /** * 獲取一組字段的信息,返回字符串 * * @param fields * @return */ private static String getFieldInfo(Field[] fields) { StringBuilder sBuilder = new StringBuilder(); int i = 0; for (Field field : fields) { sBuilder.append("field: " + ++i + " : "); sBuilder.append("\n" + getFieldInfo(field)); sBuilder.append("\n"); } return sBuilder.toString(); } /** * 獲取方法的信息,組成一個字符串返回 * * @param method * @return */ private static String getMethodInfo(Method method) { StringBuilder sBuilder = new StringBuilder(); sBuilder.append("name: " + method.getName()); sBuilder.append("\ngetReturnType: " + method.getReturnType()); sBuilder.append("\ngetParameterTypes: " + Arrays.toString(method.getParameterTypes())); sBuilder.append(getModifiersInfo(method)); return sBuilder.toString(); } /** * 獲取一組方法的信息,組成一個字符串返回 * * @param methods * @return */ private static String getMethodInfo(Method[] methods) { StringBuilder sBuilder = new StringBuilder(); int i = 0; for (Method method : methods) { sBuilder.append("method: " + ++i + " : "); sBuilder.append("\n" + getMethodInfo(method)); sBuilder.append("\n"); } return sBuilder.toString(); } /** * 獲取修飾符信息 * * @param member * @return */ private static String getModifiersInfo(Member member) { StringBuilder sBuilder = new StringBuilder(); int modifiers = member.getModifiers(); sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 獲得修飾符編碼 sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", "); sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", "); sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", "); sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", "); sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers)); return sBuilder.toString(); } /** * 是不是公用靜態方法 * * @param member * @return */ private static boolean isPublicStatic(Member member) { boolean isPS = false; int mod = member.getModifiers(); isPS = Modifier.isPublic(mod) && Modifier.isStatic(mod); return isPS; } /** * 調用靜態方法 * * @param className * @param methodName * @param paramTypes * @param params * @return * @throws Exception */ public static Object invokePublicStaticMethod(String className, String methodName, Class<?>[] paramTypes, Object[] params) throws Exception { Class<?> cls = Class.forName(className); Method method = cls.getMethod(methodName, paramTypes); Object value = null; if (isPublicStatic(method)) { value = method.invoke(null, params); } return value; } /* * wrong: * public static Object invokePublicStaticMethod(String className, * String methodName, Object[] params) throws Exception { * * Class<?> cls = Class.forName(className); * Class<?>[] paramTypes = new Class<?>[params.length]; * for (int i = 0; i < params.length; ++i) { * paramTypes[i] = params[i].getClass(); * * } * Method method = cls.getMethod(methodName, paramTypes); * Object value = null; * if (isPublicStatic(method)) { * value = method.invoke(null, params); * } * * return value; * } */ /** * 調用私有方法 * * @param obj * 調用類對象 * @param methodName * 方法名 * @param paramTypes * 參數類型 * @param params * 參數 * @return * @throws Exception */ public static Object invokePrivateMethod(Object obj, String methodName, Class<?>[] paramTypes, Object[] params) throws Exception { Object value = null; Class<?> cls = obj.getClass(); // 注意不要用getMethod(),由於getMethod()返回的都是public方法 Method method = cls.getDeclaredMethod(methodName, paramTypes); method.setAccessible(true);// 抑制Java的訪問控制檢查 value = method.invoke(obj, params); return value; } }
測試類和測試代碼:
package com.mengdd.reflect; public class Example { private String mFiledOne = null; private int mCount = 0; private double mNum = 6; public int mPub = 4; public Example() { } public Example(String filedOne, int count, double num) { super(); this.mFiledOne = filedOne; this.mCount = count; this.mNum = num; } public String getFiledOne() { return mFiledOne; } public void setFiledOne(String filedOne) { this.mFiledOne = filedOne; } public int getCount() { return mCount; } public void setCount(int count) { this.mCount = count; } public double getNum() { return mNum; } public void setNum(double num) { this.mNum = num; } public static void printSomething(String line) { System.out.println(line); } public static int add(int a, int b) { return a + b; } public static double getPi() { return 3.14159d; } @Override public String toString() { return "Example [mFiledOne=" + mFiledOne + ", mCount=" + mCount + "]"; } private String tellSecret(String name, int num) { String result = name + num + toString(); return result; } }
package com.mengdd.reflect; import org.junit.Assert; import org.junit.Test; public class ReflectTest { @Test public void testNewInstance() { Object object = ReflectUtils.newInstance("com.mengdd.reflect.Example"); Assert.assertNotNull(object); } @Test public void testGetConstructorInfo() { String result = ReflectUtils .getPublicConstructorInfo("com.mengdd.reflect.Example"); System.out .println("=============testGetConstructorInfo================"); System.out.println(result); System.out .println("==================================================="); Assert.assertNotNull(result); } @Test public void testFieldInfos() { String result = ReflectUtils .getDecleardFieldInfo("com.mengdd.reflect.Example"); System.out.println("=============testFieldInfos================"); System.out.println(result); System.out .println("==================================================="); Assert.assertNotNull(result); } @Test public void testMethodInfos() { String result = ReflectUtils .getDeclaredMethodInfos("com.mengdd.reflect.Example"); System.out.println("=============testMethodInfos================"); System.out.println(result); System.out .println("==================================================="); Assert.assertNotNull(result); } @Test public void testPublicStaticInvocation() { System.out .println("=============test static invocation================"); try { // 靜態方法1 ReflectUtils.invokePublicStaticMethod("com.mengdd.reflect.Example", "printSomething", new Class<?>[] { String.class }, new Object[] { "Hello World" }); // 靜態方法2 Object result1 = ReflectUtils.invokePublicStaticMethod( "com.mengdd.reflect.Example", "add", new Class<?>[] { int.class, Integer.TYPE }, new Object[] { 1, 2 }); // int.class和Integer.TYPE都行 Assert.assertEquals(3, result1); // 靜態方法3 Object result2 = ReflectUtils.invokePublicStaticMethod( "com.mengdd.reflect.Example", "getPi", new Class<?>[] {}, new Object[] {}); Assert.assertEquals(3.14159, result2); } catch (Exception e) { e.printStackTrace(); System.out.println("Exception!"); } System.out .println("==================================================="); } @Test public void testPrivateInvocation() { Example example = new Example("1", 5, 0); Object secret = null; try { secret = ReflectUtils.invokePrivateMethod(example, "tellSecret", new Class<?>[] { String.class, Integer.TYPE }, new Object[] { "Hello", 2 }); } catch (Exception e) { e.printStackTrace(); } String expected = "Hello2Example [mFiledOne=1, mCount=5]"; Assert.assertEquals(expected, secret); } }
再補充一個反射工具類:
ReflectUtils
package com.hwhmd.core.report.jasper.bean; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; /** * 反射工具類 * <p>Title: ReflectUtils</p> * <p>Description: </p> * @author xiayuxuanmin * @date 2019年5月16日 */ public class ReflectUtils { /** * 經過字段名從對象或對象的父類中獲得字段的值 * @param object 對象實例 * @param fieldName 字段名 * @return 字段對應的值 * @throws Exception */ public static Object getValue(Object object, String fieldName) throws Exception { if (object == null) { return null; } if (StringUtils.isBlank(fieldName)) { return null; } Field field = null; Class<?> clazz = object.getClass(); for (; clazz != Object.class; clazz = clazz.getSuperclass()) { try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field.get(object); } catch (Exception e) { //這裏甚麼都不要作!而且這裏的異常必須這樣寫,不能拋出去。 //若是這裏的異常打印或者往外拋,則就不會執行clazz = clazz.getSuperclass(),最後就不會進入到父類中了 } } return null; } /** * 經過字段名從對象或對象的父類中獲得字段的值(調用字典的get方法) * @param object 對象實例 * @param fieldName 字段名 * @return 字段對應的值 * @throws Exception */ public static Object getValueOfGet(Object object, String fieldName) throws Exception { if (object == null) { return null; } if (StringUtils.isBlank(fieldName)) { return null; } Field field = null; Class<?> clazz = object.getClass(); for (; clazz != Object.class; clazz = clazz.getSuperclass()) { try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); //得到get方法 Method getMethod = pd.getReadMethod(); //執行get方法返回一個Object return getMethod.invoke(object); } catch (Exception e) { //這裏甚麼都不要作!而且這裏的異常必須這樣寫,不能拋出去。 //若是這裏的異常打印或者往外拋,則就不會執行clazz = clazz.getSuperclass(),最後就不會進入到父類中了 } } return null; } /** * 經過字段名從對象或對象的父類中獲得字段的值(調用字典的get方法,能夠取出複雜的對象的值) * @param object 對象實例 * @param fieldName 字段名 * @return 字段對應的值 * @throws Exception */ public static Object getValueOfGetIncludeObjectFeild(Object object, String fieldName) throws Exception { if (object == null) { return null; } if (StringUtils.isBlank(fieldName)) { return null; } if(HashMap.class.equals(object.getClass())){ return ((Map)object).get(fieldName); } Field field = null; Class<?> clazz = object.getClass(); for (; clazz != Object.class; clazz = clazz.getSuperclass()) { try { if (fieldName.contains(".")) { // 如:operatorUser.name、operatorUser.org.name,遞歸調用 String[] splitFiledName = fieldName.split("\\."); return getValueOfGetIncludeObjectFeild( getValueOfGetIncludeObjectFeild(object, splitFiledName[0]), splitFiledName[1]); } field = clazz.getDeclaredField(fieldName); field.setAccessible(true); PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); //得到get方法 Method getMethod = pd.getReadMethod(); //執行get方法返回一個Object return getMethod.invoke(object); } catch (Exception e) { //這裏甚麼都不要作!而且這裏的異常必須這樣寫,不能拋出去。 //若是這裏的異常打印或者往外拋,則就不會執行clazz = clazz.getSuperclass(),最後就不會進入到父類中了 } } return null; } /** * 根據屬性名獲取屬性值 * */ private Object getFieldValueByName(String fieldName, Object o) { try { String firstLetter = fieldName.substring(0, 1).toUpperCase(); String getter = "get" + firstLetter + fieldName.substring(1); Method method = o.getClass().getMethod(getter, new Class[] {}); Object value = method.invoke(o, new Object[] {}); return value; } catch (Exception e) { System.out.println(e.getStackTrace()); return null; } } /** * 獲取屬性名數組 * */ private String[] getFiledName(Object o){ Field[] fields=o.getClass().getDeclaredFields(); String[] fieldNames=new String[fields.length]; for(int i=0;i<fields.length;i++){ System.out.println(fields[i].getType()); fieldNames[i]=fields[i].getName(); } return fieldNames; } /** * 獲取屬性類型(type),屬性名(name),屬性值(value)的map組成的list */ private List getFiledsInfo(Object o){ Field[] fields=o.getClass().getDeclaredFields(); String[] fieldNames=new String[fields.length]; List list = new ArrayList(); Map infoMap=null; for(int i=0;i<fields.length;i++){ infoMap = new HashMap(); infoMap.put("type", fields[i].getType().toString()); infoMap.put("name", fields[i].getName()); infoMap.put("value", getFieldValueByName(fields[i].getName(), o)); list.add(infoMap); } return list; } /** * 獲取對象的全部屬性值,返回一個對象數組 */ public Object[] getFiledValues(Object o){ String[] fieldNames=this.getFiledName(o); Object[] value=new Object[fieldNames.length]; for(int i=0;i<fieldNames.length;i++){ value[i]=this.getFieldValueByName(fieldNames[i], o); } return value; } /** * 獲取對象的get方法 */ public static String convertToGetterMethodName(String fieldName) { StringBuilder getterName = new StringBuilder("get"); getterName.append(fieldName.substring(0, 1).toUpperCase()); getterName.append(fieldName.substring(1)); return getterName.toString(); } /** * 獲取對象的set方法 */ public static String convertToSetterMethodName(String fieldName) { StringBuilder setterName = new StringBuilder("set"); setterName.append(fieldName.substring(0, 1).toUpperCase()); setterName.append(fieldName.substring(1)); return setterName.toString(); } }