调用参数类型与对象类型完全匹配的方法。
/******************************************************************************* * Copyright (c) 2011 MadRobot. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Elton Kent - initial API and implementation ******************************************************************************/ /* 时 代 J a v a 公 众 号 - N o w J a v a . c o m 提供 */ import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; public class Main{/* 来 自 n o w j a v a . c o m*/ /** * <p> * Invoke a method whose parameter types match exactly the object types. * </p> * * <p> * This uses reflection to invoke the method obtained from a call to * <code>getAccessibleMethod()</code>. * </p> * * @param object * invoke method on this object * @param methodName * get method with this name * @param args * use these arguments - treat null as empty array * @return The value returned by the invoked method * * @throws NoSuchMethodException * if there is no such accessible method * @throws InvocationTargetException * wraps an exception thrown by the * method invoked * @throws IllegalAccessException * if the requested method is not accessible * via reflection */ public static Object invokeExactMethod(Object object, String methodName, Object... args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (args == null) { args = ArrayUtils.EMPTY_OBJECT_ARRAY; } int arguments = args.length; Class<?>[] parameterTypes = new Class[arguments]; for (int i = 0; i < arguments; i++) { parameterTypes[i] = args[i].getClass(); } return invokeExactMethod(object, methodName, args, parameterTypes); } /** * <p> * Invoke a method whose parameter types match exactly the parameter types * given. * </p> * * <p> * This uses reflection to invoke the method obtained from a call to * <code>getAccessibleMethod()</code>. * </p> * * @param object * invoke method on this object * @param methodName * get method with this name * @param args * use these arguments - treat null as empty array * @param parameterTypes * match these parameters - treat null as empty array * @return The value returned by the invoked method * * @throws NoSuchMethodException * if there is no such accessible method * @throws InvocationTargetException * wraps an exception thrown by the * method invoked * @throws IllegalAccessException * if the requested method is not accessible * via reflection */ public static Object invokeExactMethod(Object object, String methodName, Object[] args, Class<?>[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (args == null) { args = ArrayUtils.EMPTY_OBJECT_ARRAY; } if (parameterTypes == null) { parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY; } Method method = getAccessibleMethod(object.getClass(), methodName, parameterTypes); if (method == null) { throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + object.getClass().getName()); } return method.invoke(object, args); } /** * <p> * Return an accessible method (that is, one that can be invoked via * reflection) with given name and parameters. If no such method can be * found, return <code>null</code>. This is just a convenient wrapper for * {@link #getAccessibleMethod(Method method)}. * </p> * * @param cls * get method from this class * @param methodName * get method with this name * @param parameterTypes * with these parameters types * @return The accessible method */ public static Method getAccessibleMethod(Class<?> cls, String methodName, Class<?>... parameterTypes) { try { return getAccessibleMethod(cls.getMethod(methodName, parameterTypes)); } catch (NoSuchMethodException e) { return (null); } } /** * <p> * Return an accessible method (that is, one that can be invoked via * reflection) that implements the specified Method. If no such method can * be found, return <code>null</code>. * </p> * * @param method * The method that we wish to call * @return The accessible method */ public static Method getAccessibleMethod(Method method) { if (!MemberUtils.isAccessible(method)) { return null; } // If the declaring class is public, we are done Class<?> cls = method.getDeclaringClass(); if (Modifier.isPublic(cls.getModifiers())) { return method; } String methodName = method.getName(); Class<?>[] parameterTypes = method.getParameterTypes(); // Check the implemented interfaces and subinterfaces method = getAccessibleMethodFromInterfaceNest(cls, methodName, parameterTypes); // Check the superclass chain if (method == null) { method = getAccessibleMethodFromSuperclass(cls, methodName, parameterTypes); } return method; } /** * <p> * Return an accessible method (that is, one that can be invoked via * reflection) that implements the specified method, by scanning through all * implemented interfaces and subinterfaces. If no such method can be found, * return <code>null</code>. * </p> * * <p> * There isn't any good reason why this method must be private. It is * because there doesn't seem any reason why other classes should call this * rather than the higher level methods. * </p> * * @param cls * Parent class for the interfaces to be checked * @param methodName * Method name of the method we wish to call * @param parameterTypes * The parameter type signatures * @return the accessible method or <code>null</code> if not found */ private static Method getAccessibleMethodFromInterfaceNest( Class<?> cls, String methodName, Class<?>... parameterTypes) { Method method = null; // Search up the superclass chain for (; cls != null; cls = cls.getSuperclass()) { // Check the implemented interfaces of the parent class Class<?>[] interfaces = cls.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { // Is this interface public? if (!Modifier.isPublic(interfaces[i].getModifiers())) { continue; } // Does the method exist on this interface? try { method = interfaces[i].getDeclaredMethod(methodName, parameterTypes); } catch (NoSuchMethodException e) { /* * Swallow, if no method is found after the loop then this * method returns null. */ } if (method != null) { break; }