属性存取,方法调用是最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