经常在程序中,我们有时需要有关数据 - 例如,它们是什么类型的,还是类(OOP)的一个实例。基于这一认识,我们需要进行一些这些操作,甚至改变他们 - 但必要的各种数据,我们可能没有!如果你不明白,不要担心 - 我们将在整个详细的了解。所有这一切我已经在这里描述 - 一个说明用途两种可能性存在于几乎所有的现代编程语言:自省和反射。
内省 Introspector
内省 - 该程序在运行时,探索的对象的类型或特性的能力。正如我们提到的,你可能想知道什么类型的对象,无论是类的一个实例。有些人甚至让你学习对象的继承层次的语言的能力,在语言如Ruby,Java,PHP和Python中,C ++和其他反射。一般情况下,内省 - 这是非常简单的,非常强大的现象。这里是使用instrospektsii的几个例子:
2
3
4
5
6
|
// Java
if
(
obj
instance of
Person
)
{
Person
p
=
(
Person
)
obj
;
p
.
walk
(
)
;
}
|
1
2
3
4
5
|
//PHP
if
(
$obj
instance of
Person
)
{
// 我们做任何事
}
|
# 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']
下面是使用内省IRB(交互式Ruby外壳)的几个简单的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 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
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# 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()'
)
|
1
2
3
4
5
6
7
8
9
10
11
|
// 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
)
;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# Python
# 没有反射
obj
=
Foo
(
)
obj
.
hello
(
)
#反射
class_name
=
"Foo"
method
=
"hello"
obj
=
globals
(
)
[
class_name
]
(
)
getattr
(
obj
,
method
)
(
)
# С eval
eval
(
"Foo().hello()"
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 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表达式的能力 - 即识别值(通常是一个字符串)作为表达式的表达式。这样的言论 - 是 反射,甚至元编程中最强大的原则,也是最危险的,因为它们代表了对安全的威胁。
考虑Python中,从外部源接收网页(这就是为什么人们使用eval表达式的原因之一)上的数据下面的示例代码:
1
2
3
|
session
[
'authenticated'
]
=
False
data
=
get_data
(
)
foo
=
eval
(
data
)
|
保护方案将被打破,如果有人将GET_DATA给予()方法是以下行:
1
|
"session.update(authenticated=True)"
|
结论
自省和反射 - 这是现代语言的一个非常强大的工具和自己的理解可能让你写的非常酷的代码。再次,我们注意到:自省 - 在对象属性的研究和 反射 - 他们的操纵。使用反射的时候,因为它可以使你的代码不可读和弱势群体要小心。