文档章节

Java反射随记

canghailan
 canghailan
发布于 2012/05/05 01:35
字数 3357
阅读 247
收藏 8

属性存取,方法调用是最Java反射最常用也是最基本的功能。虽然已经有commons-beanutils实现在前,但出于种种考虑,还是自己实现了一遍。经过一段时间的思考重构,终于将原来一些简单的想法渐渐实现并完善。

属性存取实现了根据getter/setter方法和直接访问Field两种方式。

方法调用主要实现了根据方法参数自动决定调用最特定的重载方法。

主要支持接口及类:

通用查找接口

public interface Lookup<K, V> {
    V find(K key);
}

类及名称

public class ClassNamePair {
    private final Class<?> clazz;
    private final String name;
...

方法名及参数

public class MethodIdentifier {
    private final Class<?> clazz;
    private final String name;
    private final Class<?>[] argumentTypes;
...

根据属性名查找Field

public class FieldLookup implements Lookup<ClassNamePair, Field> {
...

根据方法名、参数查找最特定Method

public class MethodLookup implements Lookup<MethodIdentifier, Method> {
...


实现:

1.根据属性名查找Field(public, protected, private, package)

按当前类->接口->超类的顺序搜索声明的Field即可。

public Field find(ClassNamePair key) {
    Field field = getDeclaredField(key.getClazz(), key.getName());
    if (field == null) {
        field = getInheritedFromInterfaces(key.getClazz(), key.getName());
        if (field == null) {
            field = getInheritedFromSuperclass(key.getClazz(), key.getName());
        }
    }
    return field;
}

在给定类/接口查找Field

private static Field getDeclaredField(Class<?> cls, String name) {
    for (Field field : cls.getDeclaredFields()) {
        if (field.getName().equals(name)) {
            return field;
        }
    }
    return null;
}

在此基础上,在接口及超类中查找也相当容易实现

private static Field getInheritedFromInterfaces(Class<?> cls, String name) {
    for (Class<?> i : cls.getInterfaces()) {
        Field field = getDeclaredField(i, name);
        if (field != null) {
            return field;
        }
    }
    return null;
}

private static Field getInheritedFromSuperclass(Class<?> cls, String name) {
    for (Class<?> s = cls.getSuperclass(); s != null; s = s.getSuperclass()) {
        Field field = getDeclaredField(s, name);
        if (field != null) {
            return field;
        }
    }
    return null;
}

 

 2.根据方法名、参数查找合适Method(public)

 由于涉及方法重载(Overloading),所以根据方法名、参数查找合适的Method比较复杂。将之分解为多个步骤来实现。

2.1 根据方法名过滤并排序所有可能的方法

对Method进行一些简单的包装:方便后续查找

public class MethodSignature {
    private final Method method;
    private final Class<?>[] parameterTypes;
    private final Class<?> varArgType;

    public MethodSignature(Method method) {
        this.method = method;
        parameterTypes = method.getParameterTypes();
        varArgType = method.isVarArgs() ?
                parameterTypes[parameterTypes.length - 1].getComponentType() : null;
    }
...

重载方法查找:过滤->排序

public class OverloadingLookup implements Lookup<ClassNamePair, MethodSignature[]> {
    public MethodSignature[] find(ClassNamePair key) {
        return sort(filter(key.getClazz(), key.getName()));
    }
...

按方法名过滤,获取所有重载方法

private static MethodSignature[] filter(Class<?> cls, String name) {
    List<MethodSignature> overloadingMethods = new LinkedList<>();
    for (Method method : cls.getMethods()) {
        if (method.getName().equals(name)) {
            overloadingMethods.add(new MethodSignature(method));
        }
    }
    return overloadingMethods.toArray(new MethodSignature[overloadingMethods.size()]);
}

按参数长度由小到大排序,相同参数长度的方法,变元方法在前,定元方法在后,方便后续查找

public static final Comparator<MethodSignature> PARAM_LENGTH_COMPARATOR =
        new Comparator<MethodSignature>() {
            @Override
            public int compare(MethodSignature o1, MethodSignature o2) {
                int c1 = Integer.compare(
                        o1.getParameterTypes().length,
                        o2.getParameterTypes().length
                );
                if (c1 == 0) {
                    if (o1.isVarArgs()) {
                        return o2.isVarArgs() ? 0 : -1;
                    } else {
                        return o2.isVarArgs() ? 1 : 0;
                    }
                } else {
                    return c1;
                }
            }
        };

private static MethodSignature[] sort(MethodSignature[] overloadingMethods) {
    Arrays.sort(overloadingMethods, PARAM_LENGTH_COMPARATOR);
    return overloadingMethods;
}

