introspection和reflection有什么区别?

68

有没有人能够从语言和环境的角度解释这两个概念之间的区别?

另外,编程语言需要满足一组条件才能成为反射性和/或内省性吗?

如果有这样的条件,那么这些条件是什么?


只需点击您在此问题上放置的标签的标签维基,即可转到http://en.wikipedia.org/wiki/Type_introspection,这是一个相当不错的起点。不是吗? - deceze
这是对的,但它并没有说明任何一般情况。 - U r s u s
2
有趣的是,这个相关的问题提供了一个非常好的答案:https://dev59.com/D3RC5IYBdhLWcg3wRO7k - slebetman
因为我认为这里的大多数答案都是错误的,所以我将参考我认为引入/推广这些术语的工作:Gilad Bracha、David M. Ungar: 镜像:面向对象编程语言元级设施的设计原则。OOPSLA 2004: 331-344 - Christophe De Troyer
3个回答

61

维基百科文章中有一个相当不错的概述:

在计算机科学中,类型内省是指程序在运行时检查对象类型或属性的能力。一些编程语言具备这种能力。

内省不应与反射混淆,后者更进一步,也就是程序能够在运行时操作对象的值、元数据、属性和/或函数的能力。一些编程语言,例如Java,也具备这种能力。

以静态类型、编译型程序为例:

SomeType function foo(int i) {
    return new SomeType(i);
}
所有类型都在编译时已知和强制执行,如果程序不满足其自己的显式类型约束,则程序甚至不应该编译。动态编程语言通常不表现出这种严格性,变量的类型不一定在编译时就已知。它们可能看起来更像这样:
function foo(i) {
    return new SomeType(i);
}

这个函数无法保证 i 是准确的,它只是传递它。这可能会导致某些问题,类型系统也无法帮助解决。这种错误检查通常由用户代码处理,因此需要具有内省能力的代码:

function foo(i) {
    if (!is_int(i)) {
        throw new InvalidArgumentException;
    }
    return new SomeType(i);
}

如何准确地界定内省(introspection)与反射(reflection)之间的区别存在一些争议。有人认为,内省是指任何允许代码测试某个东西是什么(“我是什么?”)的行为,而反射则是指能够操作程序结构本身的能力。例如,PHP 的一个示例:

$ref = new ReflectionClass('Foo');
$foo = $ref->newInstanceWithoutConstructor();

上述代码规避了创建新实例时运行Foo类的构造函数。这是运行时代码操作。不过,在实践中,PHP反射API还包含内省能力。其中一些能力是“较低级”内省能力所能做到的重复功能。例如:

以上代码绕过了创建一个新实例时运行Foo类的构造函数。这是运行时的代码操作。但在实践中,PHP的反射API也包含了内省的功能。其中一些能力与“更低级”的内省能力可以完成相同的任务。例如:

$ref = new ReflectionClass($obj);
if ($ref->getName() == 'Foo') ...

if ($obj instanceof Foo) ...

这两个代码片段本质上都做着相同的事情,但一个使用了反射(reflection),另一个则可称作内省(introspection)。可以看出,二者之间很难有清晰的分界线。不过,通常情况下,反射要比内省更加强大。例如在PHP中,你必须使用反射API来获取函数接受参数的类型信息,这只是“被动”的内省但属于反射API。不过这主要是实际实现的问题。

简而言之,按照一般定义,一个具有内省能力的程序需要能够在运行时检查其自身的部分,并根据此信息执行不同的代码。而一个拥有反射能力的程序除此之外还能在运行时改变自己的代码执行规则,例如选择不调用构造函数,而这在语言定义中通常是必需的操作。


4
自省(Introspection)不应与类型自省混淆。例如,Tcl具有输入/输出自省、函数源代码自省、运行时环境自省(可执行文件名称、库路径、操作系统、解释器版本等)、函数自省(列出所有可用函数)以及变量自省(列出所有可用变量)等功能,但没有类型自省,因为在Tcl中只有一种类型:字符串。 - slebetman
好的,我改掉了我的措辞。 - deceze
你的回答意味着所有静态类型程序都内置了内省机制,但实际上这并不是对象自我查看的情况,而是程序/解析器查看编写的命令并相应地定义对象属性的情况。在整个过程中,对象本身更多地是被动的。在大部分时间里,该对象并不存在,因为它尚未初始化。即使在具有静态类型的语言中,内省和反射也是通过库和框架及其API实现的。 - Nate T
每个语言都有自己的元编程工具。例如,C中的introspection支持GNOME GObject introspection库,而Java中的reflection可以通过reflection API实现。我将它们放在这里以供未来读者参考,您仍然因为回答详细和信息丰富而得到我的投票。 - Nate T

12

2

类型反射:

编程语言在运行时检查对象类型或属性的能力。

示例(Java):

String myObj1 = new String();
MyCustomObject myObj2 = new MyCustomObject();
if(myObj2 instanceof MyCustomObject) {
    System.out.println("This is an example of type interospection");
}

反射:

编程语言在运行时实现以下功能的能力。

  • 类型内省(如上所示)
  • 检查和修改对象。
  • 等等。

反射如何修改类结构?请参见此处:https://dev59.com/7ErSa4cB1Zd3GeqPV18r。 - Istiaque Ahmed
请仅翻译文本内容,不要解释它。你的回答意味着所有静态类型的程序都内置了自省功能,但这并不是对象自我查看的情况,而是程序/解析器查看编写的命令并相应地定义对象属性的情况。对象本身在整个过程中更多地是被动的。在大部分时间里,对象并不存在,因为它尚未初始化。即使在具有静态类型的语言中,自省和反射也是通过库和框架以及它们的API实现的。 - Nate T
每个都有一个例子:使用GNOME GObject内省库的C语言内省 - 以及通过反射API在Java中进行反射。您仍然会得到我对彻底回答的支持。 - Nate T

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接