我正在尝试读取一个java文件,并在控制台中显示包,类和方法名称。像这样的东西:
文件:Test.java
package tspec.test;
public class Test {
public void addTest () {}
public void deleteTest () {}
}
输出:
package name: tspec.test
class name: Test
method name:
addTest
deleteTest
提前致谢:)
答案 0 :(得分:6)
这可以使用Java Compiler API(在Java 6中引入)来完成。不幸的是,这个解决方案仅限于Sun的JDK。因此,您必须安装和 JDK,您必须在类路径中包含其tools.jar
文件。
public void displayInformation(File javaSourceFile) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// The file manager locates your Java source file for the compiler. Null arguments indicate I am comfortable with its default behavior.
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
// These will be parsed by the compiler
Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(javaSourceFile);
// Creates a new compilation task. This doesn't actually start the compilation process.
// Null arguments indicate I am comfortable with its default behavior.
CompilationTask task = compiler.getTask(null, null, null, null, null, fileObjects);
// Cast to the Sun-specific CompilationTask.
com.sun.tools.javac.api.JavacTaskImpl javacTask = (com.sun.tools.javac.api.JavacTaskImpl) task;
// The Sun-specific JavacTaskImpl can parse the source file without compiling it, returning
// one CompilationUnitTree for each JavaFileObject given to the compiler.getTask call (only one in our case).
Iterable<? extends CompilationUnitTree> trees = javacTask.parse();
CompilationUnitTree tree = trees.iterator().next();
// Create a class that implements the com.sun.source.tree.TreeVisitor interface.
// The com.sun.source.util.TreeScanner is a good choice because it already implements most of the logic.
// We just override the methods we're interested in.
class MyTreeVisitor extends TreeScanner<Void, Void> {
@Override
public Void visitClass(ClassTree classTree, Void p) {
System.out.println("class name: " + classTree.getSimpleName());
System.out.println("method name:");
return super.visitClass(classTree, p);
}
@Override
public Void visitMethod(MethodTree methodTree, Void p) {
System.out.println(methodTree.getName());
return super.visitMethod(methodTree, p);
}
}
tree.accept(new MyTreeVisitor(), null);
}
当我传递此方法的内容为您的样本的File
时,我收到此输出:
class name: Test method name: addTest deleteTest
不幸的是,我还没弄清楚包名的存储位置。
答案 1 :(得分:3)
它的目的是内省Java代码并报告它的内容。使用Reflection,您可以执行以下操作:
Class.forName(className).getDeclaredMethods();
这两种解决方案都不需要第三方库或工具。
答案 2 :(得分:0)
唯一的困难是java代码可能格式不正确。就像函数声明可以在多行上传播一样。
最终的解决方案是创建一个自动机来首先对源代码进行标记,然后应用一些编译器技术从解析的数据中获取您想要的内容。
答案 3 :(得分:0)
我们使用PMD Java代码分析器来解决类似的问题。 这很有用。
答案 4 :(得分:0)
您不必通过自己解析Java文件来完成此操作! Java已经包含一种获取有关其自己的类,方法和包的信息的方法:它被称为reflection。
查看java.lang.Class课程。此类的每个实例都代表一个特定的Java类,并包含返回类名,它所在的包,它包含的方法以及更多信息的方法。
另外值得一看的是java.lang.reflect包,因为Class
的某些方法会从此包中返回类型。该包包含用于表示方法,类型,字段等内容的类。
要获取Class
类的Test
实例,可以使用以下代码:
Class<?> testclass = Class.forName("tspec.test.Test");
这将返回一个未知类型的类,如果您不熟悉泛型,则尖括号内的问号意味着什么。为什么类实例的类型未知是因为您使用字符串指定类名,该字符串在运行时进行解析。在编译时,Java无法确定传递给forName
的字符串是否甚至代表了一个有效的类。
但是,如上所定义的testclass
可以用于获取类的名称,方法和包含。