 2.2 在重载方法中根据参数选择最特定的方法

这部分的思路参照了Java语言规范(JLS)15.12节 方法调用表达式。

JLS 15.12.2节编译期确定方法签名分为以下几个步骤:

1)不允许拆装箱及使用可变元数方法进行重载解析,即可由类型宽化(扩展基本转换、扩展引用转换)确定的匹配元数方法。(确保较老语言版本中任何有效的方法调用不会因为引入隐式拆装箱、可变元数方法而被当成不明确的)

2)允许拆装箱但不允许使用可变元数方法进行重载解析,即可由方法调用转换确定的匹配元数方法。(确保如果存在一个可用固定元数方法,可变元数方法就不会被调用)

3)允许拆装箱及使用可变元数方法进行重载解析。

以上每个步骤中,如果存在多个符合的方法,则需在它们中选择最特定的方法。

JLS 5.3节方法调用转换规定可包括以下转换:

  • 同一性转换:如int->int, Object->Object
  • 扩展基本转换:如short->int
  • 扩展引用转换:如String->Object
  • 装箱转换,可后接扩展引用转换:如int->Integer->Number
  • 拆箱转换,可后接扩展基本转换:如Short->short->int

public class MethodInvocationConversion {
    public static boolean isWideningPrimitiveConversion(Class<?> from, Class<?> to) {
        if (to == int.class) {
            return from == char.class ||
                    from == short.class ||
                    from == byte.class;
        }
        if (to == double.class) {
            return from == float.class ||
                    from == long.class ||
                    from == int.class ||
                    from == char.class ||
                    from == short.class ||
                    from == byte.class;
        }
        if (to == short.class) {
            return from == byte.class;
        }
        if (to == long.class) {
            return from == int.class ||
                    from == char.class ||
                    from == short.class ||
                    from == byte.class;
        }
        if (to == float.class) {
            return from == long.class ||
                    from == int.class ||
                    from == char.class ||
                    from == short.class ||
                    from == byte.class;
        }
        return false;
    }

    public static boolean isWideningReferenceConversion(Class<?> from, Class<?> to) {
        return to.isAssignableFrom(from);
    }

    public static Class<?> boxing(Class<?> cls) {
        if (cls == int.class) {
            return Integer.class;
        }
        if (cls == double.class) {
            return Double.class;
        }
        if (cls == boolean.class) {
            return Boolean.class;
        }
        if (cls == byte.class) {
            return Byte.class;
        }
        if (cls == char.class) {
            return Character.class;
        }
        if (cls == short.class) {
            return Short.class;
        }
        if (cls == long.class) {
            return Long.class;
        }
        if (cls == float.class) {
            return Float.class;
        }
        return null;
    }

