欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java反射,,Methods.java

来源: javaer 分享于  点击 39941 次 点评:106

Java反射,,Methods.java


Methods.java

package canghailan.lang.reflect;import canghailan.util.CachedLookup;import canghailan.util.Lookup;import canghailan.util.SimpleLRUCache;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * @author canghailan 2012-04-10 21:03 */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();    }}

Fields.java

package canghailan.lang.reflect;import canghailan.util.CachedLookup;import canghailan.util.Lookup;import canghailan.util.SimpleLRUCache;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * @author canghailan 2012-04-10 21:03 */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);        }    }}

FieldLookup.java

package canghailan.lang.reflect;import canghailan.util.Lookup;import java.lang.reflect.Field;/** * @author canghailan 2012-02-23 20:31 */public class FieldLookup implements Lookup<ClassNamePair, Field> {    @Override    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;    }    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;    }}

MethodLookup.java

package canghailan.lang.reflect;import canghailan.util.Lookup;import java.lang.reflect.Method;/** * @author canghailan 2012-04-19 22:21 */public class MethodLookup implements Lookup<MethodIdentifier, Method> {    private final Lookup<ClassNamePair, MethodSignature[]> overloadingLookup;    public MethodLookup(Lookup<ClassNamePair, MethodSignature[]> overloadingLookup) {        this.overloadingLookup = overloadingLookup;    }    @Override    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()));    }    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();    }    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;    }}

OverloadingLookup.java

package canghailan.lang.reflect;import canghailan.util.Lookup;import java.lang.reflect.Method;import java.util.Arrays;import java.util.Comparator;import java.util.LinkedList;import java.util.List;/** * overloading methods and sorted by parameter length * * @author canghailan 2012-04-10 21:02 */public class OverloadingLookup implements Lookup<ClassNamePair, MethodSignature[]> {    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;                    }                }            };    @Override    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()]);    }    private static MethodSignature[] sort(MethodSignature[] overloadingMethods) {        Arrays.sort(overloadingMethods, PARAM_LENGTH_COMPARATOR);        return overloadingMethods;    }}

PropertyGetterLookup.java

package canghailan.lang.reflect;import canghailan.util.Lookup;import java.lang.reflect.Method;import java.util.Arrays;import java.util.List;/** * @author canghailan 2012-04-10 20:19 */public class PropertyGetterLookup implements Lookup<ClassNamePair, Method> {    @Override    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;    }    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);    }}

Lookup.java

package canghailan.util;/** * @author canghailan 2012-04-10 18:34 */public interface Lookup<K, V> {    V find(K key);}

ClassNamePair.java

package canghailan.lang.reflect;/** * @author canghailan 2012-04-10 19:54 */public class ClassNamePair {    private final Class<?> clazz;    private final String name;    public ClassNamePair(Class<?> clazz, String name) {        assert clazz != null;        assert name != null;        this.clazz = clazz;        this.name = name;    }    public Class<?> getClazz() {        return clazz;    }    public String getName() {        return name;    }    @Override    public boolean equals(Object o) {        if (this == o) {            return true;        }        if (o == null || getClass() != o.getClass()) {            return false;        }        ClassNamePair that = (ClassNamePair) o;        return clazz == that.clazz && name.equals(that.name);    }    @Override    public int hashCode() {        return clazz.hashCode() * 31 + name.hashCode();    }}

MethodIdentifier.java

package canghailan.lang.reflect;import java.util.Arrays;/** * @author canghailan 2012-04-19 22:19 */public class MethodIdentifier {    private final Class<?> clazz;    private final String name;    private final Class<?>[] argumentTypes;    public MethodIdentifier(Class<?> clazz, String name, Class<?>[] argumentTypes) {        this.clazz = clazz;        this.name = name;        this.argumentTypes = argumentTypes;    }    public Class<?> getClazz() {        return clazz;    }    public String getName() {        return name;    }    public Class<?>[] getArgumentTypes() {        return argumentTypes;    }    @Override    public String toString() {        return Arrays.toString(argumentTypes);    }}

MethodSignature.java

package canghailan.lang.reflect;import java.lang.reflect.Method;/** * @author canghailan 2012-04-19 20:03 */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 Method getMethod() {        return method;    }    public Class<?>[] getParameterTypes() {        return parameterTypes;    }    public boolean isVarArgs() {        return varArgType != null;    }    public Class<?> getVarArgType() {        return varArgType;    }    @Override    public String toString() {        return method.toString();    }}

MethodInvocationConversion.java

package canghailan.lang.reflect;/** * @author canghailan 2012-04-21 22:54 */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;    }}

MethodSignatureDeterminer.java

package canghailan.lang.reflect;import static canghailan.lang.reflect.MethodInvocationConversion.*;/** * @author canghailan 2012-04-21 21:47 */public class MethodSignatureDeterminer {    private Phase currentPhase;    private MethodSignature mostSpecific;    public MethodSignatureDeterminer() {        this.currentPhase = Phase.START;    }    public Phase getCurrentPhase() {        return currentPhase;    }    public MethodSignature getMostSpecific() {        return mostSpecific;    }    public void accept(MethodSignature signature, MethodIdentifier id) {//        Phase bp = currentPhase;//        MethodSignature bms = mostSpecific;        currentPhase.accept(this, signature, id);//        Phase ap = currentPhase;//        MethodSignature ams = mostSpecific;//        System.out.print("accept: " + signature.getMethod());//        System.out.println(" <= (" + id + ")");//        System.out.println(bms + " => " + ams);//        System.out.println(bp + " => " + ap);//        System.out.println();    }    /**     * <ul>     * <li>Phase 1: Identify Matching Arity Methods Applicable by Subtyping</li>     * <li>Phase 2: Identify Matching Arity Methods Applicable by Method Invocation Conversion</li>     * <li>Phase 3: Identify Applicable Variable Arity Methods</li>     * </ul>     */    public static enum Phase {        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            }        };        abstract void accept(MethodSignatureDeterminer determiner,                             MethodSignature signature, MethodIdentifier id);    }    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;    }    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;        }    }    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;        }    }    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;    }    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;        }    }}

CachedLookup.java

package canghailan.util;import java.util.Map;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Future;/** * @author canghailan 2012-03-12 18:57 */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);        }    }}

SimpleLRUCache.java

package canghailan.util;import java.util.LinkedHashMap;import java.util.Map;/** * @author canghailan 2012-04-18 18:09 */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;    }}
相关栏目:

用户点评