介绍
实际开发中经常用到将字符串转换为函数,以实现class的插件式操作,即调用时不绑定class的具体方法,运行时才绑定。在python中可以通过getattr()实现字符串和函数的转换。Java是通过反射机制来实现,通过getMethod()获取指定类的method,利用method.invoke()方法实现方法的执行获取结果。
反射机制
编译时不获取.class文件(或者获取不到.class文件),运行时才打开和检查.class文件。
Java反射常用的方法有
- getFields() 获取定义的成员变量,包括父类的成员变量
- getMethods() 获取全部的方法,包括父类的方法
- getAnnotations() 获取注解,包括父类的注解
- Method的invoke()方法
- getDeclaredMethods() 获取声明的方法
- getDeclaredField() 获取声明的成员变量
- getDeclaredAnnotations() 获取注解
字符串转换为函数
具体操作类
接下来我们利用Java的反射机制实现字符串和函数的转换并执行。首先定义用于实现的类,以四则运算为例,代码如下:
package com.notepad.thinkingnote.reflect;
/**
* Description: 四则运算实现
* <p>
* Create: 2018/8/12 20:39
*
* @author Yang Meng(eyangmeng@163.com)
*/
public class CalculateNode {
public static int add(int v1, int v2) {
return v1 + v2;
}
public static int minus(int v1, int v2) {
return v1 - v2;
}
}
反射类
定义一个反射类,封装一些方便使用的方法。如根据类名和方法名获取对应的方法。
package com.notepad.thinkingnote.reflect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Description: Java反射方法
* <p>
* Create: 2018/8/12 20:25
*
* @author Yang Meng(eyangmeng@163.com)
*/
public class ReflectNote {
public static List getMethods(String className) {
try {
Class<?> c = Class.forName(className);
Method [] methods = c.getMethods();
for (Method m : methods) {
System.out.println(m.getName());
}
return Arrays.asList(methods);
} catch (ClassNotFoundException e) {
LOG.warn("can not find class: {}", className);
return null;
}
}
public static List<String> getDeclaredMethodsName(String className) {
try {
List<String> methodNames = new ArrayList<>();
Class<?> c = Class.forName(className);
Method [] methods = c.getDeclaredMethods();
for (Method m : methods) {
methodNames.add(m.getName());
}
return methodNames;
} catch (ClassNotFoundException e) {
LOG.warn("can not find class: {}", className);
return null;
}
}
/**
* 根据类名和方法名获取对应的方法
*
* @param name 类名
* @param method 方法名
* @return a Method, null 找不到
*/
public static Method getMethod(String name, String method) {
try {
Class<?> c = Class.forName(name);
for (Method m : c.getDeclaredMethods()) {
if (m.getName().equals(method)) {
return m;
}
}
return null;
} catch (ClassNotFoundException e) {
LOG.warn("can not find class: {}", name);
return null;
}
}
/**
* 根据类名和方法名获取对应的方法
*
* @param cls 类
* @param method 方法名
* @return a Method, null 找不到
*/
public static Method getMethod(Class<?> cls, String method) {
for (Method m : cls.getDeclaredMethods()) {
if (m.getName().equals(method)) {
return m;
}
}
return null;
}
private static final Logger LOG = LoggerFactory.getLogger(ReflectNote.class);
}
测试
字符串转换为函数的示例见 单测3:testReflect()
package com.notepad.thinkingnote.reflect;
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Method;
/**
* Description:
* <p>
* Create: 2018/8/12 20:33
*
* @author Yang Meng(eyangmeng@163.com)
*/
public class ReflectNoteTest {
@Test
public void testGetMethods() throws Exception {
String name = "com.notepad.thinkingnote.reflect.CalculateNode";
System.out.println(ReflectNote.getMethods(name));
}
@Test
public void testGetDeclaredMethod() throws Exception {
String name = "com.notepad.thinkingnote.reflect.CalculateNode";
System.out.println(ReflectNote.getDeclaredMethodsName(name));
}
/**
* 字符串转换为函数并执行
*
* @throws Exception 处理异常
*/
@Test
public void testReflect() throws Exception {
String name = "com.notepad.thinkingnote.reflect.CalculateNode";
String v1 = "20";
String v2 = "10";
// add
String methodName = "add";
Method m = ReflectNote.getMethod(name, methodName);
assert m != null;
Assert.assertEquals(m.getName(), methodName);
System.out.println(m);
int v = (int)m.invoke(CalculateNode.class, Integer.valueOf(v1), Integer.valueOf(v2));
System.out.println(String.format("%s %s %s = %s", v1, methodName, v2, v));
// 直接获取方法
Method method = CalculateNode.class.getDeclaredMethod(methodName, int.class, int.class);
assert method != null;
int value = (int)method.invoke(CalculateNode.class, Integer.valueOf(v1), Integer.valueOf(v2));
System.out.println(String.format("direct %s %s %s = %s", v1, methodName, v2, value));
// minus
methodName = "minus";
Method m2 = ReflectNote.getMethod(CalculateNode.class, methodName);
int minusValue = (int) m2.invoke(CalculateNode.class, Integer.valueOf(v1), Integer.valueOf(v2));
System.out.println(String.format("%s %s %s = %s", v1, methodName, v2, minusValue));
}
}
总结
通过本文我们利用Java反射机制实现字符串和函数的转换并执行。
参数
Java编程思想 类型信息