    public static Class<?> unboxing(Class<?> cls) {
        if (cls == Integer.class) {
            return int.class;
        }
        if (cls == Double.class) {
            return double.class;
        }
        if (cls == Boolean.class) {
            return boolean.class;
        }
        if (cls == Byte.class) {
            return byte.class;
        }
        if (cls == Character.class) {
            return char.class;
        }
        if (cls == Short.class) {
            return short.class;
        }
        if (cls == Long.class) {
            return long.class;
        }
        if (cls == Float.class) {
            return float.class;
        }
        return null;
    }
}

确定方法签名时执行的转换可以分为类型宽化,方法调用转换两种,出于性能考虑,还可以加上完全匹配(全是同一性转换)。

public class MethodSignatureDeterminer {
...
    private static ApplicableKind checkApplicable(Class<?> from, Class<?> to) {
        if (to == from) {
            return ApplicableKind.MATCHING;
        }
        if (to.isPrimitive()) {
            if (from == null) {
                return null;
            }
            if (from.isPrimitive()) {
                return isWideningPrimitiveConversion(from, to) ?
                        ApplicableKind.SUBTYPING : null;
            } else {
                Class<?> unboxingClass = unboxing(from);
                return (to == unboxingClass || isWideningPrimitiveConversion(unboxingClass, to)) ?
                        ApplicableKind.METHOD_INVOCATION_CONVERSION : null;
            }
        } else {
            if (from == null) {
                return ApplicableKind.SUBTYPING;
            }
            if (from.isPrimitive()) {
                Class<?> boxingClass = boxing(from);
                return (to == boxingClass || isWideningReferenceConversion(boxingClass, to)) ?
                        ApplicableKind.METHOD_INVOCATION_CONVERSION : null;
            } else {
                return isWideningReferenceConversion(from, to) ?
                        ApplicableKind.SUBTYPING : null;
            }
        }
    }

    static enum ApplicableKind {
        MATCHING,
        SUBTYPING,
        METHOD_INVOCATION_CONVERSION;

        ApplicableKind combine(ApplicableKind that) {
            return this.compareTo(that) > 0 ? this : that;
        }
    }
...
}

固定元数方法、可变元数方法的判定

public class MethodSignatureDeterminer {
...
    private static boolean isMatchingArity(MethodSignature signature, MethodIdentifier id) {
        return !signature.isVarArgs() &&
                signature.getParameterTypes().length == id.getArgumentTypes().length;
    }

    private static boolean isVariableArity(MethodSignature signature, MethodIdentifier id) {
        return signature.isVarArgs() &&
                signature.getParameterTypes().length <= id.getArgumentTypes().length;
    }
...
}

在上述准备工作做好后,可通过JLS 15.12.2节中给出的算法实现各步骤。

步骤1、步骤2:固定元数方法的转换

public class MethodSignatureDeterminer {
...
    private static ApplicableKind checkApplicableMatchingArity(MethodSignature method,
                                                               MethodIdentifier id) {
        if (method.getParameterTypes().length == 0) {
            return ApplicableKind.MATCHING;
        } else {
            ApplicableKind kind = null;
            final Class<?>[] paramTypes = method.getParameterTypes();
            final Class<?>[] argTypes = id.getArgumentTypes();
            for (int i = 0; i < paramTypes.length; ++i) {
                ApplicableKind paramKind = checkApplicable(argTypes[i], paramTypes[i]);
                if (paramKind == null) {
                    return null;
                }
                kind = kind == null ? paramKind : kind.combine(paramKind);
            }
            return kind;
        }
    }
...
}

步骤3:可变元数方法的转换

public class MethodSignatureDeterminer {
...
    private static ApplicableKind checkApplicableVariableArity(MethodSignature method,
                                                               MethodIdentifier id) {
        ApplicableKind kind = null;
        final Class<?>[] paramTypes = method.getParameterTypes();
        final int paramsLength = paramTypes.length;
        final Class<?>[] argTypes = id.getArgumentTypes();
        final int argsLength = argTypes.length;
        for (int i = 0; i < paramsLength - 1; ++i) {
            ApplicableKind paramKind = checkApplicable(argTypes[i], paramTypes[i]);
            if (paramKind == null) {
                return null;
            }
            kind = kind == null ? paramKind : kind.combine(paramKind);
        }
        Class<?> varArgType = method.getVarArgType();
        for (int i = paramsLength - 1; i < argsLength; ++i) {
            ApplicableKind paramKind = checkApplicable(argTypes[i], varArgType);
            if (paramKind == null) {
                return null;
            }
            kind = kind == null ? paramKind : kind.combine(paramKind);
        }
        return kind;
    }
...
}

选择最特定的方法

public class MethodSignatureDeterminer {
...
    private static boolean isMoreSpecificFixArity(MethodSignature m1, MethodSignature m2) {
        final Class<?>[] paramTypes1 = m1.getParameterTypes();
        final Class<?>[] paramTypes2 = m2.getParameterTypes();
        for (int i = 0; i < paramTypes1.length; ++i) {
            if (checkApplicable(paramTypes1[i], paramTypes2[i]) == null) {
                return false;
            }
        }
        return true;
    }

