zoukankan      html  css  js  c++  java
  • Java编程思想:第1章 对象导论

    1.1 抽象过程

    所有语言都是抽象的,但是抽象的类型质量决定了解决问题的复杂度

    A.针对机器模型建模

    ------------------------------------------------------------------------------------------------------------------------------------------------

    最底层的  汇编是对底层机器轻微抽象,基于底层机器

    命令式语言 如FORTRAN/BASIC/C是对汇编的抽象,但仍基于底层机器结构,基本元素是基于机器模型[解空间]的,

          所以必须建立起与问题模型[问题空间]的关联,很费力且难以维护

    ------------------------------------------------------------------------------------------------------------------------------------------------

    B.针对待解问题建模

    ------------------------------------------------------------------------------------------------------------------------------------------------

    早期面向对象 如LISP/APL是特定类型问题元素抽象,对特定问题解决起来很好,超出范围则无能为力

    为解决早期面向对象的问题,面向对象向程序员提供了一种工具,这个工具可以用来表示问题空间中的元素,

    使程序员可以通过添加新类型对象使之适用于新的某个特定问题

    面向对象语言的基本元素就是问题空间的元素.所以面向对象程序就是描述问题模型的,所以OOP是根据问题描述问题,而不是根据运行程序的计算机描述问题

    但OOP与计算机还是有联系的:每个对象相当于一个微型计算机(一个命令式程序)

    C.总结一个成熟(纯粹)的OOP语言应该具有5种特性:

      1>万物皆对象:问题空间的任何概念化构建都可以抽取成一个对象

      2>程序是对象的集合,通过发送消息告知彼此需要做的

      3>每个对象都有自己的由其它对象构成的存储:对象中包含其它对象

      4>每个对象都有自己的类型,区别在于可以发送什么消息

      5>同一类型所有对象可以接受同样消息:同一类型包含了继承实现(多态)

    1.2每个对象都有一个接口(确定该对象可以发出的请求)

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

    如内置的浮点型也是具有相同特性和行为的集合,差别在于我们可以创建新的类型,

    而不再局限于使用仅有的一些内置表示机器存储单元的数据类型

    那么如何让我们的类型创建出来的对象"有用"?

    必须有某种方式产生对对象的请求,是对象可以完成各种任务,每个对象都可以满足一些请求,这些请求在接口中定义,

    决定接口的就是类型.

    接口定义了某一特定对象所能发出的请求,但是程序中必须有满足这些请求的代码,这些代码与隐藏的数据一起构成了实现。

    从过程型编程观点来看调用方法并不复杂

    1.3每个对象都提供服务

    将每个对象看成是一个服务提供者是一个伟大的简化工具

    1.从设计对象角度出发,先问自己 该对象像什么样子?能提供哪些服务?需要拥有哪些对象才能履行它的义务?

      最终我们就能知道如何将问题分解成对象。

    2.提高对象的内聚性:高内聚要求对象的各部分"组合的很好" 在良好的OOP设计中每个对象都可以很好的完成一项任务,

      但是它并不试图做更多的事情

    1.4被隐藏的具体实现
    在任何相互关系中,关系所涉及到的各方都遵循一个边界是非常重要的。

    访问控制的一个作用是使得客户端程序员无法触及他们不应该触及的部分,这些部分对数据类型的内部操作是必须的,但并不是用户解决问题

    所需接口的一部分。另一个作用是允许类的设计者改变类的工作方式,而不用担心会影响到客户端程序员。

    利用public,[default],protected,private来明确被定义的部分可以由谁来访问

    1.5复用具体实现

    最简单的复用就是创建一个类的实例对象,还有用它组成新的类。

    组合:强关联性,一方消亡另一方也消亡,如:人死了,心脏也没用了

    聚合:弱关联性,           如:人死了,电脑还在

    1.6继承

    对象的观念本身就是十分方便的工具,使用它我们可以把概念转变成类,由属性数据和行为方法构成。

    但是如果有多个类似对象,如:可回收垃圾和不可回收垃圾,它们有共同点也有很多不同点,我们就必须得重新创建它

    这是非常麻烦的。

    我们的想法是在现有类的基础上,复制然后通过添加和修改已有类的副本来创建新类,这样就好多了。

    此时我们就需要用"基类--->导出类"的模式来定义一个基类以及若干导出类,用以实现上述类似类的创建。

    这种模式就是继承

    类型不单单是描述了作用于某种对象集合上的约束条件,同时还有与其它类型之间的关系(层次结构)。

    以同样术语将解决方案转换成问题是大有好处的,我们可以用真实世界里的关系和描述以相同的思维来实现解决方案,

    这样从真实系统过渡到代码系统比面向过程实在是方便太多了。

    继承现有类型时就已经创造了新类型,它不仅包含了现有类型的所有成员(虽然private成员不可访问),更重要的是它复制了基类的接口。

    所以可发给现有类型的消息也可以发送给导出类型,由于通过发送给类的消息的类型可以知道类的类型,所以导出类与基类具有相同的类型

    如果仅仅是做一下继承,而不做其他操作是没有什么意义的。

    使得扩展类与基类之间产生差异有2种方式:

    1.在扩展类里添加新的方法

    2.覆盖基类已有方法,表明我有相同的接口,但是我想干点不一样的

    理想方式是使用第二种方法,具有完全相同的接口使得我们可以用扩展类完全替换基类,纯粹替代,称之为替代原则。这种情况就是"is-a"关系

    如果扩展类里定义了新的方法,新类型虽然还可以替代基类,但是并不完美,因为基类无法访问添加的新接口。这种情况就是"is-like-a"关系

    1.7 伴随多态的可互换对象

    在处理层次结构时,经常把一个对象当做其基类对象来处理,这样的代码不会受添加新类型影响(用于处理新情况)

    对扩展开放,对修改关闭,这种能力可以极大的改善设计,降低维护代价

    那么如何让基类执行正确的代码(调用我们想让调用的某子类的实现)呢?

    传统语言:非面向对象语言的'编译器函数调用'会产生前期绑定,即把调用与函数名对应的代码绝对地址绑定。

    OOP语言:程序直到运行时才知道确定代码地址,后期绑定。(第八章详细解说)

    java 默认方式就是动态绑定,c++需要用关键字virtual来指明是动态绑定

    void doSomething(Shape shape){

      ...

      shape.draw();

      ...

    }

    我们可以传入任意Shape基类的子类对象给doSomething方法,这种代码好处在于我不需要知道你具体是哪种类型,

    "只要你是Shape我知道你可以draw(),那就去draw()吧,注意细节正确即可."

    正是因为多态才使得事情可以在不知道具体类型的情况下,被正确的执行

    这种代码也称为向上转型

    1.8 单根继承结构

    单根继承确保所有的对象都具有某些功能(Object里)

    如参数传递得到极大简化,无需构建自己的继承体系来达成操作没有层次联系的类

    还使得垃圾回收机制变得容易很多,对系统级操作(如异常处理)也非常重要

    1.9容器

    我们利用容器(集合)来存储和管理一组不一定知道数量的对象,java提供了多种满足不同需要的容器,

    如List用于存储序列,Map用于存储关联数组,Set用于存储不重复对象,还有队列、树、堆栈等更多构件。

    从设计角度出发,我们只需要一个可以被操作的序列即可,用单一类型容器即可解决问题,为什么还要设计不同种类的容器呢?

    1)不同容器提供了不同的接口和外部行为,不同情况下某种容器可能比通用容器解决问题要灵活的多。

    2)不同容器针对某些操作有不同的效率

    1.9.1参数化类型

      在Java SE5之前,容器里存储的对象都是Object,单根继承使得任何对象都可以放入容器中(基本类型从出现了包装类之后也可了)

      存放时候具体类型向上转型成Object,是安全的,但是在取的时候,Object向下转型成具体类型时候是不安全的,我们希望最好可以

      有种方式记住这些对象是什么类型,这样才能知道应该如何向下转型。

      因此创建一种知道自己应该保存什么类型的容器,从而避免向下转型,这就是参数化类型。

      利用参数化类型(Java称之为泛型)我们可以定制只接受特定类型的容器。

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

    1.10对象的创建和生命周期

       1)C++式: 可以让对象在栈中创建(静态存储区),追求最大执行速度,但是牺牲了灵活性,必须在编程时就明确对象的数量、生命周期和类型。

       2)Java式动态内存分配方式: 对象在堆(heap)的内存池中动态创建。总是假定对象变得复杂,查找和释放空间的开销不会对对象的创建造成重大冲击。

       在需要时直接在堆中创建,由于存储空间是在运行时动态管理的,所以需要大量时间在堆中分配存储空间,可能会远大于在栈中创建时间。

        栈中创建只需要上下移动指针即可创建或释放存储空间,由于是栈,编译器就完全知道对象的存活时间并可以自动销毁,但如果是堆上创建,C++方式必须

      在编程时就确定何时及如何销毁,处理不当就会产生内存泄露。而java的垃圾回收机制,可以自动查找并回收不再使用的对象,减少了编程时必须考虑的内容,

      配合单根继承结构Object,使得java编程比C++简单得多。

    1.11 异常处理:处理错误

    异常是一种对象,它从出错地点抛出,并被特定的异常处理器捕获,异常处理就像是与程序正常执行路径并行的,在错误发生时执行的另一条路径,因为它是另一条

    完全分离的执行路径,所以它不会干扰正常代码。异常不能被忽略,必须要保证它一定可以被处理,提供了从错误状态进行可靠恢复的途径。可以让程序更健壮。

    java的异常处理非常引人注目,因为它内置了一次处理,并通过编译强制你使用它。而其它很多语言的异常处理依赖于程序员自身的警惕性。

    异常不是面向对象的特性,面向过程语言也有。但是在OOP中,它是一个对象。

    1.12 并发编程

    最初的程序员通过编写硬件中断来处理,尽管可以解决问题,但是这么做既费时又费力。大部分情况我们利用并发是想把问题切分成多个可独立运行的部分,从而提高

    程序的相应能力,最常见的就是用户界面。

    通常来说并发使用看起来相当简单,但有一个隐患:共享资源。 当多个线程操作同一资源时,需要某个任务锁定资源,执行完成后释放给其他任务使用。

    java的并发是内置语言中的,Java SE5添加了很多额外lib支持。

    1.13 Java与Internet

    Java促使编程语言向前迈进了革命性一步:不仅是在解决传统单机程序设计问题非常有用,同样重要的在于解决了在万维网上的程序设计问题!

    1.13.1 Web 是什么

      1.CS架构技术

      信息存储池、用于分发信息的软件,以及信息和软件驻留的机器或集群被称为服务器,用户机器上的软件与服务器进行通信,以获取处理信息,然后显示在

      客户机上。如果客户端软件发生变化,就必须重新编译调试安装到客户机上,非常复杂和费力。难以开发和不能复用。

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

      Web实际上就是一个巨型的客户、服务器系统,所有的客户端和服务器都在同一个网络里,拥有"天然"的环境。

      Web浏览器前进了一大步:使得一段信息不经过修改就可以在任意计算机上显示。但最初浏览器只是用于显示,功能太过单一,且有需要用编程实现的任务(即使

      是简单的页面样式改变,隐藏)都得发回给服务器完成,这非常花费时间。解决问题的途径一方面是增强动画和视频的播放能力,另一方面就是"客户端编程"。

    1.13.2 客户端编程

      Web最初的"服务器-浏览器"设计是为了能提供交互性的内容,但是交互性完全由服务器提供,浏览器显示。一般来说表单提交动作通过所有Web服务器都有的
      CGI来处理。有很多网站都是用CGI构建,CGI几乎也可以做任何事情,但是它可能会变得非常复杂和难维护。

      Web输入表单验证的过程: 按下提交按钮之后,数据发回给服务器验证,服务器启动一个CGI程序来检查、发现错误,并把错误返回给你。这种过程不仅很慢,而且很不优雅。而客户端编程就可以解决此类问题,它可以使得浏览器完成一些他们可以完成的工作,使得返回给用户的结果更加快捷,且网站更具交互性。缺点在于必须按照客户端编程方式编程和解决出现的各种问题。

    以下是客户端编程方法概述:

      1.插件

      通过给浏览器安装插件来添加新功能。插件对客户端编程的价值在于:允许专家级程序员不需经过浏览器厂商允许就可以开发扩展,并添加到浏览器中。

      2.脚本语言

      通过把脚本语言的源代码(客户端程序源码)直接嵌入到html中,解释这种脚本语言的插件在html页面被显示时自动激活,优点是易于理解且可以被快速加载。缺点是客户端代码暴露,但一般没什么大问题。可知在web浏览器内部使用脚本语言,主要是为了创建更丰富、更具有交互性的图形化用户界面。80%的客户端编程问题是可以用脚本语言完成的,优先考虑脚本语言。

      3.Java

      java applet可以解决客户端编程中脚本语言完成不了的功能(已经过时)。

      4.备选方案

      由于Java applet对JRE的要求使得它在当初并没有压倒性优势,而Flash实际上已经掌控了市场。

      5. .Net 和 C#

      6.Internet与Intranet

      Web可以很好的解决CS架构的问题,Internet与Intranet问题都可以使用Web来解决,Intranet是Internet的一个子集。

    1.13.3服务器端编程

      过去,服务器编程通常是采用Perl,Python,C++或其他语言编写的CGI程序实现,但却造成了之后更加复杂的系统。

      Java采用servlet实现服务端编程。Servlet及衍生物JSP消除了处理具有不同能力浏览器时所遇到的问题。

    1.14总结

      面向过程:看起来就像是数据定义和函数调用,想要明白程序含义,需要构建一些模型,做深入理解才行。

      OOP:用来表示问题空间的对象,以及发送给这些对象用来表示在该空间内行为的消息。

  • 相关阅读:
    流程控制之if判断
    各种运算符
    输入和输出
    垃圾回收机制(详细)
    3/5 作业
    3/4 作业
    数据类型
    变量
    Checkout 显示 URL /../../.. 不存在
    Tomcat8 访问 manager App 失败
  • 原文地址:https://www.cnblogs.com/superzhao/p/4599236.html
Copyright © 2011-2022 走看看