企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### [类方法提取器](https://lingcoder.gitee.io/onjava8/#/book/19-Type-Information?id=%e7%b1%bb%e6%96%b9%e6%b3%95%e6%8f%90%e5%8f%96%e5%99%a8) 通常,你不会直接使用反射工具,但它们可以帮助你创建更多的动态代码。反射是用来支持其他 Java 特性的,例如对象序列化(参见[附录:对象序列化](https://lingcoder.github.io/OnJava8/#/book/Appendix-Object-Serialization))。但是,有时动态提取有关类的信息很有用。 考虑一个类方法提取器。查看类定义的源代码或 JDK 文档,只显示*在该类定义中*定义或重写的方法。但是,可能还有几十个来自基类的可用方法。找到它们既单调又费时\[^1\]。幸运的是,反射提供了一种方法,可以简单地编写一个工具类自动地向你展示所有的接口: ~~~ // typeinfo/ShowMethods.java // 使用反射展示一个类的所有方法,甚至包括定义在基类中方法 // {java ShowMethods ShowMethods} import java.lang.reflect.*; import java.util.regex.*; public class ShowMethods { private static String usage = "usage:\n" + "ShowMethods qualified.class.name\n" + "To show all methods in class or:\n" + "ShowMethods qualified.class.name word\n" + "To search for methods involving 'word'"; private static Pattern p = Pattern.compile("\\w+\\."); public static void main(String[] args) { if (args.length < 1) { System.out.println(usage); System.exit(0); } int lines = 0; try { Class<?> c = Class.forName(args[0]); Method[] methods = c.getMethods(); Constructor[] ctors = c.getConstructors(); if (args.length == 1) { for (Method method : methods) System.out.println( p.matcher( method.toString()).replaceAll("")); for (Constructor ctor : ctors) System.out.println( p.matcher(ctor.toString()).replaceAll("")); lines = methods.length + ctors.length; } else { for (Method method : methods) if (method.toString().contains(args[1])) { System.out.println(p.matcher( method.toString()).replaceAll("")); lines++; } for (Constructor ctor : ctors) if (ctor.toString().contains(args[1])) { System.out.println(p.matcher( ctor.toString()).replaceAll("")); lines++; } } } catch (ClassNotFoundException e) { System.out.println("No such class: " + e); } } } ~~~ 输出结果: ~~~ public static void main(String[]) public final void wait() throws InterruptedException public final void wait(long,int) throws InterruptedException public final native void wait(long) throws InterruptedException public boolean equals(Object) public String toString() public native int hashCode() public final native Class getClass() public final native void notify() public final native void notifyAll() public ShowMethods() ~~~ `Class`方法`getmethods()`和`getconstructors()`分别返回`Method`数组和`Constructor`数组。这些类中的每一个都有进一步的方法来解析它们所表示的方法的名称、参数和返回值。但你也可以像这里所做的那样,使用`toString()`,生成带有整个方法签名的`String`。代码的其余部分提取命令行信息,确定特定签名是否与目标`String`(使用`indexOf()`)匹配,并使用正则表达式(在[Strings](https://lingcoder.gitee.io/onjava8/#/book/19-Type-Informationstrings)一章中介绍)删除名称限定符。 编译时无法知道`Class.forName()`生成的结果,因此所有方法签名信息都是在运行时提取的。如果你研究 JDK 反射文档,你将看到有足够的支持来实际设置和对编译时完全未知的对象进行方法调用(本书后面有这样的例子)。虽然最初你可能认为你永远都不需要这样做,但是反射的全部价值可能会令人惊讶。 上面的输出来自命令行: ~~~ java ShowMethods ShowMethods ~~~ 输出包含一个`public`无参数构造函数,即使未定义构造函数。你看到的构造函数是由编译器自动合成的。如果将`ShowMethods`设置为非`public`类(即只有包级访问权),则合成的无参数构造函数将不再显示在输出中。自动为合成的无参数构造函数授予与类相同的访问权。 尝试运行`java ShowMethods java.lang.String`,并附加一个`char`、`int`、`String`等参数。 编程时,当你不记得某个类是否有特定的方法,并且不想在 JDK 文档中搜索索引或类层次结构时,或者如果你不知道该类是否可以对`Color`对象执行任何操作时,该工具能节省不少时间。