《Java编程思想》读书笔记:第一章 对象导论

目录

1.1抽象过程

1.2每个对象都有一个接口

1.3每个对象都提供服务

1.4被隐藏的具体实现

1.5复用具体实现

1.6继承

      1.6.1“是一个”与“像一个”关系

1.7伴随多态的可互换对象

1.8单根继承结构

1.9容器

1.9.1参数化类型

1.10对象的创建和生命期

1.11异常处理:处理错误

1.12开发编程

1.13Java与Internet

1.13.1Web是什么

1.13.2客户端编程

1.13.3服务器编程


1.1抽象过程

        程序员必须建立起在机器模型(位于“解空间”内,这是你对问题建模的地方,例如计算机)和实际待解问题的模型(位于“问题空间”内,这是问题存在的地方,例如一项业务)之间的联系

       每个对象具有状态,还具有操作,用户可以要求对象执行这些操作。如果要对现实世界中的对象作类比,那么说它们都具有特性和行为似乎不错。

面向对象程序设计(OOP)的特征:

1)万物皆为对象:理论上讲,你可以抽取待求解问题的任何概念化构件(狗、建筑物...)将其表示为程序中的对象。

2)程序是对象的集合,他们通过发送消息来告知彼此所要做的:可以把消息想象为对某个特定对象的方法的调用请求。

3)每个对象都有自己的由其他对象所构成的存储:换句话说,可以通过创建包含现有对象的包的方式来创建新类型的对象。因此,可以在程序中构建复杂的体系,同时将其复杂性隐藏在对象的简单性背后。

4)每个对象都拥有其类型:“每个对象都是某个类(class)的一个实例”。这里的:类:就是“类型”的同义词

5)某一特定类型的所有对象都可以接收同样的消息:也就是一个“圆形”对象必须能够接受发送给“几何形”对象的消息、

Booch对对象提出了更加简洁的描述:"对象具有状态、行为和标识"。这意味着每一个对象都可以拥有内部数据(它们给出了该对象的状态)和方法(它们产生的行为),并且每一个对象都可以唯一地与其他对象区分开来,具体来说,就是每一个对象在内存中都有一个唯一的地址。

1.2每个对象都有一个接口

        抽象数据类型的运行方式于内置类型几乎完全一致:你可以创建某一类型的变量(按照面向对象的说法,称其为对象或实例)然后操作这些变量(称其为发送消息或请求;发送消息,对象就知道药做什么)。

       类描述了具有相同特性(数据元素)和行为(功能)的对象集合,所以一个类实际上就是一个数据类型。

      对面对象程序设计的挑战之一,就是在问题空间的元素和解空间的对象之间创建一对一的映射。

       每个对象都只能满足某些请求,这些请求由对象的接口所定义,决定接口的便是类型。接口确定了对某一特定对象所能发出的请求。但是,在程序中必须有满足这些请求的代码。这些代码于隐藏的数据一起构成了实现。

Eg:

类型/类的名称是Light,特定的Light对象的名称是it,可以向Light对象发出的求情是:打开它、关闭它、将它调亮、将它调暗。

Light it = new Light();
it.on();

上列方式创建了一个Light对象:定义这个对象的“引用”it,然后调用new方法来创建该类型的新对象。为了向对象发送消息,需要声明对象的名称,并以圆点符号连接一个消息请求。

1.3每个对象都提供服务

       正当在试图开发或理解一个程序设计时,最好的方法之一就是将对象想象为"服务提供者"。程序本身将向用户提供服务,它将通过调用其他对象提供的服务来实现这一目的。你的目标就是去去创建(或者最好是在现有代码库中寻找)能够提供理想的服务来解决问题的一系列对象。

       将对象看作是服务提供者还有一个附带的好处:它有助于提高对象的内聚性。高内聚是软件设计的基本质量要求之一;这意味着一个软件构件(例如一个对象,当然它也有可能是指一个方法或一个对象库)的各个方面"组合"得很好。人们在设计对象时所面临的一个问题是,将过多的功能都塞在一个对象中。在良好的面向对象设计中,每个对象都可以很好地完成一项任务,但是它并不试图做更多的事。

