0
点赞
收藏
分享

微信扫一扫

程序设计的基本原则:内省和反射



经常在程序中,我们有时需要有关数据 - 例如,它们是什么类型的,还是类(OOP)的一个实例。基于这一认识,我们需要进行一些这些操作,甚至改变他们 - 但必要的各种数据,我们可能没有!如果你不明白,不要担心 - 我们将在整个详细的了解。所有这一切我已经在这里描述 - 一个说明用途两种可能性存在于几乎所有的现代编程语言:自省和反射。


内省 Introspector
内省 - 该程序在运行时,探索的对象的类型或特性的能力。正如我们提到的,你可能想知道什么类型的对象,无论是类的一个实例。有些人甚至让你学习对象的继承层次的语言的能力,在语言如Ruby,Java,PHP和Python中,C ++和其他反射。一般情况下,内省 - 这是非常简单的,非常强大的现象。这里是使用instrospektsii的几个例子:


// Java
 
if ( obj instance of  Person ) {
   Person  p = ( Person ) obj ;
   p . walk ( ) ;
}




//PHP
 
if ( $obj instance of  Person ) {
   // 我们做任何事
}

在Python,自省最常见的形式是使用dir方法来显示对象列表的属性:




# Python
 
class foo(object):
  def __init__(self, val):
    self.x = val
  def bar(self):
    return self.x
 
...
 
dir(foo(5))
=> ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']



在Ruby中,自省是非常有用的 - 尤其是因为语言本身的运作。在这一切都是对象 - 甚至是类 - 这带来了有趣的可能性,继承和

反射(见下文)的条款。如果你想知道更多一点,我建议你在Ruby中小周期读元编程。


下面是使用内省IRB(交互式Ruby外壳)的几个简单的例子:

# Ruby
 
$ irb
irb ( main ) : 001 : 0 > A = Class . new
= > A
irb ( main ) : 002 : 0 > B = Class . new A
= > B
irb ( main ) : 003 : 0 > a = A . new
= > #<A:0x2e44b78>
irb ( main ) : 004 : 0 > b = B . new
= > #<B:0x2e431b0>
irb ( main ) : 005 : 0 > a . instance_of ? A
= > true
irb ( main ) : 006 : 0 > b . instance_of ? A
= > false
irb ( main ) : 007 : 0 > b . kind_of ? A
= > true

您还可以找到一个对象,该类它是一个实例,甚至是“比较”类。



# Ruby
 
irb ( main ) : 008 : 0 > A . instance_of ? Class
= > true
irb ( main ) : 009 : 0 > a . class
= > A
irb ( main ) : 010 : 0 > a . class . class
= > Class
irb ( main ) : 011 : 0 > A > B
= > true
irb ( main ) : 012 : 0 > B <= A
= > true


然而,内省 - 这是不反射;反射允许我们使用内省的主要原则和真正做强大的东西与我们的代码。




反射

reflective


自省让你在运行时学习对象属性和反射 - 操纵它们。

反射 - 是一种计算机程序在运行时,研究和修改他们的结构和行为(值,元数据,属性和功能)的能力。在简单的语言:它可以让你调用方法的对象,创建新的对象,对其进行修改,甚至不知道的接口,字段,方法的名称在编译时。因为这种 反射的性质是比较困难的静态类型语言实现,如输入错误可以在编译时有发生,而不是运行时。然而,这是可能的,语言如Java,C#和其他允许同时使用内省和 反射(但不是C ++,它只允许使用内省)。


出于同样的原因,反射是更容易在一个解释语言来实现的,因为在创建并在运行时调用的函数,对象和其他数据结构时,使用一些内存分配系统。解释型语言通常提供一个默认的系统以及编译需要额外的编译器和解释器,监视反射的正确性。

我认为我们已经说了很多反射的定义,但它的意义是小熊。让我们来看看下面的代码示例(带和不带反射),每个创建一个类Foo对象,并调用了招呼。

/ ECMAScript - 如何JavaScript
 
//没有反射
new Foo ( ) . hello ( )
 
// 反射
//假设Foo属于此
new this [ 'Foo' ] ( ) [ 'hello' ] ( )
 
// 或承担
new ( eval( 'Foo' ) ) ( ) [ 'hello' ] ( )
 
// 还是不要打扰
eval( 'new Foo().hello()' )




// Java
 
//没有反射
Foo foo = new Foo ( ) ;
foo . hello ( ) ;
 
//反射
Object foo = Class . forName ( "complete.classpath.and.Foo" ) . newInstance ( ) ;
// 替代: Object foo = Foo.class.newInstance();
Method m = foo . getClass ( ) . getDeclaredMethod ( "hello" , new Class < ? > [ 0 ] ) ;
m . invoke ( foo ) ;




# Python
 
# 没有反射
obj = Foo ( )
obj . hello ( )
 
#反射
class_name = "Foo"
method = "hello"
obj = globals ( ) [ class_name ] ( )
getattr ( obj , method ) ( )
 
# С eval
eval( "Foo().hello()" )




# Ruby
 
#没有反射
obj = Foo . new
obj . hello
 
#反射
class_name = "Foo"
method = : hello
obj = Kernel . const_get ( class_name ) . new
obj . send method
 
# С eval
eval "Foo.new.hello"

这份清单并未穷尽反射的可能性。这是一个非常强大的原则,这也是在元编程的普遍做法。但是,使用反射时必须非常小心。虽然有它的优势,而使用反射,更不用说阅读代码,这使得它很难调试,同时也打开大门,非常糟糕的事情,比如通过eval语句注入的代码。



EVAL-表达


有些反光语言提供了使用eval表达式的能力 - 即识别值(通常是一个字符串)作为表达式的表达式。这样的言论 - 是

反射,甚至元编程中最强大的原则,也是最危险的,因为它们代表了对安全的威胁。


考虑Python中,从外部源接收网页(这就是为什么人们使用eval表达式的原因之一)上的数据下面的示例代码:

session [ 'authenticated' ] = False
data = get_data ( )
foo = eval( data )



保护方案将被打破,如果有人将GET_DATA给予()方法是以下行:

"session.update(authenticated=True)"

安全使用的eval语句的需要大大限制输入数据的格式 - 它通常只需要太多的时间。



结论


自省和反射 - 这是现代语言的一个非常强大的工具和自己的理解可能让你写的非常酷的代码。再次,我们注意到:自省 - 在对象属性的研究和

反射 - 他们的操纵。使用反射的时候,因为它可以使你的代码不可读和弱势群体要小心。



举报

相关推荐

0 条评论