在Java中如何通过反射找到一个变量,这个变量的类型是指定的类型

来源:互联网 发布:简明python教程 编辑:程序博客网 时间:2024/05/20 04:28

1. 说明以下的代码是我从Spring中抓出来的,然后加了一些我认为对自己有用的方法。

2. 直接上代码,看不懂的请留言。

3. 如何解决标题中提到的问题呢?请查找findAllField方法。

ReflectionUtils.java

package test.util;/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.UndeclaredThrowableException;import java.sql.SQLException;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import org.eclipse.core.runtime.Assert;/** * Simple utility class for working with the reflection API and handling * reflection exceptions. * * <p>Only intended for internal use. * * @author Juergen Hoeller * @author Rob Harrop * @author Rod Johnson * @author Costin Leau * @author Sam Brannen * @author Chris Beams * @author Roy Clarkson * @author jialiang * @since 1.1 */public abstract class ReflectionUtils {/** * Attempt to find a {@link Field field} on the supplied {@link Class} with the * supplied <code>name</code>. Searches all superclasses up to {@link Object}. * @param clazz the class to introspect * @param name the name of the field * @return the corresponding Field object, or <code>null</code> if not found */public static Field findField(Class<?> clazz, String name) {return findField(clazz, name, null);}/** * Attempt to find a {@link Field field} on the supplied {@link Class} with the * supplied <code>name</code> and/or {@link Class type}. Searches all superclasses * up to {@link Object}. * @param clazz the class to introspect * @param name the name of the field (may be <code>null</code> if type is specified) * @param type the type of the field (may be <code>null</code> if name is specified) * @return the corresponding Field object, or <code>null</code> if not found */public static Field findField(Class<?> clazz, String name, Class<?> type) {Assert.isNotNull(clazz, "Class must not be null");Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified");Class<?> searchType = clazz;while (!Object.class.equals(searchType) && searchType != null) {Field[] fields = searchType.getDeclaredFields();for (Field field : fields) {if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) {return field;}}searchType = searchType.getSuperclass();}return null;}/** * Attempt to find a {@link Field field} on the supplied {@link Class} with the * supplied <code>name</code> and/or {@link Class type}. Searches all superclasses * up to {@link Object}. * @param clazz the class to introspect * @param name the name of the field (may be <code>null</code> if type is specified) * @param type the type of the field, must not be <code>null</code> * @return the corresponding Field object, or <code>null</code> if not found */public static List<Field> findAllField(Class<?> clazz, String name, Class<?> type) {Assert.isNotNull(clazz, "Class must not be null");Assert.isNotNull(type, "The type of filed must not be null");List<Field> list = new ArrayList<Field>();Class<?> searchType = clazz;while (!Object.class.equals(searchType) && searchType != null) {Field[] fields = searchType.getDeclaredFields();for (Field field : fields) {if ((name == null || name.equals(field.getName())) && type.equals(field.getType())) {list.add(field);}}searchType = searchType.getSuperclass();}return list;}public static List<Field> findAllField(Class<?> clazz, Class<?> type) {return findAllField(clazz, null, type);}/** * Set the field represented by the supplied {@link Field field object} on the * specified {@link Object target object} to the specified <code>value</code>. * In accordance with {@link Field#set(Object, Object)} semantics, the new value * is automatically unwrapped if the underlying field has a primitive type. * <p>Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. * @param field the field to set * @param target the target object on which to set the field * @param value the value to set; may be <code>null</code> */public static void setField(Field field, Object target, Object value) {try {field.set(target, value);}catch (IllegalAccessException ex) {handleReflectionException(ex);throw new IllegalStateException("Unexpected reflection exception - " + ex.getClass().getName() + ": "+ ex.getMessage());}}/** * Get the field represented by the supplied {@link Field field object} on the * specified {@link Object target object}. In accordance with {@link Field#get(Object)} * semantics, the returned value is automatically wrapped if the underlying field * has a primitive type. * <p>Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. * @param field the field to get * @param target the target object from which to get the field * @return the field's current value */public static Object getField(Field field, Object target) {try {field.setAccessible(true);return field.get(target);}catch (IllegalAccessException ex) {handleReflectionException(ex);throw new IllegalStateException("Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());}}public static Object getField(String fieldName, Object target) {Field field = findField(target.getClass(), fieldName);if(field == null) {return null;}try {field.setAccessible(true);return field.get(target);}catch (IllegalAccessException ex) {handleReflectionException(ex);throw new IllegalStateException("Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());}}/** * Attempt to find a {@link Method} on the supplied class with the supplied name * and no parameters. Searches all superclasses up to <code>Object</code>. * <p>Returns <code>null</code> if no {@link Method} can be found. * @param clazz the class to introspect * @param name the name of the method * @return the Method object, or <code>null</code> if none found */public static Method findMethod(Class<?> clazz, String name) {return findMethod(clazz, name, new Class[0]);}public static Object invokeMethod(Object target, String name) {Assert.isNotNull(target, "target must not be null");Assert.isNotNull(name, "Method name must not be null");Method m = findMethod(target.getClass(), name);if(m == null) {return null;}makeAccessible(m);return invokeMethod(m, target);}public static Object invokeMethod(Object target, String name,  Object... args) {Assert.isNotNull(target, "target must not be null");Assert.isNotNull(name, "Method name must not be null");Method m = findMethod(target.getClass(), name);if(m == null) {return null;}return invokeMethod(m, target, args);}/** * Attempt to find a {@link Method} on the supplied class with the supplied name * and parameter types. Searches all superclasses up to <code>Object</code>. * <p>Returns <code>null</code> if no {@link Method} can be found. * @param clazz the class to introspect * @param name the name of the method * @param paramTypes the parameter types of the method * (may be <code>null</code> to indicate any signature) * @return the Method object, or <code>null</code> if none found */public static Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {Assert.isNotNull(clazz, "Class must not be null");Assert.isNotNull(name, "Method name must not be null");Class<?> searchType = clazz;while (searchType != null) {Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());for (Method method : methods) {if (name.equals(method.getName())&& (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {return method;}}searchType = searchType.getSuperclass();}return null;}/** * Invoke the specified {@link Method} against the supplied target object with no arguments. * The target object can be <code>null</code> when invoking a static {@link Method}. * <p>Thrown exceptions are handled via a call to {@link #handleReflectionException}. * @param method the method to invoke * @param target the target object to invoke the method on * @return the invocation result, if any * @see #invokeMethod(java.lang.reflect.Method, Object, Object[]) */public static Object invokeMethod(Method method, Object target) {return invokeMethod(method, target, new Object[0]);}/** * Invoke the specified {@link Method} against the supplied target object with the * supplied arguments. The target object can be <code>null</code> when invoking a * static {@link Method}. * <p>Thrown exceptions are handled via a call to {@link #handleReflectionException}. * @param method the method to invoke * @param target the target object to invoke the method on * @param args the invocation arguments (may be <code>null</code>) * @return the invocation result, if any */public static Object invokeMethod(Method method, Object target, Object... args) {try {return method.invoke(target, args);}catch (Exception ex) {handleReflectionException(ex);}throw new IllegalStateException("Should never get here");}/** * Invoke the specified JDBC API {@link Method} against the supplied target * object with no arguments. * @param method the method to invoke * @param target the target object to invoke the method on * @return the invocation result, if any * @throws SQLException the JDBC API SQLException to rethrow (if any) * @see #invokeJdbcMethod(java.lang.reflect.Method, Object, Object[]) */public static Object invokeJdbcMethod(Method method, Object target) throws SQLException {return invokeJdbcMethod(method, target, new Object[0]);}/** * Invoke the specified JDBC API {@link Method} against the supplied target * object with the supplied arguments. * @param method the method to invoke * @param target the target object to invoke the method on * @param args the invocation arguments (may be <code>null</code>) * @return the invocation result, if any * @throws SQLException the JDBC API SQLException to rethrow (if any) * @see #invokeMethod(java.lang.reflect.Method, Object, Object[]) */public static Object invokeJdbcMethod(Method method, Object target, Object... args) throws SQLException {try {return method.invoke(target, args);}catch (IllegalAccessException ex) {handleReflectionException(ex);}catch (InvocationTargetException ex) {if (ex.getTargetException() instanceof SQLException) {throw (SQLException) ex.getTargetException();}handleInvocationTargetException(ex);}throw new IllegalStateException("Should never get here");}/** * Handle the given reflection exception. Should only be called if no * checked exception is expected to be thrown by the target method. * <p>Throws the underlying RuntimeException or Error in case of an * InvocationTargetException with such a root cause. Throws an * IllegalStateException with an appropriate message else. * @param ex the reflection exception to handle */public static void handleReflectionException(Exception ex) {if (ex instanceof NoSuchMethodException) {throw new IllegalStateException("Method not found: " + ex.getMessage());}if (ex instanceof IllegalAccessException) {throw new IllegalStateException("Could not access method: " + ex.getMessage());}if (ex instanceof InvocationTargetException) {handleInvocationTargetException((InvocationTargetException) ex);}if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}throw new UndeclaredThrowableException(ex);}/** * Handle the given invocation target exception. Should only be called if no * checked exception is expected to be thrown by the target method. * <p>Throws the underlying RuntimeException or Error in case of such a root * cause. Throws an IllegalStateException else. * @param ex the invocation target exception to handle */public static void handleInvocationTargetException(InvocationTargetException ex) {rethrowRuntimeException(ex.getTargetException());}/** * Rethrow the given {@link Throwable exception}, which is presumably the * <em>target exception</em> of an {@link InvocationTargetException}. Should * only be called if no checked exception is expected to be thrown by the * target method. * <p>Rethrows the underlying exception cast to an {@link RuntimeException} or * {@link Error} if appropriate; otherwise, throws an * {@link IllegalStateException}. * @param ex the exception to rethrow * @throws RuntimeException the rethrown exception */public static void rethrowRuntimeException(Throwable ex) {if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}if (ex instanceof Error) {throw (Error) ex;}throw new UndeclaredThrowableException(ex);}/** * Rethrow the given {@link Throwable exception}, which is presumably the * <em>target exception</em> of an {@link InvocationTargetException}. Should * only be called if no checked exception is expected to be thrown by the * target method. * <p>Rethrows the underlying exception cast to an {@link Exception} or * {@link Error} if appropriate; otherwise, throws an * {@link IllegalStateException}. * @param ex the exception to rethrow * @throws Exception the rethrown exception (in case of a checked exception) */public static void rethrowException(Throwable ex) throws Exception {if (ex instanceof Exception) {throw (Exception) ex;}if (ex instanceof Error) {throw (Error) ex;}throw new UndeclaredThrowableException(ex);}/** * Determine whether the given method explicitly declares the given * exception or one of its superclasses, which means that an exception of * that type can be propagated as-is within a reflective invocation. * @param method the declaring method * @param exceptionType the exception to throw * @return <code>true</code> if the exception can be thrown as-is; * <code>false</code> if it needs to be wrapped */public static boolean declaresException(Method method, Class<?> exceptionType) {Assert.isNotNull(method, "Method must not be null");Class<?>[] declaredExceptions = method.getExceptionTypes();for (Class<?> declaredException : declaredExceptions) {if (declaredException.isAssignableFrom(exceptionType)) {return true;}}return false;}/** * Determine whether the given field is a "public static final" constant. * @param field the field to check */public static boolean isPublicStaticFinal(Field field) {int modifiers = field.getModifiers();return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));}/** * Determine whether the given method is an "equals" method. * @see java.lang.Object#equals(Object) */public static boolean isEqualsMethod(Method method) {if (method == null || !method.getName().equals("equals")) {return false;}Class<?>[] paramTypes = method.getParameterTypes();return (paramTypes.length == 1 && paramTypes[0] == Object.class);}/** * Determine whether the given method is a "hashCode" method. * @see java.lang.Object#hashCode() */public static boolean isHashCodeMethod(Method method) {return (method != null && method.getName().equals("hashCode") && method.getParameterTypes().length == 0);}/** * Determine whether the given method is a "toString" method. * @see java.lang.Object#toString() */public static boolean isToStringMethod(Method method) {return (method != null && method.getName().equals("toString") && method.getParameterTypes().length == 0);}/** * Determine whether the given method is originally declared by {@link java.lang.Object}. */public static boolean isObjectMethod(Method method) {try {Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes());return true;} catch (SecurityException ex) {return false;} catch (NoSuchMethodException ex) {return false;}}/** * Make the given field accessible, explicitly setting it accessible if * necessary. The <code>setAccessible(true)</code> method is only called * when actually necessary, to avoid unnecessary conflicts with a JVM * SecurityManager (if active). * @param field the field to make accessible * @see java.lang.reflect.Field#setAccessible */public static void makeAccessible(Field field) {if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) ||Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {field.setAccessible(true);}}/** * Make the given method accessible, explicitly setting it accessible if * necessary. The <code>setAccessible(true)</code> method is only called * when actually necessary, to avoid unnecessary conflicts with a JVM * SecurityManager (if active). * @param method the method to make accessible * @see java.lang.reflect.Method#setAccessible */public static void makeAccessible(Method method) {if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))&& !method.isAccessible()) {method.setAccessible(true);}}/** * Make the given constructor accessible, explicitly setting it accessible * if necessary. The <code>setAccessible(true)</code> method is only called * when actually necessary, to avoid unnecessary conflicts with a JVM * SecurityManager (if active). * @param ctor the constructor to make accessible * @see java.lang.reflect.Constructor#setAccessible */public static void makeAccessible(Constructor<?> ctor) {if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers()))&& !ctor.isAccessible()) {ctor.setAccessible(true);}}/** * Perform the given callback operation on all matching methods of the given * class and superclasses. * <p>The same named method occurring on subclass and superclass will appear * twice, unless excluded by a {@link MethodFilter}. * @param clazz class to start looking at * @param mc the callback to invoke for each method * @see #doWithMethods(Class, MethodCallback, MethodFilter) */public static void doWithMethods(Class<?> clazz, MethodCallback mc) throws IllegalArgumentException {doWithMethods(clazz, mc, null);}/** * Perform the given callback operation on all matching methods of the given * class and superclasses (or given interface and super-interfaces). * <p>The same named method occurring on subclass and superclass will appear * twice, unless excluded by the specified {@link MethodFilter}. * @param clazz class to start looking at * @param mc the callback to invoke for each method * @param mf the filter that determines the methods to apply the callback to */public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf)throws IllegalArgumentException {// Keep backing up the inheritance hierarchy.Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {if (mf != null && !mf.matches(method)) {continue;}try {mc.doWith(method);}catch (IllegalAccessException ex) {throw new IllegalStateException("Shouldn't be illegal to access method '" + method.getName()+ "': " + ex);}}if (clazz.getSuperclass() != null) {doWithMethods(clazz.getSuperclass(), mc, mf);}else if (clazz.isInterface()) {for (Class<?> superIfc : clazz.getInterfaces()) {doWithMethods(superIfc, mc, mf);}}}/** * Get all declared methods on the leaf class and all superclasses. Leaf * class methods are included first. */public static Method[] getAllDeclaredMethods(Class<?> leafClass) throws IllegalArgumentException {final List<Method> methods = new ArrayList<Method>(32);doWithMethods(leafClass, new MethodCallback() {public void doWith(Method method) {methods.add(method);}});return methods.toArray(new Method[methods.size()]);}/** * Get the unique set of declared methods on the leaf class and all superclasses. Leaf * class methods are included first and while traversing the superclass hierarchy any methods found * with signatures matching a method already included are filtered out. */public static Method[] getUniqueDeclaredMethods(Class<?> leafClass) throws IllegalArgumentException {final List<Method> methods = new ArrayList<Method>(32);doWithMethods(leafClass, new MethodCallback() {public void doWith(Method method) {Method methodBeingOverriddenWithCovariantReturnType = null;for (Method existingMethod : methods) {if (method.getName().equals(existingMethod.getName()) &&Arrays.equals(method.getParameterTypes(), existingMethod.getParameterTypes())) {// is this a covariant return type situation?if (existingMethod.getReturnType() != method.getReturnType() &&existingMethod.getReturnType().isAssignableFrom(method.getReturnType())) {methodBeingOverriddenWithCovariantReturnType = existingMethod;}break;}}if (methodBeingOverriddenWithCovariantReturnType != null) {methods.remove(methodBeingOverriddenWithCovariantReturnType);}}});return methods.toArray(new Method[methods.size()]);}/** * Invoke the given callback on all fields in the target class, going up the * class hierarchy to get all declared fields. * @param clazz the target class to analyze * @param fc the callback to invoke for each field */public static void doWithFields(Class<?> clazz, FieldCallback fc) throws IllegalArgumentException {doWithFields(clazz, fc, null);}/** * Invoke the given callback on all fields in the target class, going up the * class hierarchy to get all declared fields. * @param clazz the target class to analyze * @param fc the callback to invoke for each field * @param ff the filter that determines the fields to apply the callback to */public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff)throws IllegalArgumentException {// Keep backing up the inheritance hierarchy.Class<?> targetClass = clazz;do {Field[] fields = targetClass.getDeclaredFields();for (Field field : fields) {// Skip static and final fields.if (ff != null && !ff.matches(field)) {continue;}try {fc.doWith(field);}catch (IllegalAccessException ex) {throw new IllegalStateException("Shouldn't be illegal to access field '" + field.getName() + "': " + ex);}}targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);}/** * Given the source object and the destination, which must be the same class * or a subclass, copy all fields, including inherited fields. Designed to * work on objects with public no-arg constructors. * @throws IllegalArgumentException if the arguments are incompatible */public static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException {if (src == null) {throw new IllegalArgumentException("Source for field copy cannot be null");}if (dest == null) {throw new IllegalArgumentException("Destination for field copy cannot be null");}if (!src.getClass().isAssignableFrom(dest.getClass())) {throw new IllegalArgumentException("Destination class [" + dest.getClass().getName()+ "] must be same or subclass as source class [" + src.getClass().getName() + "]");}doWithFields(src.getClass(), new FieldCallback() {public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {makeAccessible(field);Object srcValue = field.get(src);field.set(dest, srcValue);}}, COPYABLE_FIELDS);}/** * Action to take on each method. */public interface MethodCallback {/** * Perform an operation using the given method. * @param method the method to operate on */void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;}/** * Callback optionally used to filter methods to be operated on by a method callback. */public interface MethodFilter {/** * Determine whether the given method matches. * @param method the method to check */boolean matches(Method method);}/** * Callback interface invoked on each field in the hierarchy. */public interface FieldCallback {/** * Perform an operation using the given field. * @param field the field to operate on */void doWith(Field field) throws IllegalArgumentException, IllegalAccessException;}/** * Callback optionally used to filter fields to be operated on by a field callback. */public interface FieldFilter {/** * Determine whether the given field matches. * @param field the field to check */boolean matches(Field field);}/** * Pre-built FieldFilter that matches all non-static, non-final fields. */public static FieldFilter COPYABLE_FIELDS = new FieldFilter() {public boolean matches(Field field) {return !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()));}};/** * Pre-built MethodFilter that matches all non-bridge methods. */public static MethodFilter NON_BRIDGED_METHODS = new MethodFilter() {public boolean matches(Method method) {return !method.isBridge();}};/** * Pre-built MethodFilter that matches all non-bridge methods * which are not declared on <code>java.lang.Object</code>. */public static MethodFilter USER_DECLARED_METHODS = new MethodFilter() {public boolean matches(Method method) {return (!method.isBridge() && method.getDeclaringClass() != Object.class);}};}


原创粉丝点击