1.4被隐藏的具体实现

        将程序开发人员按角色分为类创建者(那些创建新数据类型的程序员)和客户端程序员(那些在其应用中使用数据类型的类消费者)。类创建者的目标是构建类,这种类只需要向客户端程序员暴露必须的部分,而隐藏其他部分。隐藏的这部分客户端程序员将不能够访问它,这意味这类创建者可以任意修改被隐藏的部分,而不用担心对其他任何人造成影响。

        Java用三个关键字在类的内部设定边界:public、private、protected。这些访问指定词决定了紧跟其后被定义的东西可以被谁使用

public:表示紧跟其后的元素对任何人都是可用的

private:表示除了类型创建者和类型的内部方法之外的任何人都不能访问的元素。

protected:和private作用相当,差别仅在于继承的类可以访问protected成员,但是不能访问                             private成员。

不写:表示一种默认的访问权限,这种权限通常被称为包访问权限,因为在这种权限下,类可以               访问在同一个包(库构件)中的其他类成员,但是在包之外,这些成员如同指定了private               一样

1.5复用具体实现

        代码复用是面向对象程序设计所提供的最了不起的优点之一。

        最简单地复用某个类的方式就是直接使用该类的一个对象,此外也可以将哪个类的一个对象置于某个新的类中。我们称其为“创建一个成员对象”。因为是在使用现有的类合成新的类,所以这种概念成为“组合”。组合具有“has-a”关系,就像我们常说的“汽车拥有引擎”。

        在继承和组合这两种复用具体实现的方法中,实际上,在建立一个新类时,应该首先考虑组合,因为它更加简单灵活。

1.6继承

       我们以现有类为基础,复制它,然后通过添加和修改这个副本来创建新类那就要好多了。通过继承可以实现这种效果,不过也有例外,当源类(被称为基类、越类或父类)发生变动时,被修改的“副本”(被称为导出类、继承类或子类)也会反映出这些变动。

        当继承现有类时,也就创建了新的类型,这个新的类型不仅包括现有类型的所有成员(频率i特成员被隐藏起来,并且不可访问),而且更重要的是它复制了基类的接口,也就是说,所有可以发送给基类对象的消息同时也可以发送给导出类对象。通过继承而产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛,例如“一个圆形也就是一个几何形”。

      有两种方法可以使基类与导出类产生差异。

  • 第一种方法:直接在导出类中添加新方法。这种新方法并不是基类接口的一部分。
  • 第二种方法:改变现有基类的方法的行为,这种称为“覆盖”那个方法。要想要覆盖某个方法,可以直接在导出类中创建该方法的新定义即可。也就是“此时,我正在使用相同的接口方法,但是我想在新类型中做些不同的事情”   

      1.6.1“是一个”与“像一个”关系

   在继承关系中,如果只是覆盖基类的方法,而不添加在基类中没有的新方法。这样它们具有完全相同的接口。这可以被视为存粹代替,通常称之为替代原则。这种情况下的基类和导出类之间的关系称为is-a(是一个)关系,因为可以说”一个圆形就是一个几何形状“。判断是否继承,就是要去欸的那个是否可以用is-a来描述类之间的关系,并使之具有实际意义。

    有时必须在导出类型中添加新的接口元素,这样也就扩展了接口。这样新的类型仍然代替基类,但是这种替代并不完美,因为基类无法访问新添加的方法。这种情况我们可以描述为is-like-a(像是一个)关系。

1.7伴随多态的可互换对象

       面向对象程序设计语言使用后期绑定的概念,当向对象发送消息时,被调用的代码直到运行时才能确定。编译器确保被调用的方法的存在,并对调用参数和返回值执行类型检查,但是并不知道将被执行的确切代码。

        为了执行后期绑定,Java使用一小段特殊的代码来替代绝对地址调用。这段代码使用在对象中存储的信息来计算方法体的地址。这样根据这一小段代码的内容,每一个对象都可以具有不同的行为表现。当向一个对象发送消息时,该对象就能够知道对这条消息应该做些什么。

在Java中,动态绑定是默认行为,不要添加额外的关键字来实现多态。

Eg:

void doSomething(Shape shape){
 shape.erase();
 //...
 shape.draw();
}

