对象(下): 如果 @ISA 包含多于一个包的名字,包的搜索都是从左向右的顺序进行的。这些搜索是由 浅入深的,因此,如果你有一个 Mule 类有象下面这样的继承关系: 因为一个 BEGIN 块立即就执行了,所以它甚至可以在其他文件编译前把子过程声明, 定义以及输入等抓过来。这 些动作可能改变编译器对当前文件其他部分分析的结果, 特别是在你输入了子过程定义的情况下。至少,声明一个 子过程就把它当作一个列表 操作符使用,这样就令圆括号是可选的。如果输入的子过程定义了原型,那么调用它 的时候就会当作内建函数分析,甚至覆盖同名的内建函数,这样就可以给它们不同的 语意。use 声明就是一个带有 目的的 BEGIN 块声明。 访问被覆盖的方法: [root@wx03 5]# cat a5.pl END {print cccccccccccc." "}; print "aaaaaaaaaaaaa "; BEGIN {print bbbbbbbbbbbbbb." "}; [root@wx03 5]# perl a5.pl bbbbbbbbbbbbbb aaaaaaaaaaaaa cccccccccccc 根据结果,我们得出,BEGIN是在Perl语言运行最开始运行的块,END是在Perl语言运行最后运行的块,并注意BEGIN和END必须是大写的。 有时候, 你希望一个衍生类的方法表现得象基类中的某些方法的封装器。 这就是 SUPER 伪类提供便利的地方。它令你能够调用一个覆盖了的基类方法,而不用声 明是哪个类定义了该方法。 访问被覆盖的方法: [root@wx03 5]# cat Critter.pm package Critter; sub new { my $self = {}; my $invocant = shift; my $class = ref($invocant) || $invocant; my ($name)=@_; my $self = { "name" =>$name }; bless $self, $class; # Use class name to bless() reference return $self; }; sub sum2 { $self=shift; my $a=shift; my $b=shift; return $a + $b; }; sub fun1 { $self=shift; my $a=shift; my $b=shift; return $a / $b; } sub kick { my $self=shift; my $a=shift; my $b=shift; return $a / $b +66; } 1; [root@wx03 5]# cat a6.pl use Horse; use Data::Dumper; $steed = Horse->new(color => "dun"); print $steed->kick(33,4); print " "; use base qw(Critter); require Critter; print $steed->SUPER::kick(33,4); print " "; [root@wx03 5]# perl a6.pl 132 74.25 /******************** [root@wx03 5]# cat Horse.pm package Horse; our @ISA = "Critter"; require Critter; sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = { color => "bay", legs => 4, owner => undef, @_, # 覆盖以前的属性 }; return bless $self, $class; #return $self; }; sub sum1 { $self=shift; my $a=shift; my $b=shift; return $a + $b + 7; }; sub kick { my $self=shift; $self->SUPER::kick(@_); }; 1; [root@wx03 5]# cat Critter.pm package Critter; sub new { my $self = {}; my $invocant = shift; my $class = ref($invocant) || $invocant; my ($name)=@_; my $self = { "name" =>$name }; bless $self, $class; # Use class name to bless() reference return $self; }; sub sum2 { $self=shift; my $a=shift; my $b=shift; return $a + $b; }; sub fun1 { $self=shift; my $a=shift; my $b=shift; return $a / $b; } sub kick { my $self=shift; my $a=shift; my $b=shift; return $a / $b +66; } 1; [root@wx03 5]# cat a6.pl use Horse; use Data::Dumper; $steed = Horse->new(color => "dun"); print $steed->kick(12,4); print " "; [root@wx03 5]# perl a6.pl 69 UNIVERSAL :最终的祖先类: 这个包从来不会在 @ISA 中出现,但如果查找 @ISA 失败总是要查找它。你可以把 UNIVERSAL 看作最终 的祖先,所有类都隐含地从它衍生而来。 INVOCANT->isa(CLASS) 如果 INVOCANT 的类是 CLASS 或者任何从 CLASS 继承来的,isa 方法返回真。 [root@wx03 5]# cat a7.pl use Horse; use Data::Dumper; $steed = Horse->new(color => "dun"); print $steed->isa(Horse); print " "; print $steed->isa(Critter); print " "; print $steed->isa(test); print " "; [root@wx03 5]# perl a7.pl 1 1 [root@wx03 5]# $steed的类是Horse 或者从Horse继承而来的((Critter); 判断是否是HASH类型: [root@wx03 5]# cat a7.pl use Horse; use Data::Dumper; $steed = Horse->new(color => "dun"); print $steed->isa(Horse); print " "; print $steed->isa(Critter); print " "; print UNIVERSAL::isa($steed,'HASH'); print " "; [root@wx03 5]# perl a7.pl 1 1 1 判断方法是否存在: [root@wx03 5]# cat a8.pl use Horse; use Data::Dumper; $steed = Horse->new(color => "dun"); print $steed->can(sum1); print " "; print $steed->can(sumxx); print " "; [root@wx03 5]# perl a8.pl CODE(0x28f89d0) [root@wx03 5]# 我们可以用这个方法实现条件调用——只有方法存在才调用: $obj->snarl if $obj->can("snarl"); 方法自动装载: [root@wx03 5]# cat Horse.pm package Horse; our @ISA = "Critter"; require Critter; sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = { color => "bay", legs => 4, owner => undef, @_, # 覆盖以前的属性 }; return bless $self, $class; #return $self; }; sub sum1 { $self=shift; my $a=shift; my $b=shift; return $a + $b + 7; }; sub kick { my $self=shift; $self->SUPER::kick(@_); }; %h1=(a=>1); sub AUTOLOAD { return testdadadak888 ; }; 1; [root@wx03 5]# cat a8.pl use Horse; use Data::Dumper; $steed = Horse->new(color => "dun"); print $steed->dahda8da; print " "; [root@wx03 5]# perl a8.pl testdadadak888 [root@wx03 5]# 私有方法: 实例析构器; 管理实例数据: 比如,如果你希望一个叫 $city 的对象有一个数据 域名字叫 elevation,你可以简单地 $city->{elevation} 这样访问它。可以不用声明。 方法的封装会为你做这些。 大多数类都把它们的对象的属性保存在一个匿名散列表 里。对象的实例数据保存在这个散列表里,这个散列表也是该对象自己的小名字空间,用以 划分哪个类对该对象进行了哪些操作。 use fields 定义的域: 对象不一定要用匿名散列来实现。任何引用都可以。比如,如果你使用一个匿名数组,你可 以这样设置一个构造器; 用 Class::Struct 生成类: 使用 Autoloading (自动装载)生成指示器: