如何动态执行含方法调用的字符串中的方法?(尽量不使用反射)
动态执行字符串中的嵌套方法调用(优先非反射方案)
嘿,这个需求我懂,就是想把字符串里写的方法调用动态跑起来,还不想用反射对吧?咱直接上实用方案,分两种情况给你参考:
方案一:用Java ScriptEngine(无反射,支持复杂嵌套)
Java自带的脚本引擎可以帮你搞定这个事儿——把你的类对象暴露给脚本引擎,然后把字符串转成脚本调用的形式,让引擎帮你解析执行。这个方案不用自己写嵌套解析逻辑,对复杂的方法嵌套也友好。
举个代码例子,假设你的类里有first和second方法:
import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class MethodRunner { // 你的自定义方法 public String first(String s) { return "processed_" + s; } public String second(String s) { return "final_" + s; } public static void main(String[] args) throws ScriptException { MethodRunner runner = new MethodRunner(); String targetExpr = "second(first(\"string1\"))"; // 获取JavaScript引擎(Java 8用Nashorn,Java 11+可以用GraalVM的JS引擎) ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // 把当前对象绑定到脚本环境,给个名字比如"obj" engine.put("obj", runner); // 把表达式里的方法调用改成脚本能识别的"obj.method()"形式 String script = targetExpr.replaceAll("(\\w+)\\(", "obj.$1("); // 执行脚本拿结果 Object result = engine.eval(script); System.out.println(result); // 输出:final_processed_string1 } }
优点:不用自己处理嵌套解析,支持多层方法调用,甚至可以扩展支持更复杂的表达式;注意:Java 8之后Nashorn引擎被标记为Deprecated,要是用Java 11+,建议引入GraalVM的JavaScript引擎依赖。
方案二:自定义简易解析器(完全无外部依赖,轻量可控)
如果你的方法调用格式比较规整(比如都是单参数字符串、嵌套结构不复杂),可以自己写个小解析器,用栈来处理嵌套调用,完全不用反射也不用脚本引擎。
核心思路是:用栈记录方法名,用另一个栈记录参数/中间结果,遇到闭合括号时就弹出方法和参数,执行对应的方法,再把结果压回参数栈给上层方法用。
代码示例:
import java.util.Deque; import java.util.LinkedList; import java.util.Map; import java.util.function.Function; public class CustomMethodExecutor { // 把方法名和对应的实现映射起来,用Function接口更灵活 private static final Map<String, Function<String, String>> METHOD_HANDLERS = Map.of( "first", input -> "processed_" + input, "second", input -> "final_" + input ); public static String execute(String expression) { Deque<String> methodStack = new LinkedList<>(); Deque<String> paramStack = new LinkedList<>(); int idx = 0; int len = expression.length(); while (idx < len) { char currentChar = expression.charAt(idx); if (Character.isLetter(currentChar)) { // 解析方法名 StringBuilder methodName = new StringBuilder(); while (idx < len && Character.isLetter(expression.charAt(idx))) { methodName.append(expression.charAt(idx++)); } methodStack.push(methodName.toString()); idx++; // 跳过左括号'(' } else if (currentChar == '"') { // 解析字符串参数 StringBuilder param = new StringBuilder(); idx++; // 跳过开头的双引号 while (idx < len && expression.charAt(idx) != '"') { param.append(expression.charAt(idx++)); } paramStack.push(param.toString()); idx++; // 跳过结尾的双引号 } else if (currentChar == ')') { // 执行方法调用 String param = paramStack.pop(); String methodName = methodStack.pop(); Function<String, String> handler = METHOD_HANDLERS.get(methodName); if (handler == null) { throw new IllegalArgumentException("找不到方法:" + methodName); } String result = handler.apply(param); // 如果还有上层方法,把结果作为参数压栈 if (!methodStack.isEmpty()) { paramStack.push(result); } else { return result; // 没有上层方法了,返回最终结果 } idx++; } else { idx++; // 跳过其他无关字符(比如空格,这里假设输入没有多余空格) } } throw new IllegalArgumentException("表达式格式不对哦"); } public static void main(String[] args) { String targetExpr = "second(first(\"string1\"))"; String result = execute(targetExpr); System.out.println(result); // 输出:final_processed_string1 } }
优点:完全轻量,不依赖任何外部库或引擎,你自己能完全控制解析逻辑;缺点:只适合特定格式的方法调用,如果要支持多参数、不同类型参数或者更复杂的表达式,就得扩展解析逻辑了。
内容的提问来源于stack exchange,提问作者Shivanshu Bagga
相关产品推荐
相关产品推荐

