关于oop:Java / C#等中反射的用途是什么

What is the use of reflection in Java/C# etc

本问题已经有最佳答案,请猛点这里访问。

我只是好奇,为什么我们首先应该使用反射?

1
2
3
4
5
6
7
8
9
// Without reflection
Foo foo = new Foo();
foo.hello();

// With reflection
Class cls = Class.forName("Foo");
Object foo = cls.newInstance();
Method method = cls.getMethod("hello", null);
method.invoke(foo, null);

我们可以简单地创建一个对象并调用类的方法,但是为什么要使用forname、newinstance和getmthod函数呢?

让一切都充满活力?


简单地说:因为有时您在编译时既不知道"foo"也不知道"hello"部分。

绝大多数时间你都知道这一点,所以不值得使用反射。只是偶尔,你不会-在那一点上,反思是你所能转向的。

例如,协议缓冲区允许您生成代码,其中要么包含用于读取和写入消息的完全静态类型代码,要么生成的代码刚好足够让其余的代码可以通过反射完成:在反射的情况下,加载/保存代码必须通过反射来获取和设置属性-它知道所涉及的属性的名称由于消息描述符。这要慢得多,但生成的代码要少得多。

另一个例子是依赖项注入,其中用于依赖项的类型的名称通常在配置文件中提供:然后DI框架必须使用反射来构造所有涉及的组件,一路上查找构造函数和/或属性。


每当您(=your method/your class)在编译时不知道该类型应该实例化或它应该调用的方法时,就使用它。

此外,许多框架使用反射来分析和使用对象。例如:

  • hibernate/nhibernate(和任何对象关系映射器)使用反射检查类的所有属性,以便它能够更新它们或在执行数据库操作时使用它们。
  • 您可能希望让它可以配置应用程序默认执行用户定义类的哪个方法。配置的值是String,您可以获取目标类,获取具有配置名称的方法,然后调用它,而不需要在编译时知道它。
  • 解析注释是通过反射完成的


您可以使用反射来自动化任何可以有效地使用对象方法和/或属性列表的过程。如果您曾经花时间编写代码,在对象的每个字段上依次执行大致相同的操作(保存和加载数据的明显方法通常是这样工作的),那么反射就可以自动为您执行这些操作。

最常见的应用程序可能有以下三种:

  • 序列化(参见,例如.NET的XmlSerializer)
  • 生成用于编辑对象属性的小部件(例如Xcode的Interface Builder,.net的Dialog Designer)
  • 通过检查构造函数的类并在创建时提供适当的对象(例如,任何依赖项注入框架),创建具有任意依赖性的对象的工厂。

典型的用法是插件机制,它支持编译时未知的类(通常是接口的实现)。


使用反射,您可以很容易地在文本中编写详细描述方法/字段的配置,使用这些配置的框架可以读取字段的文本描述并找到真正对应的字段。

例如,jxpath允许您导航如下对象:

1
//company[@name='Sun']/address

因此jxpath将寻找一个方法getCompany()(对应于company),一个名为name的字段等。

您可以在Java中的许多框架中找到这一点,例如JavaBeans、Spring等。


我以前在一些验证类中使用过它,在那里我在构造函数中传递了一个大型的、复杂的数据结构,然后运行无数(实际上是几百个)方法来检查数据的有效性。我的所有验证方法都是私有的,并返回布尔值,因此我创建了一个可以调用的"validate"方法,该方法使用反射调用类中所有私有方法,而不是返回布尔值。

这使得validate方法更加简洁(不需要枚举每一个小方法),并将所有正在运行的方法都保存下来(例如,有人编写了一个新的验证规则,忘记在主方法中调用它)。

在改为使用反射之后,我没有注意到性能有任何有意义的损失,代码更易于维护。


它对序列化和对象关系映射等操作很有用。通过使用反射获取对象的所有属性,可以编写通用函数来序列化对象。在C++中,你必须为每个类写一个单独的函数。


有时你需要在飞行中创建一个类对象,或者从别的地方创建一个Java代码(例如JSP)。在那个时候,反射是有用的。


除了jons的答案外,另一种用法是"将脚趾浸入水中",以测试给定的设施是否存在于JVM中。

在OS X下,如果调用了一些Apple提供的类,Java应用程序看起来更好。测试这些类是否存在的最简单方法是先用反射测试