    private static boolean isMoreSpecificVariableArity(MethodSignature m1, MethodSignature m2) {
        final Class<?>[] paramTypes1 = m1.getParameterTypes();
        final int paramsLength1 = paramTypes1.length;
        final Class<?>[] paramTypes2 = m2.getParameterTypes();
        final int paramsLength2 = paramTypes2.length;
        if (paramsLength1 >= paramsLength2) {
            for (int i = 0; i < paramsLength2 - 1; ++i) {
                if (checkApplicable(paramTypes1[i], paramTypes2[i]) == null) {
                    return false;
                }
            }
            Class<?> varArgType = m2.getVarArgType();
            for (int i = paramsLength2 - 1; i < paramsLength1; ++i) {
                if (checkApplicable(paramTypes1[i], varArgType) == null) {
                    return false;
                }
            }
            return true;
        } else {
            for (int i = 0; i < paramsLength1 - 1; ++i) {
                if (checkApplicable(paramTypes1[i], paramTypes2[i]) == null) {
                    return false;
                }
            }
            Class<?> varArgType = m1.getVarArgType();
            for (int i = paramsLength1 - 1; i < paramsLength2; ++i) {
                if (checkApplicable(varArgType, paramTypes2[i]) == null) {
                    return false;
                }
            }
            return true;
        }
    }
...
}

确定方法签名的过程实质是一个有限状态转换机。

状态:开始(S), 类型宽化固定元数(P1),方法调用转换固定元数(P2),可变元数(P3),完成(F)

事件:不可转换(EN),匹配固定元数方法(EM),类型宽化固定元数方法(ES),方法调用转换固定元数方法(EC),可变元方法(EV)

S P1 P2 P3  F
 S EN ES EC EV EM
P1  X ES  X  X EM
P2  X ES EC  X EM
P3  X ES EC EV EM
 F  X  X  X  X  X

定义状态机:

public class MethodSignatureDeterminer {
    private Phase currentPhase;
    private MethodSignature mostSpecific;

    public MethodSignatureDeterminer() {
        this.currentPhase = Phase.START;
    }
...
    public void accept(MethodSignature signature, MethodIdentifier id) {
        currentPhase.accept(this, signature, id);
    }
...
    public static enum Phase {
    ...
        abstract void accept(MethodSignatureDeterminer determiner,
                             MethodSignature signature, MethodIdentifier id);
    }
...
}

开始:

START {
    @Override
    final void accept(MethodSignatureDeterminer determiner,
                      MethodSignature signature, MethodIdentifier id) {
        if (isMatchingArity(signature, id)) {
            ApplicableKind kind = checkApplicableMatchingArity(signature, id);
            if (kind != null) {
                determiner.mostSpecific = signature;
                switch (kind) {
                    case MATCHING: {
                        determiner.currentPhase = FINISH;
                        break;
                    }
                    case SUBTYPING: {
                        determiner.currentPhase = MATCHING_ARITY_BY_SUBTYPING;
                        break;
                    }
                    case METHOD_INVOCATION_CONVERSION: {
                        determiner.currentPhase = MATCHING_ARITY_BY_CONVERSION;
                        break;
                    }
                }
            }
        } else if (isVariableArity(signature, id)) {
            if (checkApplicableVariableArity(signature, id) != null) {
                determiner.mostSpecific = signature;
                determiner.currentPhase = VARIABLE_ARITY;
            }
        }
    }
}

