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/
感谢您的阅读。如果文章对您有用,那么请轻轻点个赞,以资鼓励。