这个方法可以与任何Shape对话,因此它是独立于任何它要绘制和擦除的对象的具体类型。如果程序中其他部分用到doSomething()方法

Circle circle=new Circle();
Trigangle triangle=new Trigangle();
Line line=new Line();
doSomething(circle);
doSomething(triangle);
doSomething(line);

对doSomething()的调用会自动地正确处理,而不管对象的确切类型。

  • 以doSomething(circle)为例子:当Circle被传入到预期接受Shape的方法中。由于Circle可以被doSomething()看作是Shape,也就是说,doSomething()可以发送给Shape的任何消息,Circle都可以被接收,那么,这么做是完全安全且合乎逻辑的。

       当Java编译器在编译doSomething()的代码时,并不能确切知道doSomething()要处理的确切类型。所以通常会期望它的编译结果是调用基类Shape的erase()和draw()版本,而不是具体的Circle、Square或Line的相应版本。正是因为多态才使得事情总是能够被正确处理。

      把子类看作是它的父类的过程称为向上转型。

1.8单根继承结构

在Java中所有类最终都继承自单一的基类。这个终极基类的名字就是Object。

       单根继承结构保证所有对象都具备某些功能。因此你知道,在你的系统中你可以在每个对象上执行某些基本操作,所有对象都可以很容易地在堆上创建,而参数传递也得到了极大的简化。

       单根继承结构使垃圾回收器的实现变动容易的多。由于所有对象都保证具有其类型信息,因此不会因无法确定对象的类型而陷入僵局。

1.9容器

        通常来说,如果不知道在解决某个特定问题时需要多少个对象,或者它们将存活多久,那么就不可能知道如何存储这些对象。针对这个问题,是不可能知道的,因为这类信息只有在运行时才能获得。

       创建另一种对象类型,这种新的对象类型持有对其他对象的引用。这个通常称为”容器“,在任何需要时都可以扩充自己以容纳你置于其中的所有东西。因此不需要知道将来会把多少东西个对象置于容器中,只需要创建一个容器对象,然后让它处理所有细节。

       在Java中,具有满足不同需求的各种类型的容器,例如List(用于存储序列),Map(称为关联数组,用来建立对象之间的关联),Set(每种对象类型只持有一个),以及诸如队列、树、堆栈等更多的构件。

1.9.1参数化类型

       单根继承结构意味这所有东西都是Object类型,所以可以存储Object的容器可以存储任何东西,这使得容器很容易被复用。

      要使用这样的容器,只需在其中置入对象引用,稍后还可以将它们取回。但是由于容器只存储Object,所以当将对象引用置入容器时,它必须被向上转型为Object,因此它会丢失其身份。当把它取回时,就获得了一个对Object对象的引用,而不是对置入时的那个类型的对象的引用。

      使用向下转型,可以转型为更具体的类型。我们知道,向上转型是安全的,例如Circle是一中Sjape类型,但是不知道某个Object是Circle还是Shape,所以除非确切知道所要处理的对象的类型,否则向下转型是几乎是不安全的。

      参数化类型机制,就是创建一个知道自己所保存的对象的类型,从而不需要向下转型以及消除犯错误的可能的容器。参数化类型就是一个编译器可以自动定制作用与特定类型上的类。

   在Java中称为”范型“,一对尖括号,中间包含类型信息。例如:创建一个存储Shape的ArrayList

ArrayList<Shape> shapes= new ArrayList<Shape>();

1.10对象的创建和生命期

        在使用对象时,最关键的问题之一便是它们的生成和销毁方式。每个对象为了生存都需要资源,尤其是内存。当我们不再需要一个对象时,它必须被清理掉,使其占有的资源可以被释放和重用。

        Java提供了被称为”垃圾回收器“的机制,它可以自动发现对象何时不再被使用,并继而销毁它。垃圾回收器非常有用,因为它减少了所必须考虑的议题和必须编写的代码。更重要的是,垃圾回收器提供了更高层的保障,可以避免暗藏的内存泄露问题。