 类型宽化固定元数:(由于是已排序的,所以固定元数方法搜索结束后可认为整个搜索过程结束)

MATCHING_ARITY_BY_SUBTYPING {
    @Override
    final void accept(MethodSignatureDeterminer determiner,
                      MethodSignature signature, MethodIdentifier id) {
        if (isMatchingArity(signature, id)) {
            ApplicableKind kind = checkApplicableMatchingArity(signature, id);
            if (kind != null) {
                switch (kind) {
                    case MATCHING: {
                        determiner.mostSpecific = signature;
                        determiner.currentPhase = FINISH;
                        break;
                    }
                    case SUBTYPING: {
                        if (isMoreSpecificFixArity(signature, determiner.mostSpecific)) {
                            determiner.mostSpecific = signature;
                        }
                        break;
                    }
                }
            }
        } else {
            if (signature.getParameterTypes().length != id.getArgumentTypes().length) {
                determiner.currentPhase = FINISH;
            }
        }
    }
}

方法调用转换固定元数:(由于是已排序的,所以固定元数方法搜索结束后可认为整个搜索过程结束)

MATCHING_ARITY_BY_CONVERSION {
    @Override
    final void accept(MethodSignatureDeterminer determiner,
                      MethodSignature signature, MethodIdentifier id) {
        if (isMatchingArity(signature, id)) {
            ApplicableKind kind = checkApplicableMatchingArity(signature, id);
            if (kind != null) {
                switch (kind) {
                    case MATCHING: {
                        determiner.mostSpecific = signature;
                        determiner.currentPhase = FINISH;
                        break;
                    }
                    case SUBTYPING: {
                        determiner.mostSpecific = signature;
                        determiner.currentPhase = MATCHING_ARITY_BY_SUBTYPING;
                        break;
                    }
                    case METHOD_INVOCATION_CONVERSION: {
                        if (isMoreSpecificFixArity(signature, determiner.mostSpecific)) {
                            determiner.mostSpecific = signature;
                        }
                        break;
                    }
                }
            }
        } else {
            if (signature.getParameterTypes().length != id.getArgumentTypes().length) {
                determiner.currentPhase = FINISH;
            }
        }
    }
}

可变元数:

VARIABLE_ARITY {
    @Override
    final void accept(MethodSignatureDeterminer determiner,
                      MethodSignature signature, MethodIdentifier id) {
        if (isVariableArity(signature, id)) {
            if (checkApplicableVariableArity(signature, id) != null) {
                if (isMoreSpecificVariableArity(signature, determiner.mostSpecific)) {
                    determiner.mostSpecific = signature;
                }
            }
        }
    }
}

完成:

FINISH {
    @Override
    final void accept(MethodSignatureDeterminer determiner,
                      MethodSignature signature, MethodIdentifier id) {
        //do nothing
    }
}

2.3 集成

将2.1,2.2的功能组合。

public class MethodLookup implements Lookup<MethodIdentifier, Method> {
    private final Lookup<ClassNamePair, MethodSignature[]> overloadingLookup;
...
    public Method find(MethodIdentifier key) {
        MethodSignature signature = determine(findOverloading(key), key);
        return signature == null ? null : signature.getMethod();
    }
...
}

获取所有重载方法

private MethodSignature[] findOverloading(MethodIdentifier id) {
    return overloadingLookup.find(new ClassNamePair(id.getClazz(), id.getName()));
}

根据参数个数>=元数决定搜索范围(0-maxAcceptIndex)

private static int maxAcceptIndex(MethodSignature[] methods, MethodIdentifier id) {
    int argsLength = id.getArgumentTypes().length;
    // binary search
    int from = 0;
    int to = methods.length - 1;
    while (from <= to) {
        int index = (from + to) >>> 1;

        if (methods[index].getParameterTypes().length > argsLength) {
            to = index - 1;
        } else {
            if (index == methods.length - 1 ||
                    methods[index + 1].getParameterTypes().length > argsLength) {
                return index;
            } else {
                from = index + 1;
            }
        }
    }
    return -1;
}

确定最特定方法

private static MethodSignature determine(MethodSignature[] overloading, MethodIdentifier id) {
    MethodSignatureDeterminer determiner = new MethodSignatureDeterminer();
    for (int index = maxAcceptIndex(overloading, id); index >= 0; --index) {
        determiner.accept(overloading[index], id);
        if (determiner.getCurrentPhase() == MethodSignatureDeterminer.Phase.FINISH) {
            break;
        }
    }
    return determiner.getMostSpecific();
}


3.根据属性名查找getter方法

虽然可在2的基础上实现这个功能,但是由于getter方法名及参数个数(0)的特殊性,以及getter方法调用频率较高,可作一定优化。

getter方法名:getXxx(普通),isXxx(布尔类型),xxx(布尔类型且属性名类似isXxx)

public class PropertyGetterLookup implements Lookup<ClassNamePair, Method> {
...
    private static List<String> getterNames(String name) {
        StringBuilder buffer = new StringBuilder(3 + name.length());

        buffer.append("get").append(name)
                .setCharAt("get".length(), Character.toUpperCase(name.charAt(0)));
        String get = buffer.toString();

        buffer.setLength(0);
        buffer.append("is").append(name)
                .setCharAt("is".length(), Character.toUpperCase(name.charAt(0)));
        String is = buffer.toString();

        return Arrays.asList(get, is, name);
    }
...
}

查找getter方法并选择

public Method find(ClassNamePair key) {
    return filterAndChoose(key.getClazz().getMethods(), getterNames(key.getName()));
}

private static Method filterAndChoose(Method[] methods, List<String> names) {
    Method getter = null;
    int nameIndex = -1;
    for (Method method : methods) {
        int theIndex = names.indexOf(method.getName());
        if (theIndex >= 0 && method.getParameterTypes().length == 0) {
            if (theIndex == 0) {
                return method;
            } else {
                if (getter == null || theIndex < nameIndex) {
                    getter = method;
                    nameIndex = theIndex;
                }
            }
        }
    }
    return getter;
}


性能提升:

经测试,对FieldLookup,PropertyGetterLookup,OverloadingLookup使用缓存可以较好的提升性能,而对MethodLookup使用缓存性能提升较少,甚至可能出现性能降低的情况。 

通用查找缓存

public class CachedLookup<K, V> implements Lookup<K, V> {
    private final Lookup<K, V> lookup;
    private final Map<K, Future<V>> cache;
    private final ExecutorService executorService;

