作者:empty 页数:333 出版社:empty |
提起面向对象,每个程序设计者都有自己的理解,有的深入肌理,有的剑走偏锋,但是无论所长,几个基本的概念总会得到大家的重视,它们是:类、对象、继承、封装和多态,很对,差不多就是这些元素构成了面向对象设计开发的基本逻辑,成为数以千万计程序设计者不懈努力去深入理解和实践的根本,而实际上,理解面向对象一个重要的方法就是以实际的生活米类比对象世界,对象世界的逻辑和我们生活的逻辑形成对比的时候,这种体验将会更有亲切感,深入程度自然也就不同以往,9本节就从对象这一最基本元素开始, 进行一次深度的对象旅行, 把.NET面向对象世界中的主角来一次迎历式曝光。把对象的世界和人类的世界进行一些深度类比,以人类的角度戏说对象,同时也以对15那么一个人又是如何出生呢?每个婴儿随着一声啼哭来到这个世界,鼻子是鼻子、嘴巴是嘴巴,已经成为一个活生生的独立的个体,而母亲的怀胎十月是人在母体内的成长过程,母亲为胎儿提供了所有的养分和舒适的环境,这个过程就是一次实实在在的生物化构造。同样的道理,对象的出生,也是象的逻辑反思人类,究竟这种旅程,会有什么样的洞悉,且看本文的演义,10对象和人,两个世界,一样情怀,111.1.2出生12对象就像个体的人,生而入世,死而离世,13我们的故事就从对象之生开始吧,首先,看看一个对象是如何出生的:14 Persona Person=new Person( 小王 , 27) ;对象中,可以像这样来完成:次完整的构造过程:首先会在内存中分配定的存储空间;然后初始化其附加成员,就像给人取个具有标识作用的姓名一样;最后,再调用构造函数执行初始化,这样一个对象实体就完成了其出生的过程, 例如上例中我们为a Person对象初始化了姓名和年龄,16正如人出生之时,一身赤没有任何的附加品,其余的一切将随需而生,生不带来就是这个意思,对象的出生也只是完成了对必要字段的初始化操作,其他数据要通过后面的操作来完成,例如对属性赋值,通过方法获取必要的信息等
171.1.3旅程18婴儿一山世, 由it成为he or she, 就意味着从此融入了复杂的社会关系, 经历一次在人类伦理与社会规则的双重标准中生活,开始了为人的旅程,网理,对象也一样.19作为个体的人,首先是有类型之分的,农民,工人,学者、公务员等,所形成的社会规则就是农民在田间务农,工人在工厂生产,学者探讨知识,公务员管理国家。20对象也一样是有类型的,例如整型、字符型等等,当然,分类的标准不同,产生的类别也就不同,但是常见的分类就是值类型和引用类型两种,其依据是对象在运行时在内存中的位置,值类型位于线程的堆栈,而引用类型位丁托管堆,正如农民可以进城务上,工人也可以回乡务农,值类型和引用类型的角色也会发生转变,这个过程在面向对象中称为装箱与拆箱,这一点倒是与刚刚的例子很贴切,农民进城,工人网乡,不都得把行李装进箱子里折腾嘛,21作为人,我们都是有属性的,例如你的名字、年龄、籍贯等,用来描述你的状态信息,同时每个人也用不同的行为来操作自己的属性,实现了与外界的交互,对象的字段、属性就是我们自己的标签,而方法就是操作这些标签的行为,人的名字来自于长辈,是每个人在出生之时构造的,这和对象产生时给字段赋值样,但是每个人都有随时更名的权力,这种操作名称的行为,我们称之为方法,在面向22a Person.Change Name( Apple Boy ) ;23所以,对象的旅行过程,在某种程度上就是外界通过方法与对象交互,从而达到改变对象状态信息的过程,这也和人的生存之道暗合,24人与人之间通过语言交流,人一出生,就必然和这个世界的其他人进行沟通,形成种种相互的关系,融入这个完整的社会群体,在对象的世界里,你得绝对相信对象之间也是相互关联的,不同的对象之间发生着不同的交互性操作,那么对象的交互是通过什么方式呢?对象的交互方式被记录在本称为“设计模式”的魔法书中,当你不解以什么样的方式建立对象与对象之间的关系时,学习前人的经验,往往是最好的选择,25下面,我们简要地分析一下对象到底旅行在什么样的世界里?
26对象的生存环境是CLR, 而人的生存环境是社会, CLR提供了对象赖以生存的托管环境, 制定一系列的规则,称之为语法,例如类型、继承、多态、垃圾回收等,在对象世界里建立了真正的法制秩序;而社会提供了人行走江湖的秩序,例如法律、规范、道德等,帮助我们制约个体,维护社会:27人类社会就是系统架构,也是分层的,上层建筑代表政治和思想,通过社会契约和法律规范为经济基础服务,在对象世界中,这被称为接。面向接的编程就是以接方式来抽象变化,从而形成体系。正如人类以法律手段来维系社会体系的运作和秩序一样,28由此可见,对象的旅行就是这样一个过程,在一定的约定与规则下,通过方法进行彼此的交互操作,从而达到改变本身状态的目的,从最简单的方式理解实际情况,这些体会与人的旅程如此接近,给我们的启示更加感同身受,291.1.4插曲30接下来,我们以与人类世界的诸多相似之处,来进一步释对象世界的几个最熟悉的概念.31关于继承,人的社会中,继承一般发生在有血缘关系的族群中。最直接的例子一般是,儿子继承父亲,包括姓氏、基因、财产和一切可以遗留的东西,但并不代表可以继承所有,因为父亲隐私的那一部分属丁父亲独有,不可继承。当然,也可能是继承于族群的其他人,视实情而定,而在面向对象中,继承无处不在,子类继承父类,以访问权限来实现不同的控制规则,称为访问级别,如表1-1所示,32表1-1访问修改符33这些规则可以以公司的体制来举例说明,将公司职权的层级与面向对象的访间权限层级做类比,应该34—public, 具有最高的访问权限, 就像是公司的董事会具有最高的决策权与管理权, 因此public开放性最大,不管是否同一个程序集或者不管是否继承,都可以访问,一protected, 类似丁公司业务部门经理的职责, 具有对本部门的直接管辖权, 在面向对象中就体现为子类继承这种纵向关系的访问约定,也就是只要继承了该类,则共对象就有访间父类的权限,而不管这两个具有继承关系的类是否在同一个程序集中,36—internal, 具有类比意义的就是internal类似于公司的职能部门的职责, 不管是否具有上下级的属关系,人力资源部都能管辖所有其他部门的员工考勤,这是一种横向的职责关系,在面向对象中用来表示同一程序集的访问权限,只要是隶属于同一程序集,对象即可访问其属性,而不管是否存在隶属37―protected inte mal, 可以看做是protected internal的并集, 就像公司中掌管职能部门的副总经理, 从38―private, 具有最低的访问权限, 就像公司的一般员工, 管好自己就行了, 因此, 对应丁面向对象39另外,对象中继承的目的是提高软件复用,而人类中的继承,不也是现实中的复用吗?40而关于多态,人的世界中,我们常常在不同的环境中表现为不同的角色,并遵守不同的规则,例如在学校我们是学生,回到家是儿女,而在车上又是乘客,同一个人在不同的情况下,代表了不同的身份,在家里你可以撒娇但是在学校你不可以,在学校你可以打球但在车上你不可以,所以这种身份的不同,带来的是规则的差异,在面向对象中,我们该如何表达这种复杂的人类社会学呢?
70出此带来的好处是显而易见的, 我们以I Person代表了不同角色的人, 在不同的情况下实现了不同的操作,而把决定权交给系统自行处理.这就是多态的魅力,其乐无穷中,带来的是面向对象中最为重要的特性体验, 记住, 很重要的一点是, Do Work在不同的实现类中体现为同一命名, 不同的只是实现的内部逻辑,71这和我们的规则多么一致呀!72当然,有必要补充的是对象中的多态主要包括以下两种情况:73一接实现多态,就像上例所示。74一抽象类实现多态,就是以抽象类来实现。75其细节我们将在1.4节“多态的艺术 中加以详细讨论,76由此可见,以我们自己的角度来闻释技术问题,有时候会有意想不到的收获,否则你将被淹没在诸如“为什么以这种方式来实现复用”的叫喊中不能白拔、换一个角度,眼界与思路都会更加开阀.771.1.5消亡78对象和人,有生必然有死。在对象的世界里,它的生命是由GC控制的,而在人的世界里我们把GC称为自然规律, 进入死循环的对象, 是违反规划的, 必然无法逃脱被Kill的命运, 就如同没有长生不死的人一样,79在这一部分,我们首先观察对象之死,以此反思和体味人类入世的树学,两者相比较,也会给我们更多关于白己的启示,对象的生命周期由GC控制,其规则大概是这样:GC管理所有的托管堆对象,当内存回收执行时,GC检查托管堆中不再被使用的对象,并执行内存回收操作,不被应用程序使用的对象,指的是对象没有任何引用。关于如何回收、回收的时刻,以及遍历可回收对象的算法,是较为复杂的问题,我们将在5.3节“垃圾回收”中进行深度探讨,不过,这个回收的过程,同样使我们感慨,人自然就是那个看不见的GC,造物而又终将万物回收,无法改变。我们所能做到的是,将生命的周期拓宽、延长、书写得更加精彩,801.1.6结论81程序世界其实和人类世界有很多相似的地方,本节就以这种类比的方式来诠释这两个世界的主角:对象和人,以演化推进的手法来描述面向对象程序世界的主角对象由生而死的全过程,好似复杂的人生,而其实,人也可以是简单的,这是一种相互的较量,也是一种相互的借鉴.对象创建始末(上)本文将介绍以下内容:对象的创建过程内存分配分析内存布局研究
1.引言复杂的过程,主要包括内存分配和初始化两个环书,例如,对象的创建过程可以表示为:却经历着相当复杂的过程和周折,2.内存分配02007Anytao.com了解, NET的内存管理机制, 首先应该从内存分配开始, 也就是对象的创建环节、对象的创建, 是个FileS trea nfs=new FileS tren n(wC:temp.txt, FileS lode.Create) :通过new关键字操作, 即完成了对FileStream类型对象的创建过程, 这一看似简单的操作背后,本篇全文, 正是对这操作背后过程的详细讨论, 从中了解.NET的内存分配是如何实现的?关于内存的分配, 首先应该了解分配在哪里的问题, CLR管理内存的区域, 主要有二块, 分别为:·线程的堆栈,用于分配值光型实例。堆栈主要由操作系统管理,而不受垃圾收集器的控制,当值类型实例所在方法结束时,其存储单位自动释放。栈的执行效率高,但存储察最有限。·C工当有内存分成者回收时垃级仪集器可能会对CC堆进行编,评情见后文训14G00字作时, 实例被分配到LDH准I.面LO不会被压革, 而且只在完GC同收时破同收于值类型和引用类型的论述,请参见[第八回:品味类型---值类型与引用类型(上)一内存有理].有多个IL指令解析,主要包括:本文讨论的重点是, NET的内存分配机制, 因此下文将不加说明的以GC堆上的分配为例来展开。关了解了内存分配的区域,接着我们看看有哪些操作将导致对象创建和内存分配的发生,关于实例创建newobj.用于创建引用类型对象,ld str.用于创建string类型对象.new arr, 用丁分配新的数组对象,box.在值类型转换为引用类型对象时, 将值类型字段拷贝到托管堆上发生的内存分配,在上述论述的基础上, 下面从堆栈的内存分配和托管堆的内存分配两个方面来分别论述.NET的内存分配机制
2.1堆栈的内存分配机制类的字段时,值类型作为实例成员的一部分也被创建在托管堆上:装箱发生时,值类型字段也会拷贝在托管堆上,且堆栈的内存地址是由高位到低位向下填充,以下例而言:a in开始执行, 首先进入作用城的是整型局部变量x, 它将在栈上分配4Byte的内存空间, 因此堆栈指针向下移动4个字节,则值100将保存在49997~50000单位,而堆栈指针表示的下一个自由空间地址为49996.如图所示:对于值类型来说,一般创建在线程的堆栈上,但并非所有的值类型都创建在线程的堆栈上,例如作为对于分配在堆栈上的局部变量来说,操作系统维护着一个堆栈指针来指向下一个自由空间的地址,并public static void Main 0假设线程栈的初始化地址为50000,因此堆栈指针首先指向50000地址空间。代码由入函数M一堆栈指针+接着进入下一行代码, 将为字符型变量c分配2Byte的内存空间, 堆栈指针向下移动2个字节至49994单位,值'A'会保存在49995~49996单位,地址的分配如图:—堆栈指针+