1.11异常处理:处理错误

       异常是一种对象,它从出错点地点被”抛出“,并被专门设计用来处理特定类型错误的相应的异常处理器”捕获“。异常处理就像是与程序正常执行路径并行的,在错误发生时执行的另一条路径。因为它是另一条完全分离的执行路径,所以它不会干扰正常的执行代码。

      此外,被抛出的异常不像方法返回的错误值和方法设置的用来表示错误条件的标志位那样可以被忽略。异常不能被忽略,所以它保证一定会在某处得到处理。

    Java一开始就内置了异常处理,而且强制你必须使用它。它是唯一可接受的错误报告方式。如果没有编写正确的处理异常的代码,那么就会得到一条编译时的出错消息。

1.12开发编程

       我们只是想把问题切分成多个可独立运行的部分(任务),从而提高程序的响应能力。在程序中,这些彼此独立运行的部分称为线程,上述概念被称为”并发“。

       通常,线程只是一种为单一处理器分配执行时间的手段。但是如果操作系统支持多处理器,那么每个任务都可以被指派给不同的处理器,并且它们是真正地并行执行。

       所有这些使得并发看起来相当简单,但是有一个隐患:共享资源。如果有多个并行任务都要访问同一项资源,那么就会出问题。例如,两个进程不能同时向一台打印机发送消息。为了解决这个问题,可以共享的资源,例如打印机,必须在使用期间被锁定。因此,整个过程是:某个任务锁定某项资源,完成其任务,然后释放资源锁,使其他任务可以使用这项资源。

1.13Java与Internet

        Java对于解决传统的单机程序设计问题非常有用,但同样重要的是,它解决了在万维网上的程序设计问题。

    1.13.1Web是什么

1、客户/服务器计算技术

       系统具有一个中央信息存储池,用来存储某种数据,它通常存在于数据库中,你可以根据需要将它分发给某些人员或机器集群。客户/服务器概念的关键在于信息存储池的位置集中于中央,这使得它可以被修改,并且这些修改将被传播给消息消费者。总之,信息存储池,在于分发信息的软件以及信息与软件驻留的机器或集群被总称为服务器。驻留在用户机器上的软件与服务器进行通信,以获得信息,处理信息,然后将它们显示在被称为客户机的用户机器上。

2、Web就是一台巨型服务器

Web实际上就是一个巨型客户/服务器系统,但稍微差一点,因为所有的服务器和客户机都同时共存于同一个网络中。你所要关心的只是在某一时刻怎样理解到一台服务器上,并与之进行交互。

    1.13.2客户端编程

        Web最初的”服务器-浏览器“设计是为了能够提供交互性的内容,但是其交互性完全由服务器提供。服务器提供静态页面,提供给只能解释并显示它们的客户端浏览器。

        基本的HTML包含有简单的数据收集机制:文本输入框、复选框、单选框、列表和下拉式列表以及按钮——它只能被编程来实现复位表单上的数据或提交表单上的数据给服务器。这种提交的动作通过所有的Web服务器都提供的通用网关接口CGI传递。提交内容会告诉CGI应该如何处理它。最常见的动作就是运行一个在服务器中常被命名为”cgi-bin“的目录下的一个程序。几乎所有的语言都可以用来编写这些程序,常见的有Python或者Perl。

       当今许多有影响力的网站完全构建于CGI之上,实际上你几乎可以通过CGI做任何事,但是,构建GCI程序之上的网站可能会迅速变得过于复杂而难以维护,并同时产生响应时间过长的问题。CGI程序的响应时间依赖于所必须发送的数据量的大小,以及服务器和Internet的负载。Web的最初设计者们并没有预见到网络带宽被人们开发的各种应用迅速耗尽。例如对Web输入单表进行数据验证的过程:你按下网页上的提交按钮,数据被发送回服务器,服务器启动一个CGI程序来检查,发现错误,并将错误组装为一个HTML页面,然后将这个页面发回给你,之后你必须回退一个页面,然后重新再试。这个过程不仅很慢,而且不太优雅。

        此问题的解决方案就是”客户端编程“,意味着Web浏览器能用来执行任何它可以完成的工作,使得返回给用户的结果更加迅捷,而且使得你都网站更加具有交互性。

       客户端编程的问题是:它于通常意义上的编程十分不同,参数几乎相同,而平台却不同。Web浏览器就像一个功能受限的操作系统。最终,你仍然必须编写程序,而且还得处理那些令人头晕眼花的成堆问题,并以客户端编程的方式来产生解决方案。

