fbpx
维基百科

反射式编程

计算机学中,反射式编程(英語:reflective programming)或反射(英語:reflection),是指计算机程序运行时runtime)可以访问、检测和修改它本身状态或行为的一种能力。[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

要注意术语“反射”和“内省”(type introspection)的关系。内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。[1]

概况

反射用于观察并修改程序在运行时的行为。一个反射導向的程式组件可以监测一个范围内的代码执行情况,可以根据获取的目标对象信息及与此相关的范围修改自身。这可通过在运行时动态分配程序代码实现。

在类型检测严格的面向对象编程语言Java中,一般需要在编译期间对程序中需要调用的对象的具体类型、介面(interface)、資料成員(fields)和方法的合法性进行检查。反射技术则允许将对需要调用的物件的訊息检查工作从编译期间推迟到运行期间再现场执行。这样一来,可以在编译期间先不明确目标物件的介面(interface)名称、字段(fields),即物件的資料成員(成员变量)、可用方法,然后在运行根据目标物件自身的訊息决定如何处理。它还允许根据判断结果进行实例化新物件和相关方法的呼叫。

反射主要用途就是使给定的程式,动态地适应不同的运行情况。利用物件導向建模中的多型(多态性)也可以简化编写分别适用于多种不同情形的功能代码,但是反射可以解决多型(多态性)并不适用的更普遍情形,从而更大程度地避免硬编码(即把代码的细节“写死”,缺乏灵活性)的代码风格。

反射也是元编程的一个关键策略。

历史背景

早期计算机的原生汇编语言本质上就具有反射特性。因为这些最初架构可以通过定义指令作为数据及使用自修改代码来编程,实现反射功能是很平常的。编程发展到使用编译型高级语言如AlgolCobolFortran和包括PascalC在内的很多其他语言时,自修改代码等实践很大程度上消失了,直到将反射特性内建入类型系统的高级编程语言出现后才再次提供了反射功能。Lisp语言家族以具有同像性作为标志性特征,可以认为具有反射性。

1982年,布莱恩·史密斯英语Brian Cantwell Smith在其博士论文《编程语言中的过程式反射》中[2],向过程式编程语言介入了“计算反射”的概念,并且引入自循環直譯器概念用作3-Lisp的一个组成部份[3]

特点

优点

支持反射的语言提供了一些在早期高级语言中难以实现的运行时特性。

  • 可以在一定程度上避免硬编码,提供灵活性和通用性。[4]
  • 可以作为一个頭等物件发现并修改源代码的结构(如代码块、类、方法、协议等)。
  • 可以在运行时像对待源代码语句一样动态解析字符串中可执行的代码(类似JavaScript的eval()函数),进而可将跟class或function匹配的字符串转换成class或function的调用或引用。
  • 可以创建一个新的语言字节码解释器来给编程结构一个新的意义或用途。

劣势

  • 此技术的学习成本高。面向反射的编程需要较多的高级知识,包括框架、关系映射和对象交互,以实现更通用的代码执行。
  • 同样因为反射的概念和语法都比较抽象,过多地滥用反射技术会使得代码难以被其他人读懂,不利于合作与交流。[4]
  • 由于将部分信息检查工作从编译期推迟到了运行期,此举在提高了代码灵活性的同时,牺牲了一点点运行效率。[4]

通过深入学习反射的特性和技巧,它的劣势可以尽量避免,但这需要许多时间和经验的积累。[4]

例子

下列代码片段建立Foo的一个实例foo,并调用它的方法PrintHello。对于每个编程语言,展示平常的和基于反射的调用序列。

C#

// Without reflection Foo foo = new Foo(); foo.PrintHello(); // With reflection Object foo = Activator.CreateInstance("complete.classpath.and.Foo"); MethodInfo method = foo.GetType().GetMethod("PrintHello"); method.Invoke(foo, null); 

Go

import "reflect" // Without reflection f := Foo{} f.Hello() // With reflection fT := reflect.TypeOf(Foo{}) fV := reflect.New(fT) m := fV.MethodByName("Hello") if m.IsValid() {  m.Call(nil) } 

Java

import java.lang.reflect.Method; // Without reflection Foo foo = new Foo(); foo.hello(); // With reflection try {  // Alternatively: Object foo = Foo.class.newInstance();  Object foo = Class.forName("complete.classpath.and.Foo").newInstance();  Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);  m.invoke(foo); } catch (Exception e) {  // Catching ClassNotFoundException, NoSuchMethodException  // InstantiationException, IllegalAccessException } 

Perl

# Without reflection my $foo = Foo->new; $foo->hello; # or Foo->new->hello; # With reflection my $class = "Foo" my $constructor = "new"; my $method = "hello"; my $f = $class->$constructor; $f->$method; # or $class->$constructor->$method; # with eval eval "new Foo->hello;"; 

PHP

// Without reflection $foo = new Foo(); $foo->hello(); // With reflection, using Reflections API $reflector = new ReflectionClass('Foo'); $foo = $reflector->newInstance(); $hello = $reflector->getMethod('hello'); $hello->invoke($foo); 

Python

# Without reflection obj = Foo() obj.hello() # With reflection obj = globals()['Foo']() # globals() Return a dictionary representing the current global symbol table.  getattr(obj, 'hello')() # getattr(object, name) Return the value of the named attribute of object.  # With eval eval('Foo().hello()') 

R

# Without reflection, assuming foo() returns an S3-type object that has method "hello" obj <- foo() hello(obj) # With reflection the.class <- "foo" the.method <- "hello" obj <- do.call(the.class, list()) do.call(the.method, alist(obj)) 

Ruby

# Without reflection obj = Foo.new obj.hello # With reflection class_name = "Foo" method_name = :hello obj = Object.const_get(class_name).new obj.send method_name # With eval eval "Foo.new.hello" 

常见应用

  • 反射经常作为软件测试的一部分,比如运行时创建/实例化模拟对象。
  • Java语言解析XML文件的技术用到了反射。

参见

参考资料

引用

  1. ^ 1.0 1.1 Forman 2005,第8頁。
  2. ^ Brian Cantwell Smith, Procedural Reflection in Programming Languages, Department of Electrical Engineering and Computer Science, Massachusetts Institute of Technology, PhD dissertation, 1982.
  3. ^ 3-lisp: an infinite tower of meta-circular interpreters. [2023-01-26]. (原始内容于2023-01-26). 
  4. ^ 4.0 4.1 4.2 4.3 Forman 2005,第4頁。

来源

  • Ira R. Forman, Nate Forman. Java Reflection in Action [Java反射实战] 1. Manning Publications Co. 2005年. ISBN 1-932394-18-4 (英语). 

外部链接

  • Reflection in logic, functional and object-oriented programming: a short comparative study (页面存档备份,存于互联网档案馆
  • Brian Foote's pages on Reflection in Smalltalk (页面存档备份,存于互联网档案馆
  • Java Reflection API Tutorial (页面存档备份,存于互联网档案馆) from Oracle

反射式编程, 在计算机学中, 英語, reflective, programming, 或反射, 英語, reflection, 是指计算机程序在运行时, runtime, 可以访问, 检测和修改它本身状态或行为的一种能力, 用比喻来说, 反射就是程序在运行的时候能够, 观察, 并且修改自己的行为, 要注意术语, 反射, 内省, type, introspection, 的关系, 内省, 或称, 自省, 机制仅指程序在运行时对自身信息, 称为元数据, 的检测, 反射机制不仅包括要能在运行时对程序自身信息进行检测, . 在计算机学中 反射式编程 英語 reflective programming 或反射 英語 reflection 是指计算机程序在运行时 runtime 可以访问 检测和修改它本身状态或行为的一种能力 1 用比喻来说 反射就是程序在运行的时候能够 观察 并且修改自己的行为 要注意术语 反射 和 内省 type introspection 的关系 内省 或称 自省 机制仅指程序在运行时对自身信息 称为元数据 的检测 反射机制不仅包括要能在运行时对程序自身信息进行检测 还要求程序能进一步根据这些信息改变程序状态或结构 1 目录 1 概况 2 历史背景 3 特点 3 1 优点 3 2 劣势 4 例子 4 1 C 4 2 Go 4 3 Java 4 4 Perl 4 5 PHP 4 6 Python 4 7 R 4 8 Ruby 5 常见应用 6 参见 7 参考资料 7 1 引用 7 2 来源 8 外部链接概况 编辑反射用于观察并修改程序在运行时的行为 一个反射導向的程式组件可以监测一个范围内的代码执行情况 可以根据获取的目标对象信息及与此相关的范围修改自身 这可通过在运行时动态分配程序代码实现 在类型检测严格的面向对象的编程语言如Java中 一般需要在编译期间对程序中需要调用的对象的具体类型 介面 interface 資料成員 fields 和方法的合法性进行检查 反射技术则允许将对需要调用的物件的訊息检查工作从编译期间推迟到运行期间再现场执行 这样一来 可以在编译期间先不明确目标物件的介面 interface 名称 字段 fields 即物件的資料成員 成员变量 可用方法 然后在运行根据目标物件自身的訊息决定如何处理 它还允许根据判断结果进行实例化新物件和相关方法的呼叫 反射主要用途就是使给定的程式 动态地适应不同的运行情况 利用物件導向建模中的多型 多态性 也可以简化编写分别适用于多种不同情形的功能代码 但是反射可以解决多型 多态性 并不适用的更普遍情形 从而更大程度地避免硬编码 即把代码的细节 写死 缺乏灵活性 的代码风格 反射也是元编程的一个关键策略 历史背景 编辑早期计算机的原生汇编语言本质上就具有反射特性 因为这些最初架构可以通过定义指令作为数据及使用自修改代码来编程 实现反射功能是很平常的 编程发展到使用编译型高级语言如Algol Cobol Fortran和包括Pascal和C在内的很多其他语言时 自修改代码等实践很大程度上消失了 直到将反射特性内建入类型系统的高级编程语言出现后才再次提供了反射功能 Lisp语言家族以具有同像性作为标志性特征 可以认为具有反射性 1982年 布莱恩 史密斯 英语 Brian Cantwell Smith 在其博士论文 编程语言中的过程式反射 中 2 向过程式编程语言介入了 计算反射 的概念 并且引入自循環直譯器概念用作3 Lisp的一个组成部份 3 特点 编辑优点 编辑 支持反射的语言提供了一些在早期高级语言中难以实现的运行时特性 可以在一定程度上避免硬编码 提供灵活性和通用性 4 可以作为一个頭等物件发现并修改源代码的结构 如代码块 类 方法 协议等 可以在运行时像对待源代码语句一样动态解析字符串中可执行的代码 类似JavaScript的eval 函数 进而可将跟class或function匹配的字符串转换成class或function的调用或引用 可以创建一个新的语言字节码解释器来给编程结构一个新的意义或用途 劣势 编辑 此技术的学习成本高 面向反射的编程需要较多的高级知识 包括框架 关系映射和对象交互 以实现更通用的代码执行 同样因为反射的概念和语法都比较抽象 过多地滥用反射技术会使得代码难以被其他人读懂 不利于合作与交流 4 由于将部分信息检查工作从编译期推迟到了运行期 此举在提高了代码灵活性的同时 牺牲了一点点运行效率 4 通过深入学习反射的特性和技巧 它的劣势可以尽量避免 但这需要许多时间和经验的积累 4 例子 编辑下列代码片段建立类Foo的一个实例foo 并调用它的方法PrintHello 对于每个编程语言 展示平常的和基于反射的调用序列 C 编辑 Without reflection Foo foo new Foo foo PrintHello With reflection Object foo Activator CreateInstance complete classpath and Foo MethodInfo method foo GetType GetMethod PrintHello method Invoke foo null Go 编辑 import reflect Without reflection f Foo f Hello With reflection fT reflect TypeOf Foo fV reflect New fT m fV MethodByName Hello if m IsValid m Call nil Java 编辑 import java lang reflect Method Without reflection Foo foo new Foo foo hello With reflection try Alternatively Object foo Foo class newInstance Object foo Class forName complete classpath and Foo newInstance Method m foo getClass getDeclaredMethod hello new Class lt gt 0 m invoke foo catch Exception e Catching ClassNotFoundException NoSuchMethodException InstantiationException IllegalAccessException Perl 编辑 Without reflection my foo Foo gt new foo gt hello or Foo gt new gt hello With reflection my class Foo my constructor new my method hello my f class gt constructor f gt method or class gt constructor gt method with eval eval new Foo gt hello PHP 编辑 Without reflection foo new Foo foo gt hello With reflection using Reflections API reflector new ReflectionClass Foo foo reflector gt newInstance hello reflector gt getMethod hello hello gt invoke foo Python 编辑 Without reflection obj Foo obj hello With reflection obj globals Foo globals Return a dictionary representing the current global symbol table getattr obj hello getattr object name Return the value of the named attribute of object With eval eval Foo hello R 编辑 Without reflection assuming foo returns an S3 type object that has method hello obj lt foo hello obj With reflection the class lt foo the method lt hello obj lt do call the class list do call the method alist obj Ruby 编辑 Without reflection obj Foo new obj hello With reflection class name Foo method name hello obj Object const get class name new obj send method name With eval eval Foo new hello 常见应用 编辑反射经常作为软件测试的一部分 比如运行时创建 实例化模拟对象 Java语言解析XML文件的技术用到了反射 参见 编辑程序自修改 反射式编程语言和平台列表参考资料 编辑引用 编辑 1 0 1 1 见Forman 2005 第8頁 Brian Cantwell Smith Procedural Reflection in Programming Languages Department of Electrical Engineering and Computer Science Massachusetts Institute of Technology PhD dissertation 1982 3 lisp an infinite tower of meta circular interpreters 2023 01 26 原始内容存档于2023 01 26 4 0 4 1 4 2 4 3 见Forman 2005 第4頁 来源 编辑 Ira R Forman Nate Forman Java Reflection in Action Java反射实战 1 Manning Publications Co 2005年 ISBN 1 932394 18 4 英语 使用 accessdate 需要含有 url 帮助 外部链接 编辑Reflection in logic functional and object oriented programming a short comparative study 页面存档备份 存于互联网档案馆 An Introduction to Reflection Oriented Programming Brian Foote s pages on Reflection in Smalltalk 页面存档备份 存于互联网档案馆 Java Reflection API Tutorial 页面存档备份 存于互联网档案馆 from Oracle 取自 https zh wikipedia org w index php title 反射式编程 amp oldid 76307587, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。