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