1、插件

      客户端编程最重要的一步就是插件的开发。通过这种方式、程序员可以下载一段代码,并将其插入到浏览器中适当的位置,以此来为浏览器添加新功能。它告诉浏览器:从现在开始,你可以采取这个行动了(只需要下载一次插件即可)。

2、脚本语言

       插件引发了浏览器脚本语言的开发。通过使用某种脚本语言,你可以将客户端程序的源代码直接嵌入到HTML页面中,解释这种语言的插件在HTML页面被显示时自动激活。脚本语言先天就相当易于理解,因为它们只是作为HTML页面一部分的简单文本,当服务器收到要获取该页面的请求时,它们可以被快速加载。

       JavaScript是一种在Web浏览器不需要任何插件的情况下就可以得到支持的脚本语言。通常,你必须以JavaScript的某种最小公分泌形式来编程,以使得你的程序可以在所有的浏览器上运行。JavaScript的错误处理的调试只能一团糟来形容。

       这也表明,在Web浏览器内部使用的脚本语言实际上总是被用来解决特定类型的问题,主要是用来创建更丰富、更具有交互性的图形化用户界面。但是,脚本语言可以解决客户端编程所遇到的百分之八十的问题。

3、Java

       如果脚本语言可以解决客户端编程百分之八十的问题的话,那么剩下那百分只二十就交给Java来解决。Java是通过applet以及使用Java Web Start来进行客户端编程的。

       applet是只在Web浏览器中运行的小程序,它是作为网页的一部分自动下载的。当applet被激活时,它便开始执行一个程序,这正是它的优雅之处:它提供一种分发软件的方法,一旦用户需要客户端软件时,就自动从服务器把客户端软件分发给用户。用户获取最新版本的客户端软件时不会产生错误,而且也不需要很麻烦的重新安装过程。

4、备选方案

        Java applet没有达到它所吹嘘的境界。因为人们期望它们最终解决严峻的客户端可编程性问题,从而提高基于互联网的应用的可响应性,同时降低它们对带宽的需求。尽管如此,applet和Java Web Start应用在某些情况下仍旧很有价值。

       在“图形化用户界面”一章中,我们将看到一种折中的新技术,Macromedia的Flex。它允许你创建基于Flash的与applet相当的应用。因为Flash Player在超过98%的Web浏览器上都可以用。因此他被认为是事实上已被接受的标准。ActionScript语言是基于ECMAScript的,因此我们对它应该很首席,但是Flex使得我们在编程时无需担心浏览器相关性,因此,它远比JavaScript要吸引人得多。对于客户端编程而言,这是一种值得考虑的备选方案

5、.NET和C#

      微软以.NET平台和C#编程语言的形式推出了与Java全面竞争的对手。.NET平台大致相当于Java虚拟机JVM和Java类库,而C#毫无疑问与Java有类似之处。它们可以看得到Java在什么地方做的好没在什么地方做得还不够好,然后基于此去构建,并要具备Java不具备的优点。

6、Internet与Intranet

       Web是最常用的解决客户/服务器问题的方案。当Web技术仅限用于特定公司的信息网络时,它就被称为Intranet(企业内部网)。Intranet比Internet提供了更高的安全性,因为可以物理地控制对公司内部服务器的访问。

    1.13.3服务器编程

        当提出对服务器的请求后,会发生什么呢?大部分时间,请求只是要求“给我发生一个文件”,之后浏览器会以某种适当的形式解释这个文件,例如将其作为HTML页面、图片、Java applet或脚本程序等来解释。利益汇总常见的情形是,当你要加入一个团体或下订单时,可能想在数据库中注册自己的名字,这将设计对数据库的修改。这些数据库请求必须通过服务器端的某些代码来处理,这就是所谓的服务器端编程。过去服务器端编程都是通过使用Perl、Python、C++或者其他某种语言所编写的CGI程序而实现的,但却造成了从此之后更加复杂的系统。其中就包括基于Java的Web服务器,它让你用Java编写被称为servlet的程序来实现服务器端编程。serclet及其衍生物JSP,是许多开发网站的公司迁移到Java上的两个主要的原因,尤其是因为它们消除了处理具有不同能力的浏览器所遇到的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值