协作翻译|五分钟理解Java的反射API
像java一样,一种具有反射功能的语言;允许开发人员在运行时检查类型、方法、字段、注解等,并在程序运行时决定是否使用。 为此,Java的反射API提供类,类,字段,构造函数,方法,注释和其他。 使用它们可以与编译时未知的类型进行交互,例如创建未知类的实例并对它们调用方法。
这个快速提示旨在让您深度了解什么是反射,它在Java中的使用,以及它可以用于什么。 之后,你将准备好开始或工作更长的教程。 为了充分使用它,你应该很好地理解Java的类构造器,特别是什么类和方法以及它们如何关联。 了解注释可解锁单独的部分。
反射API
我们从一个简单的Java代码开始(代码针对有一定java基础的阅读人员)
URLurl=newURL("https://sitepoint.com/java");
String urlString = url.toExternalForm();
System.out.println(urlString);
我决定在编译时间(意味着,当我在写代码时)我想创建一个URL对象,并且调用了其中的一些方法。下面演示了我使用Java的反射API完成同样的事情:
使用反射API当然比直接写代码更麻烦。 但是这种方式, 以前被用来部署代码 (就像我使用URL或我调用的方法) 是使用的一个参数。 因此,不是必须在编译时解决URL和toExternalForm,它们可以在程序运行时决定。
大多数使用情况发生在“框架”环境中。 想想JUnit,例如,想要执行用@Test注释的所有方法。 一旦它发现@Test注释与类路径扫描,它使用getMethod和invoke调用它们。 Spring和其他Web框架在寻找控制器和请求映射时的行为类似。 另一个用例是在运行时加载用户提供的插件的可扩展应用程序。
基本类型和方法
调用反射API的方法是Class :: forName。 在它的简单形式中,这个静态方法只需要一个完全限定的类名,并为它返回一个Class实例。 该实例可用于获取字段,方法,构造函数等。
通过构造器函数获取类对象,getConstructor方法可以使用构造函数参数的类型调用,就像我上面做的那样。 类似地,可以通过调用getMethod并传递其名称以及参数类型来访问特定方法。上面的getMethod(“toExternalForm”)调用没有指定任何类型,因为该方法没有参数。
这里有一个方法:
Class<?> type = Class.forName("java.net.URL");
// `URL::openConnection` has an overload that accepts a java.net.Proxy
Method openConnection = type.getMethod("openConnection", Proxy.class);
继续openConnection示例:
openConnection.invoke(instance, someProxy);
如果要调用静态方法,则将忽略实例参数,因此可以为null。
注解
注解是反射的重要组成部分。 事实上,注解主要针对反射。 它们旨在提供程序运行时访问的元信息,然后用于塑造程序的行为。 (如上所述,JUnit的@Test和Spring的@Controller和@RequestMapping是很好的例子。)
所有重要的反射相关类型,如类,字段,构造函数,方法和参数实现AnnotatedElement接口。 链接的Javadoc包含了注释如何与这些元素(直接呈现,间接呈现或关联)相关的详细解释,但是它最简单的形式是:getAnnotations方法以注释实例数组的形式返回该元素上存在的注释 ,然后可以访问其成员。
总结
Java的反射API允许在运行时对类型,方法,注释等进行自省,并调用在编译时未知的构造函数和方法。 使用时,请调用Class.forName(“fully.qualified.class.Name”),然后调用getConstructors,getMethods,getAnnotations或类似方法。 调用发生与newInstance的构造函数和调用方法。
你也可以使用反射分解代码和突变非公共字段或调用非公共方法 - 这是一个冒险的做法,而且在Java 9中变得更加困难。如果你好奇,并希望 知道所有的API的细节,在Java的官方文档中给出反射详细信息。 到目前为止,API有点过时,有一些缺点,但更新的选择存在,检查方法句柄(自Java 7)和变量句柄(自Java 9)