    public CachedLookup(Lookup<K, V> lookup, Map<K, Future<V>> cache, ExecutorService executorService) {
        this.lookup = lookup;
        this.cache = cache;
        this.executorService = executorService;
    }

    @Override
    public V find(final K key) {
        Future<V> value = cache.get(key);
        if (value == null) {
            synchronized (cache) {
                value = cache.get(key);
                if (value == null) {
                    value = executorService.submit(new Callable<V>() {
                        @Override
                        public V call() throws Exception {
                            return lookup.find(key);
                        }
                    });
                    cache.put(key, value);
                }
            }
        }
        try {
            return value.get();
        } catch (Exception e) {
            return lookup.find(key);
        }
    }
}

简单LRU缓存

public class SimpleLRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int threshold;

    public SimpleLRUCache(int threshold) {
        this(threshold, 0.75f);
    }

    public SimpleLRUCache(int threshold, float loadFactor) {
        super((int) (threshold / loadFactor) + 1, loadFactor, true);
        this.threshold = threshold;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > threshold;
    }
}

 
便捷方法:

public class Fields {
    private static final ExecutorService executorService = Executors.newCachedThreadPool();
    private static final Lookup<ClassNamePair, Field> fieldLookup = buildFieldLookup();
    private static final Lookup<ClassNamePair, Method> propertyGetterLookup = buildPropertyGetterLookup();

