JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制。
Java Reflection
Reflection(反射)是被視為動態語言的關鍵,反射機制允許程序在執行期借助於Reflection API取得任何類的內部信息,並能直接操作任意對象的內部屬性及方法
Java反射機制提供的功能
在運行時判斷任意一個對象所屬的類
在運行時構造任意一個類的對象
在運行時判斷任意一個類所具有的成員變量和方法
在運行時調用任意一個對象的成員變量和方法
生成動態代理
反射相關的主要API:
java.lang.Class:代表一個類
java.lang.reflect.Method:代表類的方法
java.lang.reflect.Field:代表類的成員變量
java.lang.reflect.Constructor:代表類的構造方法
。。。。。。
1 import java.lang.reflect.Field; 2 import java.lang.reflect.InvocationTargetException; 3 import java.lang.reflect.Method; 4 import java.lang.reflect.Modifier; 5 import java.lang.reflect.ParameterizedType; 6 import java.lang.reflect.Type; 7
8 import org.apache.commons.lang3.StringUtils; 9 import org.apache.commons.lang3.Validate; 10 import org.slf4j.Logger; 11 import org.slf4j.LoggerFactory; 12 import org.springframework.util.Assert; 13
14 /**
15 * 反射工具類. 16 * 提供調用getter/setter方法, 訪問私有變量, 調用私有方法, 獲取泛型類型Class, 被AOP過的真實類等工具函數. 17 */
18 //壓制警告,即去除警告
19 @SuppressWarnings("rawtypes") 20 public class Reflections { 21
22 private static final String SETTER_PREFIX = "set"; 23
24 private static final String GETTER_PREFIX = "get"; 25
26 private static final String CGLIB_CLASS_SEPARATOR = "$$"; 27
28 private static Logger logger = LoggerFactory.getLogger(Reflections.class); 29
30 /**
31 * 調用Getter方法. 32 * 支持多級,如:對象名.對象名.方法 33 */
34 public static Object invokeGetter(Object obj, String propertyName) { 35 Object object = obj; 36 for (String name : StringUtils.split(propertyName, ".")){ 37 String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); 38 object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); 39 } 40 return object; 41 } 42
43 /**
44 * 調用Setter方法, 僅匹配方法名。 45 * 支持多級,如:對象名.對象名.方法 46 */
47 public static void invokeSetter(Object obj, String propertyName, Object value) { 48 Object object = obj; 49 String[] names = StringUtils.split(propertyName, "."); 50 for (int i=0; i<names.length; i++){ 51 if(i<names.length-1){ 52 String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); 53 object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); 54 }else{ 55 String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); 56 invokeMethodByName(object, setterMethodName, new Object[] { value }); 57 } 58 } 59 } 60
61 /**
62 * 直接讀取對象屬性值, 無視private/protected修飾符, 不經過getter函數. 63 */
64 public static Object getFieldValue(final Object obj, final String fieldName) { 65 Field field = getAccessibleField(obj, fieldName); 66
67 if (field == null) { 68 throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); 69 } 70
71 Object result = null; 72 try { 73 result = field.get(obj); 74 } catch (IllegalAccessException e) { 75 logger.error("不可能拋出的異常{}", e.getMessage()); 76 } 77 return result; 78 } 79
80 /**
81 * 直接設置對象屬性值, 無視private/protected修飾符, 不經過setter函數. 82 */
83 public static void setFieldValue(final Object obj, final String fieldName, final Object value) { 84 Field field = getAccessibleField(obj, fieldName); 85
86 if (field == null) { 87 throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); 88 } 89
90 try { 91 field.set(obj, value); 92 } catch (IllegalAccessException e) { 93 logger.error("不可能拋出的異常:{}", e.getMessage()); 94 } 95 } 96
97 /**
98 * 直接調用對象方法, 無視private/protected修飾符. 99 * 用於一次性調用的情況,否則應使用getAccessibleMethod()函數獲得Method后反復調用. 100 * 同時匹配方法名+參數類型, 101 */
102 public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, 103 final Object[] args) { 104 Method method = getAccessibleMethod(obj, methodName, parameterTypes); 105 if (method == null) { 106 throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); 107 } 108
109 try { 110 return method.invoke(obj, args); 111 } catch (Exception e) { 112 throw convertReflectionExceptionToUnchecked(e); 113 } 114 } 115
116 /**
117 * 直接調用對象方法, 無視private/protected修飾符, 118 * 用於一次性調用的情況,否則應使用getAccessibleMethodByName()函數獲得Method后反復調用. 119 * 只匹配函數名,如果有多個同名函數調用第一個。 120 */
121 public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { 122 Method method = getAccessibleMethodByName(obj, methodName); 123 if (method == null) { 124 throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); 125 } 126
127 try { 128 return method.invoke(obj, args); 129 } catch (Exception e) { 130 throw convertReflectionExceptionToUnchecked(e); 131 } 132 } 133
134 /**
135 * 循環向上轉型, 獲取對象的DeclaredField, 並強制設置為可訪問. 136 * 137 * 如向上轉型到Object仍無法找到, 返回null. 138 */
139 public static Field getAccessibleField(final Object obj, final String fieldName) { 140 Validate.notNull(obj, "object can't be null"); 141 Validate.notBlank(fieldName, "fieldName can't be blank"); 142 for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { 143 try { 144 Field field = superClass.getDeclaredField(fieldName); 145 makeAccessible(field); 146 return field; 147 } catch (NoSuchFieldException e) {//NOSONAR 148 // Field不在當前類定義,繼續向上轉型
149 continue;// new add
150 } 151 } 152 return null; 153 } 154
155 /**
156 * 循環向上轉型, 獲取對象的DeclaredMethod,並強制設置為可訪問. 157 * 如向上轉型到Object仍無法找到, 返回null. 158 * 匹配函數名+參數類型。 159 * 160 * 用於方法需要被多次調用的情況. 先使用本函數先取得Method,然后調用Method.invoke(Object obj, Object... args) 161 */
162 public static Method getAccessibleMethod(final Object obj, final String methodName, 163 final Class<?>... parameterTypes) { 164 Validate.notNull(obj, "object can't be null"); 165 Validate.notBlank(methodName, "methodName can't be blank"); 166
167 for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { 168 try { 169 Method method = searchType.getDeclaredMethod(methodName, parameterTypes); 170 makeAccessible(method); 171 return method; 172 } catch (NoSuchMethodException e) { 173 // Method不在當前類定義,繼續向上轉型
174 continue;// new add
175 } 176 } 177 return null; 178 } 179
180 /**
181 * 循環向上轉型, 獲取對象的DeclaredMethod,並強制設置為可訪問. 182 * 如向上轉型到Object仍無法找到, 返回null. 183 * 只匹配函數名。 184 * 185 * 用於方法需要被多次調用的情況. 先使用本函數先取得Method,然后調用Method.invoke(Object obj, Object... args) 186 */
187 public static Method getAccessibleMethodByName(final Object obj, final String methodName) { 188 Validate.notNull(obj, "object can't be null"); 189 Validate.notBlank(methodName, "methodName can't be blank"); 190
191 for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { 192 Method[] methods = searchType.getDeclaredMethods(); 193 for (Method method : methods) { 194 if (method.getName().equals(methodName)) { 195 makeAccessible(method); 196 return method; 197 } 198 } 199 } 200 return null; 201 } 202
203 /**
204 * 改變private/protected的方法為public,盡量不調用實際改動的語句,避免JDK的SecurityManager抱怨。 205 */
206 public static void makeAccessible(Method method) { 207 if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) 208 && !method.isAccessible()) { 209 method.setAccessible(true); 210 } 211 } 212
213 /**
214 * 改變private/protected的成員變量為public,盡量不調用實際改動的語句,避免JDK的SecurityManager抱怨。 215 */
216 public static void makeAccessible(Field field) { 217 if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier 218 .isFinal(field.getModifiers())) && !field.isAccessible()) { 219 field.setAccessible(true); 220 } 221 } 222
223 /**
224 * 通過反射, 獲得Class定義中聲明的泛型參數的類型, 注意泛型必須定義在父類處 225 * 如無法找到, 返回Object.class. 226 * eg. 227 * public UserDao extends HibernateDao<User> 228 * 229 * @param clazz The class to introspect 230 * @return the first generic declaration, or Object.class if cannot be determined 231 */
232 @SuppressWarnings("unchecked") 233 public static <T> Class<T> getClassGenricType(final Class clazz) { 234 return getClassGenricType(clazz, 0); 235 } 236
237 /**
238 * 通過反射, 獲得Class定義中聲明的父類的泛型參數的類型. 239 * 如無法找到, 返回Object.class. 240 * 241 * 如public UserDao extends HibernateDao<User,Long> 242 * 243 * @param clazz clazz The class to introspect 244 * @param index the Index of the generic ddeclaration,start from 0. 245 * @return the index generic declaration, or Object.class if cannot be determined 246 */
247 public static Class getClassGenricType(final Class clazz, final int index) { 248
249 Type genType = clazz.getGenericSuperclass(); 250
251 if (!(genType instanceof ParameterizedType)) { 252 logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); 253 return Object.class; 254 } 255
256 Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); 257
258 if (index >= params.length || index < 0) { 259 logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
260 + params.length); 261 return Object.class; 262 } 263 if (!(params[index] instanceof Class)) { 264 logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); 265 return Object.class; 266 } 267
268 return (Class) params[index]; 269 } 270
271 public static Class<?> getUserClass(Object instance) { 272 Assert.notNull(instance, "Instance must not be null"); 273 Class clazz = instance.getClass(); 274 if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { 275 Class<?> superClass = clazz.getSuperclass(); 276 if (superClass != null && !Object.class.equals(superClass)) { 277 return superClass; 278 } 279 } 280 return clazz; 281
282 } 283
284 /**
285 * 將反射時的checked exception轉換為unchecked exception. 286 */
287 public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { 288 if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException 289 || e instanceof NoSuchMethodException) { 290 return new IllegalArgumentException(e); 291 } else if (e instanceof InvocationTargetException) { 292 return new RuntimeException(((InvocationTargetException) e).getTargetException()); 293 } else if (e instanceof RuntimeException) { 294 return (RuntimeException) e; 295 } 296 return new RuntimeException("Unexpected Checked Exception.", e); 297 } 298 }
轉載請注明出處!
http://www.cnblogs.com/libingbin/
感謝您的閱讀。如果文章對您有用,那么請輕輕點個贊,以資鼓勵。
