大幅地影响程序的行为,不更动已编译好程序代码的情况下。便是反射机制的动态威力所在,却能大幅地影响程序的行为,不更动已编译好程序代码的情况下。这便是反射机制的动态威力所在许多接触过像Java及C#这类程序语言的顺序人,或许对"Reflect反射)"这个名词不陌生,但实际上将这个技巧运作在日常开发工作的顺序设计者,可能就并不那么多了
维基百科的解释是计算机顺序用以观察自身,"Reflection"这个名词。及修改自身结构和行为的过程”事实上,透过反射技巧,顺序在执行时期自身便能够得知自己的外观长相,并且自我修改,甚至自我复制。甚至自我修改与复制反射的作用:得知自己的外观。大多数都是脚本式(ScriptLanguag或是以虚拟机器为基础的顺序语言,支持反射机制的顺序语言众多。例如JavaC#SmalltalkPythonRubiPHPPerl等。甚至JavaScript也支持Reflect
还是要回到为什么顺序需要在执行时期得知自己的外观长相,反射机制究竟能为顺序提供什么样的作用?为什么顺序设计者需要动用到Reflection?针对诸如此类问题的答案。甚至进一步自我修改、复制。
编译时期便已为编译器所见。对这样的对象导向顺序而言,相对于“执行时期”未使用反射机制的顺序代码。当某个类别A存在与另一个类别B互动时,类别B编译时期的长相,势必已经已为类别A所了解。对于C++顺序而言,举例来说。类别A欲与类别B互动(例如呼叫它函数)编译器在编译类别A顺序代码时,必需也要能够得知类别B宣告及定义。相较于这样的限制,Reflect则让你顺序不用在编译时期便确定此事,而是让程序得以在执行时期,根据一些外在信息,决定操作的对象以及操作的方式,毋需于编译时期便确定、同时写死这些事情。
反射机制是一个十分动态的特性,由此可以推想。而且看起来可以为顺序注入许多的弹性。运用反射机制审视自身的特性,先来看看具体的Reflect机制,解释究竟反射机制能够带来什么好处之前。以明白透过罕见的Reflect支持,顺序中究竟能做到那些事情。以Java为例介绍,目的不在介绍Java完整的ReflectAPI而是透过Java协助大家了解Reflect一般性概念。
就是一个叫“ClassclassC#中有一个相似的类别,Java中反射机制的源头。则叫做Type这个类别有点特殊,原因在于此类别的每一个对象都用来表示系统中的每一个类别。每个Class对象都描述了每个类别的相关信息,具体来说。也提供你透过它可以进行的一些操作。想要开始Reflect动作,就必需先取得Class类别的对象。最常被运用到两个途径,一个便是Object所有对象皆继承的类别)所提供的getClass函数,另一个则是Class类别所提供的forNam静态函数。而后者则让你得以指定一个类别的名称后,前者让你得以取得一个对象(尤其是类型未知的对象)所属的类别。直接得到该类别对应的Class对象。便能“审视”自身的特性,有了Class对象之后。这些特性包括了隶属于那个Packag类别自身究竟是Public还是Privat继承自那一类别、实作了那些接口等。更重要的可以得知它究竟有那些成员变量以及成员函数(包括建构式)
不需在顺序中明定函数名称、自变量个数和类型透过反射。顺序便能够了解它所要处理的对象(尤其是类型未知的对象)究竟具备了什么特质。对运用反射机制的顺序而言,透过这个自我审视的过程。所了解到这些特质,便会影响到该程序的运作行为。也可以设定其值。同样的取得了某类别的成员函数后(Java中是以Method类别的对象表示)便可取得该成员函数的回传类型、传入的自变量列表类型,取得了某类别的成员变量后(Java中是以Field类别的对象表示)便可以取得该类别对象的成员变量值。当然更重要的Method类别的对象,可被用以呼叫类别对象的相对应成员函数。
顺序面临了一个待处理的对象,所以假想一个情境。但你完全不知道它那个类型,有什么成员变量、有什么成员函数,但你还是可以发觉出这一切,会知道每个成员变量的名称,每个成员函数的名称、甚至你还可以取得每个成员函数的值、设定它值、还可以呼叫每个成员函数,同时传入正确的自变量、正确地取得回传值。Java还允许顺序人透过Class类别的newInstanc函数,除此之外。发生该类别的对象,或许是透过Constructor类别对象取得建构式并呼叫、藉以执行不同建构式,以不同方式发生类别的对象。应当能够明白,从以上简短的描述中。Reflect让你得以在执行时期处置一些原先在编译时期才干够达成的动作。例如在Java中,想要发生某个类别的对象,得在顺序中这么写:
Fooobj=newFoo;
也就是说,编译时期就得将类别的名称明确写在顺序中。编译时期就必需让顺序知道这件事。如果你想呼叫某个函数,得这么写:
obj->bararg;
都必须在顺序代码中明确指定函数名称、自变量个数和类型。
便不再需要在顺序代码中明确指定这些东西。例如,但有了反射。顺序可以动态地决定究竟要发生那个类别的对象,可以从设定档中读取类别的名称、根据使用者的输入值,经过一段逻辑运算之后,决定要产生的类别名称,接着再利用反射机制,发生类别的对象。也可以动态地得知发生进去的对象拥有那些成员函数,甚至是否具有特定名称的成员函数,接着呼叫这些函数。
顺序代码在撰写及编译的时间点,有了反射。毋需明白实际在运行时,究竟会涉及那些类别以及它各自的行为。所写下的顺序代码,可以完全是对要处理的类别一无所知,也可以是对他有一点基本的假设(例如要处理的类别都具有相同名称的函数,却没有实作相同的接口,或是继承同样的类别)一切都可以等到执行时期,透过自我审视的能力,解要面对的对象究竟具备什么特性,再依据相对应的逻辑,动态利用顺序代码控制。当顺序毋需将行为写死,便消除了相依性。顺序代码在撰写时毋需将行为写死,有了如此动态的能力。包括要处理的类别、要存取的成员变量、要呼叫的函数等。这大大增加了顺序弹性,同时也增加了顺序的扩充性。
一个连接数据库的Java系统而言,举例来说。编译时期是不需要知道究竟运作时会使用那一个JDBC驱动顺序,系统只需要透过某种方式,例如在设定档中指定类别名称,那么顺序便可以依据这类别名称,加载相对应的JDBC驱动顺序,顺序代码中完全可以不涉及具体的JDBC驱动顺序究竟为何。相较于那些将数据库连接顺序代码以静态的方式附属在顺序代码中的做法,这不仅消除了一定水平的相依性。一旦遇上了必需变卦的时候,上述的作法只需更动JDBC驱动顺序在设定档中的名称,毋需改变任何已经编译进去的顺序代码。