什么是反思,为什么它有用?

我对Java特别感兴趣,但我认为任何语言的原理都是一样的。


当前回答

我使用反射基于类名(String中的类名)创建一个对象,并调用该类的方法

Object obj = Class.forName(config.getClassPath())
                    .getDeclaredConstructor()
                    .newInstance();
Method method = obj.getClass().getMethod("getCustomer", SearchObject.class, ObjectConfig.class,
                HttpServletRequest.class);
method.invoke(obj, searchObject, config, request);

但一个主要问题是,如果您在该类上自动连线了某个对象,则该对象将被重新初始化为null

其他回答

反射是允许应用程序或框架处理可能尚未编写的代码的关键机制!

以典型的web.xml文件为例。这将包含一个servlet元素列表,其中包含嵌套的servlet类元素。servlet容器将处理web.xml文件,并通过反射创建每个servlet类的新实例。

另一个例子是Java API for XML Parsing(JAXP)。其中,XML解析器提供程序是通过众所周知的系统财产“插入”的,这些属性用于通过反射构造新实例。

最后,最全面的例子是Spring,它使用反射创建bean,并大量使用代理

反射有很多用途。我更熟悉的是能够动态创建代码。

IE:基于任何数据的动态类、函数、构造函数(xml/array/sql results/hardcoded/etc.)

重要的

从Java9开始,您不能再使用反射,除非package-info.Java打开模块以进行反射访问。

默认情况下,拒绝对模块中的所有包进行“反射”访问。

请参阅了解Java 9模块

名称反射用于描述能够检查同一系统(或其本身)中其他代码的代码。

例如,假设您在Java中有一个未知类型的对象,如果存在,您希望对其调用“doSomething”方法。Java的静态类型系统并不是为了支持这一点而设计的,除非对象符合已知的接口,但是使用反射,您的代码可以查看对象并找出它是否有一个名为“doSomething”的方法,如果需要,可以调用它。

因此,给您一个Java代码示例(假设所讨论的对象是foo):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Java中一个非常常见的用例是注释的用法。例如,JUnit4将使用反射在类中查找标记有@Test注释的方法,然后在运行单元测试时调用它们。

有一些很好的反思示例可以帮助您开始http://docs.oracle.com/javase/tutorial/reflect/index.html

最后,是的,这些概念在其他支持反射的静态类型语言(如C#)中非常相似。在动态类型语言中,上面描述的用例不太必要(因为编译器将允许在任何对象上调用任何方法,如果不存在,则在运行时失败),但是第二种情况仍然很常见,即查找被标记或以某种方式工作的方法。

从评论更新:

检查系统中的代码并查看对象类型的能力是不是反思,而是类型反思。反射就是能够在运行时通过使用反省在某些语言中,这种区别是必要的支持内省,但不支持反思。一个这样的例子是C++

我想举个例子来回答这个问题。首先,Hibernate项目使用反射API生成CRUD语句,以弥合运行应用程序和持久性存储之间的鸿沟。当域中的情况发生变化时,Hibernate必须了解这些情况,才能将其持久化到数据存储中,反之亦然。

另外,Lombok项目也可以。它只是在编译时注入代码,导致代码被插入到域类中。(我认为这对getter和setter来说是可以的)

Hibernate选择反射是因为它对应用程序的构建过程影响最小。

在Java7中,我们有MethodHandles,它用作反射API。在项目中,要使用记录器,我们只需复制粘贴下一个代码:

Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

因为在这种情况下很难出错。