Один из способов справиться с этим - загрузить этот список методов во время выполнения в Map
, а затем для каждого вызова использовать Map
. То есть что-то вроде этого (где этот код упрощен и пропускает проверку ошибок):
Map<? extends Object, Method> map;
Method[] methods = Setters.class.getMethods();
for (Method method : methods) {
if (method.getName().equals("setCellValue")) {
map.put(method.getParameterTypes()[0], method);
}
}
затем, когда вы захотите вызвать это, найдите метод в map
по типу аргумента и используйте этот экземпляр.
Чтобы показать это, снова с упрощенным, но на этот раз полным кодом. Обратите внимание, что, чтобы быть полностью общим, код становится немного более сложным, как показано ниже. Если вам не нужно беспокоиться о примитивах (что зависит от вашего использования) или если вам не нужно беспокоиться об интерфейсах или суперклассах, то вы можете упростить приведенный ниже пример.
Кроме того, если вы можете гарантировать, что не будет перекрытия в интерфейсах или суперклассах в аргументах, о которых вам нужно беспокоиться, вы можете переместить всю сложную логику в инициализацию (что не имеет значения, если это займет 1 мс больше). В этом случае вся логика в findMethodToInvoke()
будет перемещена в конструктор, где вы будете циклически перебирать все интерфейсы и суперклассы каждого найденного вами метода и добавлять их в ваш параметрTypeMap. Если вы выполните эту оптимизацию, findMethodToInvoke()
станет одной строкой:
return parameterTypeMap.get(test.getClass());
но без этой оптимизации и с полным обобщением, вот мой пример того, как это сделать:
import java.lang.reflect.*;
import java.util.*;
public class Test {
private final Map<Object, Method> parameterTypeMap = new HashMap<Object, Method>();
private final Object[] tests = {Double.valueOf(3.1415),
Boolean.TRUE,
new Date(),
new GregorianCalendar(),
new HashMap<Object, Object>()};
public Test() {
Method[] methods = Setters.class.getMethods();
for (Method method : methods) {
if (method.getName().equals("setCellValue")) {
Class<?>[] clazzes = method.getParameterTypes();
if (clazzes.length != 1) {
continue;
}
if (clazzes[0].isPrimitive()) {
handlePrimitive(method, clazzes[0]);
}
parameterTypeMap.put(clazzes[0], method);
}
}
}
// See http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isPrimitive()
private void handlePrimitive(Method method, Class<?> clazz) {
if (clazz == Boolean.TYPE) {
parameterTypeMap.put(Boolean.class, method);
} else if (clazz == Double.TYPE) {
parameterTypeMap.put(Double.class, method);
} // ... and so on for the other six primitive types (void doesn't matter)
}
public void doTests(Setters setter) {
for (Object test : tests) {
Method method = findMethodToInvoke(test);
if (method == null) {
System.out.println("Nothing found for " + test.getClass());
continue;
}
try {
method.invoke(setter, test);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private Method findMethodToInvoke(Object test) {
Method method = parameterTypeMap.get(test.getClass());
if (method != null) {
return method;
}
// Look for superclasses
Class<?> x = test.getClass().getSuperclass();
while (x != null && x != Object.class) {
method = parameterTypeMap.get(x);
if (method != null) {
return method;
}
x = x.getSuperclass();
}
// Look for interfaces
for (Class<?> i : test.getClass().getInterfaces()) {
method = parameterTypeMap.get(i);
if (method != null) {
return method;
}
}
return null;
}
public static void main(String[] args) {
Test test = new Test();
test.doTests(new Setters());
}
}
class Setters {
public void setCellValue(boolean value) {
System.out.println("boolean " + value);
}
public void setCellValue(double value) {
System.out.println("double " + value);
}
public void setCellValue(Calendar value) {
System.out.println("Calendar " + value);
}
public void setCellValue(Date value) {
System.out.println("Date " + value);
}
public void setCellValue(Map<?, ?> value) {
System.out.println("Map " + value);
}
}