集册 Java实例教程 获取匹配的可访问方法

获取匹配的可访问方法

欢马劈雪     最近更新时间:2020-01-02 10:19:05

412
获取匹配的可访问方法

/*

 **        DroidPlugin Project

 **

 ** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>

 **

 ** This file is part of DroidPlugin.

 **

 ** DroidPlugin is free software: you can redistribute it and/or

 ** modify it under the terms of the GNU Lesser General Public

 ** License as published by the Free Software Foundation, either

 ** version 3 of the License, or (at your option) any later version.

 **

 ** DroidPlugin is distributed in the hope that it will be useful,

 ** but WITHOUT ANY WARRANTY; without even the implied warranty of

 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 ** Lesser General Public License for more details.

 **

 ** You should have received a copy of the GNU Lesser General Public

 ** License along with DroidPlugin.  If not, see <http://www.gnu.org/licenses/lgpl.txt>

 **

 **/

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;
/* 
 来自 
*时 代 J a v a 公 众 号 - N o w J a v  a . c o m*/

import java.lang.reflect.Modifier;

import java.util.HashMap;

import java.util.Map;


public class Main{

    private static Map<String, Method> sMethodCache = new HashMap<String, Method>();

    private static Method getMatchingAccessibleMethod(final Class<?> cls,

            final String methodName, final Class<?>... parameterTypes) {


        String key = getKey(cls, methodName, parameterTypes);

        Method cachedMethod;

        synchronized (sMethodCache) {
        /*
        时 代 J     a    v  a - nowjava.com 提供
        */

            cachedMethod = sMethodCache.get(key);

        }

        if (cachedMethod != null) {

            if (!cachedMethod.isAccessible()) {

                cachedMethod.setAccessible(true);

            }

            return cachedMethod;

        }


        try {

            final Method method = cls.getMethod(methodName, parameterTypes);

            MemberUtils.setAccessibleWorkaround(method);

            synchronized (sMethodCache) {

                sMethodCache.put(key, method);

            }

            return method;

        } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception

        }

        // search through all methods

        Method bestMatch = null;

        final Method[] methods = cls.getMethods();

        for (final Method method : methods) {

            // compare name and parameters

            if (method.getName().equals(methodName)

                    && MemberUtils.isAssignable(parameterTypes,

                            method.getParameterTypes(), true)) {

                // get accessible version of method

                final Method accessibleMethod = getAccessibleMethod(method);

                if (accessibleMethod != null

                        && (bestMatch == null || MemberUtils

                                .compareParameterTypes(accessibleMethod

                                        .getParameterTypes(), bestMatch

                                        .getParameterTypes(),

                                        parameterTypes) < 0)) {

                    bestMatch = accessibleMethod;

                }

            }

        }

        if (bestMatch != null) {

            MemberUtils.setAccessibleWorkaround(bestMatch);

        }

        synchronized (sMethodCache) {

            sMethodCache.put(key, bestMatch);

        }

        return bestMatch;

    }

    private static String getKey(final Class<?> cls,

            final String methodName, final Class<?>... parameterTypes) {

        StringBuilder sb = new StringBuilder();

        sb.append(cls.toString()).append("#").append(methodName);

        if (parameterTypes != null && parameterTypes.length > 0) {

            for (Class<?> parameterType : parameterTypes) {

                sb.append(parameterType.toString()).append("#");

            }

        } else {

            sb.append(Void.class.toString());

        }

        return sb.toString();

    }

    private static boolean isAccessible(final Class<?> type) {

        Class<?> cls = type;

        while (cls != null) {

            if (!Modifier.isPublic(cls.getModifiers())) {

                return false;

            }

            cls = cls.getEnclosingClass();

        }

        return true;

    }

    private static Method getAccessibleMethod(Method method) {

        if (!MemberUtils.isAccessible(method)) {

            return null;

        }

        // If the declaring class is public, we are done

        final Class<?> cls = method.getDeclaringClass();

        if (Modifier.isPublic(cls.getModifiers())) {

            return method;

        }

        final String methodName = method.getName();

        final 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;

    }

    public static Method getAccessibleMethod(final Class<?> cls,

            final String methodName, final Class<?>... parameterTypes)

            throws NoSuchMethodException {

        String key = getKey(cls, methodName, parameterTypes);

        Method method;

        synchronized (sMethodCache) {

            method = sMethodCache.get(key);

        }

        if (method != null) {

            if (!method.isAccessible()) {

                method.setAccessible(true);

            }

            return method;

        }


        Method accessibleMethod = getAccessibleMethod(cls.getMethod(

                methodName, parameterTypes));

        synchronized (sMethodCache) {

            sMethodCache.put(key, accessibleMethod);

        }

        return accessibleMethod;


    }

    private static Method getAccessibleMethodFromInterfaceNest(

            Class<?> cls, final String methodName,

            final Class<?>... parameterTypes) {

        // Search up the superclass chain

        for (; cls != null; cls = cls.getSuperclass()) {


            // Check the implemented interfaces of the parent class

            final 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 {

                    return interfaces[i].getDeclaredMethod(methodName,

                            parameterTypes);

                } catch (final NoSuchMethodException e) { 
展开阅读全文