Java读取文本文件方法调用报NoSuchMethodException如何解决
报错根因
Class.getMethod()方法的合法入参是「目标类的方法名」+「方法形参类型列表」,不支持直接传入完整链式调用表达式。你把t.getP().getName()整串作为方法名传入,JVM会直接在Test类下找名为t.getP().getName()的无参方法,自然匹配不到,抛出NoSuchMethodException。
实现方案
根据场景复杂度选以下两种方案即可:
方案1:手动拆分链式调用反射执行(无额外依赖,适配简单getter场景)
核心逻辑是按.拆分每一行的调用链,逐段反射执行方法,上一段的返回值作为下一段调用的实例对象,直到走完整个链路。
实现代码如下:
import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; public class Test { private Person p; public Test(){ p = new Person("Jhon", "19", "New York", "Mathematician"); } public Person getP() { return p; } // 链式无参方法执行工具 private static Object execChain(Object rootInstance, String express) throws Exception { Object current = rootInstance; String[] nodes = express.split("\\."); for (String node : nodes) { String trimNode = node.trim(); // 跳过根变量名t,初始实例已经传入 if ("t".equals(trimNode)) continue; // 提取方法名,去掉末尾括号 String methodName = trimNode.replace("()", ""); // 查找当前对象所属类的无参方法 Method method = current.getClass().getMethod(methodName); // 执行方法,返回值作为下一轮调用的实例 current = method.invoke(current); } return current; } public static void main(String[] args) throws Exception { Test t = new Test(); // 读取Commands.txt文件 List<String> allLines = Files.readAllLines(Paths.get("Commands.txt")); List<String> validExprs = new ArrayList<>(); // 过滤无效行:大括号、空行 for (String line : allLines) { String trimLine = line.trim(); if (trimLine.isEmpty() || trimLine.equals("{") || trimLine.equals("}")) continue; validExprs.add(trimLine); } // 逐行执行并打印结果 for (String expr : validExprs) { Object result = execChain(t, expr); System.out.printf("执行语句[%s],返回结果:%s%n", expr, result); } } }
方案2:JDK脚本引擎直接执行表达式(适配复杂语句场景)
JDK8-14内置Nashorn JavaScript引擎,可以直接绑定Java对象执行链式表达式,不需要手动解析反射链路,代码更简洁。高版本JDK可单独引入Nashorn依赖使用。
核心实现代码如下:
import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.SimpleBindings; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; public class Test { private Person p; public Test(){ p = new Person("Jhon", "19", "New York", "Mathematician"); } public Person getP() { return p; } public static void main(String[] args) throws Exception { Test t = new Test(); // 初始化脚本引擎 ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); SimpleBindings bindings = new SimpleBindings(); // 把t对象绑定到脚本上下文 bindings.put("t", t); // 读取过滤文件逻辑和方案1一致 List<String> allLines = Files.readAllLines(Paths.get("Commands.txt")); for (String line : allLines) { String trimLine = line.trim(); if (trimLine.isEmpty() || trimLine.equals("{") || trimLine.equals("}")) continue; Object result = engine.eval(trimLine, bindings); System.out.printf("执行语句[%s],返回结果:%s%n", trimLine, result); } } }
注意事项
- 方案1的简易实现仅适配示例中的无参getter场景,如果需要支持带参数方法、字段访问,需要补充表达式解析、参数类型匹配逻辑
- 确保调用链上的所有类都实现了对应方法,比如Person类要存在
getName()、getAge()、getLocation()三个无参方法,否则仍会抛出方法不存在异常 - 动态执行外部文件传入的代码存在安全风险,禁止在生产环境执行来源不可信的语句,避免恶意代码注入
- JDK15及以上版本移除了内置Nashorn引擎,使用方案2需要手动引入
org.openjdk.nashorn:nashorn-core依赖
内容的提问来源于stack exchange,提问作者Brian
相关产品推荐
相关产品推荐