    private static Lookup<ClassNamePair, Field> buildFieldLookup() {
        return new CachedLookup<>(
                new FieldLookup(),
                new SimpleLRUCache<ClassNamePair, Future<Field>>(1000),
                executorService
        );
    }

    private static Lookup<ClassNamePair, Method> buildPropertyGetterLookup() {
        return new CachedLookup<>(
                new PropertyGetterLookup(),
                new SimpleLRUCache<ClassNamePair, Future<Method>>(1000),
                executorService
        );
    }

    public static Field getField(Class<?> cls, String name) {
        return fieldLookup.find(new ClassNamePair(cls, name));
    }

    public static Method getGetter(Class<?> cls, String name) {
        return propertyGetterLookup.find(new ClassNamePair(cls, name));
    }

    public static Object get(Object object, String name)
            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Method getter = propertyGetterLookup.find(new ClassNamePair(object.getClass(), name));
        if (getter != null) {
            return getter.invoke(object);
        }
        throw new NoSuchMethodException("Could not find getter for " +
                object.getClass().getName() + "." + name);
    }

    public static void set(Object object, String name, Object... value)
            throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        StringBuilder setter = new StringBuilder("set".length() + name.length());
        setter.append("set").append(name)
                .setCharAt("set".length(), Character.toUpperCase(name.charAt(0)));
        Methods.invoke(object, setter.toString(), value);
    }

    public static Object directGet(Field field, Object object) {
        try {
            if (field.isAccessible()) {
                return field.get(object);
            } else {
                field.setAccessible(true);
                Object value = field.get(object);
                field.setAccessible(false);
                return value;
            }
        } catch (IllegalAccessException e) {
            // should never reach here
            throw new RuntimeException(e);
        }
    }

    public static void directSet(Field field, Object object, Object value) {
        try {
            if (field.isAccessible()) {
                field.set(object, value);
            } else {
                field.setAccessible(true);
                field.set(object, value);
                field.setAccessible(false);
            }
        } catch (IllegalAccessException e) {
            // should never reach here
            throw new RuntimeException(e);
        }
    }
}

public class Methods {
    private static final ExecutorService executorService = Executors.newCachedThreadPool();
    private static final Lookup<MethodIdentifier, Method> methodLookup = buildMethodLookup();

    private static Lookup<MethodIdentifier, Method> buildMethodLookup() {
        return new MethodLookup(buildOverloadingLookup());
    }

    private static Lookup<ClassNamePair, MethodSignature[]> buildOverloadingLookup() {
        return new CachedLookup<>(
                new OverloadingLookup(),
                new SimpleLRUCache<ClassNamePair, Future<MethodSignature[]>>(1000),
                executorService
        );
    }

    private static final Class<?>[] EMPTY_ARGUMENT_TYPES = new Class<?>[0];

    public static Class<?>[] getArgumentTypes(Object... args) {
        if (args.length == 0) {
            return EMPTY_ARGUMENT_TYPES;
        }
        Class<?>[] argTypes = new Class<?>[args.length];
        for (int i = 0; i < args.length; ++i) {
            argTypes[i] = args[i] == null ? null : args[i].getClass();
        }
        return argTypes;
    }

    public static Method getMethod(Class<?> cls, String name, Class<?>... argTypes) {
        return methodLookup.find(new MethodIdentifier(cls, name, argTypes));
    }

    public static Object invoke(Object object, String name, Object... args)
            throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        return invoke(object.getClass(), name, getArgumentTypes(args), object, args);
    }

    public static Object invokeStatic(Class<?> cls, String name, Object... args)
            throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        return invoke(cls, name, getArgumentTypes(args), null, args);
    }

    private static Object invoke(Class<?> cls, String name, Class<?>[] argTypes, Object object, Object... args)
            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Method method = getMethod(cls, name, argTypes);
        if (method != null) {
            return method.invoke(object, args);
        }
        throw new NoSuchMethodException(invokeToString(cls, name, args));
    }

    private static String invokeToString(Class<?> cls, String name, Object... args) {
        StringBuilder buffer = new StringBuilder();
        buffer.append(cls.getName());
        buffer.append('.');
        buffer.append(name);
        buffer.append('(');
        if (args.length > 0) {
            for (Object arg : args) {
                buffer.append(arg).append(',');
            }
            buffer.setLength(buffer.length() - 1);
        }
        buffer.append(')');
        return buffer.toString();
    }
}


简易性能测试:

Reflect Benchmark                                      
os name: Linux
os arch: i386
os version: 3.2.0-24-generic
java version: 1.7.0_02
jvm name: Java HotSpot(TM) Server VM
jvm version: 22.0-b10
arguments:
	-Didea.launcher.port=7532
	-Didea.launcher.bin.path=/home/canghailan/apps/idea-IC-111.69/bin
	-Dfile.encoding=UTF-8
times: 50000000 using: 26s
case                                                             total(ns)  per(ns) ratio    
EMPTY BENCHMARK CASE                                             56362      0       1        
user.getName()                                                   89515916   1       1,588.2  
Fields.get(user, "name")                                         2610483925 52      46,316.4 
Fields.directGet(Fields.getField(user.getClass(), "name"), user) 2948211600 58      52,308.5 
Methods.invoke(user, "getName")                                  5645685285 112     100,168.3
PropertyUtils.getSimpleProperty(user, "name")                    5097645621 101     90,444.7 
PropertyUtils.getProperty(user, "name")                          9721426876 194     172,481.9

 
完整代码:

http://www.oschina.net/code/snippet_116768_10408 

© 著作权归作者所有

canghailan

canghailan

粉丝 28
博文 14
码字总数 10765
作品 0
武汉
程序员
私信 提问
Java反射实践:从反射中理解class

写在前面 今天在需求评审的时候,遇到了挺有意思的要求。需求是什么样子就不说了。总之完成这个需求需要一个调用系统api的操作。然而这个api因为并不稳定的原因。被谷歌hide掉了。 这个时候我...

MDove
2018/04/11
0
0
【免费】全网独家:详解Java反射机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/silencezwm/article/details/85115991 【免费】全网独家:这是一份非常值得珍藏的Android知识体系!!! 本文...

silencezwm
2018/12/20
0
0
最最最常见的Java面试题总结——第二周

String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性   String类中使用字符数组:保存字符串,所以String对象是...

Amsour丶
2018/08/13
0
0
老司机带你深入浅出Java反射

反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言令人意外的活力,通过运行时操作元数据或对象,Java 可以灵活地操作运行时才能确定的信息 这里笔者就深入浅出总结下Java反射,...

小刀爱编程
2018/11/07
0
0
云妹总结了一些最最最常见的Java面试题供大家参考

云妹导读:String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性 String类中使用字符数组:private final cha...

阿里云科技快讯
2018/08/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot配置百度UEditor 富文本详解

富文本简介 UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码... 准备工作 ueditor需要单独文...

wotrd
昨天
1
0
mysql 5.7之my.cnf配置大全

[client]port = 3306socket = /tmp/mysql.sock[mysqld]###############################基础设置######################################Mysql服务的唯一编号 每个mysql服务...

Online_Reus
昨天
2
0
MAVEN打包时引入外部链接的包

1.项目引入了ORACLE的jar包,MAVEN配置如下 2.打jar包的时候需要指定下main入口函数mainClass <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> ......

Cobbage
昨天
1
0
rror: Default interface methods are only supported starting with Android N (--min-api 24): java.io.

项目运行的时候,如果报错 Error: Default interface methods are only supported starting with Android N (--min-api 24): java.io.InputStream org.apache.poi.sl.usermodel.ObjectShape.......

chenhongjiang
昨天
2
0
聊聊spring cloud openfeign的Targeter

序 本文主要研究一下spring cloud openfeign的Targeter Targeter spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/Targeter.java interface Targe......

go4it
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部