对象导论 1.10 对象的创建和生命周期

1.10 对象的创建和生命周期

     在使用对象时,最关键的问题之一便是它们的生成和销毁方式。

     每个对象为了生存都需要资源,尤其是内存。当我们不在需要一个对象时,它必须被清理掉,使其占有的资源可以被释放和重用。在相对简单的编程情况下,怎样清理对象看起来似乎不是什么挑战:你创建了对象,根据需要使用它,然后它应该被销毁。然而很可能遇到相对复杂的情况。

     对象的数据位于何处?怎样控制对象的生命周期?C++认为效率控制是最重要的议题,所以给程序员提供了选择的权利。为了追求最大的执行 速度,对象的存储空间和生命周期可以在编写程序时确定,这可以通过讲对象置于堆栈(它们有时被称为自动变量(automatic variable)或限域变量(scoped variable))或静态存储区域内来实现。这种方式将存储空间分配和释放置于游仙考虑的位置,某些情况下这样控制非常有价值。但是,牺牲了灵活性,因为必须在编写程序时知道对象切换的数量、生命周期和类型。如果试图解决更一般化的问题,例如计算机辅助设计、仓储管理或者空中交通控制,这种方式就显得过于受限了。

      第二种方式是在被称为堆(heap)的内存池中动态创建对象。这种方式中,直到运行时才知道需要多少对象,它们的生命周期如何,以及它们的具体类型是什么。这些问题的答案只能在程序运行时相关代码被执行到的那一刻才能确定。如果需要一个新对象,可以在需要的时刻直接在堆中创建。因为存储空间是在运行时,被动态管理的,所以需要大量的时间在堆中分配空间,这可能要远远大于在堆栈中创建存储空间的时间。在对战中创建存储空间和释放存储空间通常各需要一条汇编指令即可,分别对应将栈顶指针向上移动。创建堆存储空间的时间依赖于存储机制的设计。

      动态方式有这样一个一般性的逻辑假设:对象趋向于变得复杂,所以查钊和释放存储空间的开销不会对对象的创建造成重大冲击。动态方式所带来的更大的灵活性正是解决一般化编程问题的要点所在。

      Java完全采用了动态内存分配方式。每当要创建新对象时,就要使用new关键字来构建此对象的动态实例。

      还有一个议题,就是对象生性周期。对于允许在堆栈上创建对象的语言,编译器可以确定对象存活的时间,并可以自动销毁它。然而,如果是在堆上创建对象,编译器就会对它的生命周期一无所知。在像C++这样的语言中,必须通过编程方式来确定何时销毁对象,这可能会因为不能正确处理而导致内存泄露(这在C++程序中是常见的问题)。Java提供了被称为“ 垃圾回收器 ”的机制,它可以自动发现对象何时不再被使用,并继而销毁它。垃圾回收器非常有用,因为它减少了所必需的考虑的议题和必须编写的代码。更重要的是,垃圾回收器提供了更高层的保障,可以避免暗藏的内存泄露问题,这个问题已经使许多C++项目折戟沉沙。

      Java的垃圾回收器被设计用来处理内存释放问题(尽管它不包括清理对象的其它方面)。垃圾回收器“ 知道 ”对象何时不再被使用,并自动释放对象占用内存。这一点同所有对象都是继承自单根基类Object 以及只能以一种方式创建对象(在堆上创建)这两个特性结合起来,使得Java编程的过程较之用C++编程要简单的多,所要作出的决策和要克服的障碍也要少得多。

1.11 异常处理:处理错误

        自从编程语言问世以来,错误处理就适中是最困难的问题之一。因为设计一个良好的错误处理机制非常困难,所以许多语言直接略去这个问题,将其交给程序库设计者处理,而这些设计者也只是提出了一些不彻底的方法,这些方法可用于许多很容易就可以绕过此问题的场合,而且其解决方式通常也只是忽略此问题。大多数错误处理机制的狐妖问题在于,它们都依赖于程序员自身的警惕性,这种警惕性来源于一种共同的约定,而不是编程语言所强制的。如果程序员不够警惕——通常是因为他们太忙,这些机制就很容易被忽视。

        异常处理将错误处理直接置于编程语言中,有时甚至置于操作系统中。异常是一种对象,它从出错地点被“ 抛出 ”,并被专门设计用来处理特定类型错误的响应的异常处理器“ 捕获 ”。异常处理就像是与程序正常执行路径并行的、在错误发生时执行的另一种路径。

        因为它是另一条完全分离的执行路径,所以它不会干扰正常的执行代码。这往往使得代码编写变得简单,因为不需要被迫定期检查错误。此外,被抛出的异常不像方法返回的错误值和方法设置的用来表示错误条件的标志位那样可以被忽略。异常不能被忽略,所以它保证一定会在某处得到处理。最后需要指出的是:异常提供了一种从错误状况进行可靠回复的途径。现在不再是只能突出程序,你可以经常进行校正,并回复程序的执行,这些都有助于编写出更健壮的程序。

        Java的异常处理在众多的编程语言中格外引人注目,因为Java一开始就内置了异常处理,而且强制你必须使用它。它是唯一可接受的错误报告方式。如果没有编写正确的处理异常的代码,那么就会得到一条编译时的出错消息。这种有保障的一致性优势会是的错误处理非常容易。

       值得注意的是,异常处理不是面向对象的特征——尽管在面向对象语言中异常常被表示成为一个对象。异常处理在面向对象语言出现之前就已经存在了。

  1.12 并发编程

       在计算机编程中有一个基本概念,就是在同一时刻处理多个任务的思想。许多程序设计问题都要求,程序能够停下正在做的工作,转而处理某个其他问题,然后再返回主进程。有许多方法可以实现这个目的。最初,程序员们用所掌握的有关机器底层的知识来编写终端服务程序,主进程的挂起是通过硬件中断来触发的。尽管这么做可以解决问题,但是其难度太大,而且不能移植,所以使得将程序一直到新型号的机器上时,既费时又费力。

       有时中断对于处理时间性强的任务是必须的,但是对于大量的其他问题,我们只是想把问题切分成多个可独立运行的部分(任务),从而提高程序的响应能力。在程序中,这些彼此独立运行的部分称之为线程,上述概念成为“ 并发 ”。并发最常见的例子就是用户界面。通过适用任务,用户可以在揿下按钮后快速得到一个响应,而不用被迫等到程序完成当前任务为止。

       通常,线程只是一种为单一处理器分配执行时间的手段。但是如果操作系统支持多处理器,那么每个任务都可以被指派给不同的处理器,并且它们是在真正地并行执行。在语言级别上,多线程所带来的便利之一便是程序员不用再操心机器上时多个处理器还是只有一个处理器。由于程序在逻辑上被分为线程,所以如果机器拥有多个处理器,那么程序不需要特殊调整也能也能执行的更快。

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

       Java的并发是内置于语言中的,Java SE5已经增添了大量额外的库支持。

 1.13 Java与Internet

      如果Java仅仅只是众多的程序设计语言的一种,你可能会问:为什么它如此重要?为什么它促使计算机编程语言向前迈进了革命性的一步?如果从传统的程序设计观点看,问题答案似乎不太明显。尽管Java对于解决传统的单机程序设计问题非常有用,但同样重要的是,它解决了在万维网(WWW)上的程序设计问题。

      1.13.1 Web是什么

        1.客户端/服务器系统的核心思想是:系统具有一个中央信息存储池(central repository of information),用来存储某种数据,它通常存在于数据库中,你可以根据需要将它分发给某些人员或机器集群。总之,信息存储吃、用于分发信息的软件以及信息与软件所驻留的机器或机群总称为服务器。驻留在用户机器上的软件与服务器进行通信,以获取信息、处理信息,然后将它们显示在被称为客户机的用户机上。

        2.Web实际上就是一个矩形客户/服务器系统,但稍微差一点,因为所有的服务器和客户机都同时共存于同一个网络中。

          最初只有一种很简单的单项进程:你对某个服务器产生一个请求,然后它返回给你一个文件,你的机器(也就是客户机)上的留恋其软件根据本地机器的格式来解读这个文件。但是很快人们就希望能够做的更多,而不仅仅是从服务器传回页面。人们希望实现完整的客户/服务器能力,使得客户可以将信息反馈给服务器。

         Web浏览器向前跨进了一大步,它包含了这样的概念:一端信息不经修改就可以在任意型号的计算机上显示。

     1.13.2 客户端编程

         Web最初的“ 服务器-浏览器 ” 设计是为了能够提供交互性的内容,但是其交互性完全由服务器提供。服务器产生静态页面,提供给只能解释并显示他们的客户端浏览器。基本的HTML(HyperText Markup Language,超文本标记语言)包含有简单的数据收集机制:文本输入框、复选框、单选框、列表和下拉列表以及按钮——它只能被编程来实现复位表单上的数据或提交表单上的数据给服务器。这种提交动作通过所有的Web服务器都提供的通用网关接口(common gateway interface,CGI)传递。提交内容会告诉CGI应该如何处理它。最长将的动作就是运行一个在服务器中常被命名为“ cgi-bin ”的目录下的一个程序。(当点击了网页上的按钮时,如果观察浏览器窗口顶部的地址,有时候可以看见“ cgi-bin ”  字样混迹在一串荣昌和不知所云的字符串中。)几乎所有的语言都可以用来编写这些程序,Perl已经成为最常见的选择,因为它被设计用来处理文本,并且是解释型语言,因此无论服务器的处理器和操作系统如何,它都是原装。然而,Python(www.python.org)已对其产生了重大的冲击,因为它更强大且更简单。

       当今许多有影响力的网站完全构件与CGI之上的,实际上你几乎可以通过CGI做任何事。然而,构件与CGI程序之上的网站可能会迅速变得过于复杂而难以维护,并同时产生响应时间过长的问题。CGI程序的响应时间依赖于所必须发送的数据量的大小,以及服务器和Internet的负载。(此外,启动CGI程序也相当慢。)Web的最初设计者们并没有预见到网络带宽被人们开发的各种应用迅速耗尽。例如,任何形式的动态图形处理几乎都不可能连贯地执行,因为图形交互格式(graphic interchange format,GIF)的文件必须在服务器端创建每一个图形版本,并发送给客户端。再比如,你肯定经历过对Web输入表单进行数据验证的过程:你按下网页上的提交按钮;数据翻倍发送回服务器;服务器启动一个CGI程序来检查、发现错误,并将错误组装为一个HTML页面,然后将这个页面发回给你;之后你必须回退一个页面,然后重新再试。这个过程不仅很慢,而且不太优雅。

      问题解决的方法就是客户端编程。

      在使用原始的静态HTML方式的情况下,它们只是闲在那里,等服务器送来下一个页面。客户端编程意味着Web浏览器能用来执行任何它可以完成的工作,使得返回给用户的结果更加迅捷,而且使得你的网站更加具有交互性。

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

      对客户端编程的问题和方法概述:

     1.插件

        客户端编程所迈出的最重要的一步就是插件(plug-in)的开发。通过这种方式,程序员可以下载一端代码,并将其插入到浏览器中适当的位置,以此来为浏览器添加新功能。它高数浏览器:从现在开始,你可以采取这个行动了(只需要下载一次查件即可)。某些更快更强大的行为都是通过插件添加到服务器中的。但是编写插件并不是件轻松的事,也不是构件某特定网站的过程中所需要做的事情。插件对于客户端编程的价值在于:它允许专家级的程序员不需经过浏览器生产厂商的许可,就可以开发某种语言扩展,并将它们添加到服务器中。因此,插件提供了一个“ 后门 ”,使得可以创建新的客户端编程语言(但是并不是所有的客户端编程语言都是以插件的形式实现的)。

     2.脚本语言

       插件引发了浏览器脚本语言(scripting language)的开发。通过适用某种脚本语言,你可以将客户端程序的源代码直接嵌入到HTML页面中,解释这种语言的插件在HTML页面被显示时自动激活。脚本语言先天就相当于易于理解,因为它们只是作为HTML页面一部分的简单文本,当服务器收到要获取该页面的请求时,它们可以被快速加载。此方法的确定是代码会暴露给任何人去浏览(或窃取)。但是,通常不会使用脚本语言去做相当复杂的事情,所以这个缺点并不严重。

    如果你期望有一种脚本语言在Web浏览器不需要任何插件的情况下就可以得到支持,那它非JavaScript莫属(它与Java之间只存在表面上的相似,要想使用它,你必须在额外的学习去县上攀爬。它之所以这样命名只是因为想感伤Java潮流)。遗憾的是,大多数的Web浏览器最初都是以彼此相异的方式来实现对JavaScript的支持的,这种差异甚至存在于同一种浏览器的不同版本之间。

   3. Net和Java

     .Net平台大致相当于Java虚拟机(JVM,即执行Java程序的软件平台)和Java类库,C#毫无疑问与Java有类似之处。这当然是微软在编程语言与编程环境这块竞技厂商所做出的的最出色的成果。

     淡然,他们有相当大的有力条件:他们可以看到Java在什么方面做得好,在什么方面做得还不够好,然后基于此去构建,并要具备Java不具备的特点。这是自从Java出现依赖,Java所碰到的真正的竞争。因此,Sun的Java设计者们已经认真仔细的研究了C#,以及为什么程序员们可能会转而使用它,然后通过在Java SES中对Java做出的重大改进而做出了回应。

     目前,.Net主要受到攻击的地方和人们所关心的重要的问题就是,微软是否会允许将它完全移植到其他平台上。微软宣城这么做没有问题,而且Mono项目已经有了一个在Linux上运行的.Net的部分实现;但是,在该实现完成及微软不会排斥其中的任何部分之前,.Net作为一种跨平台的解决方案仍旧是异常高风险的赌博。 

   6. Internet 与 intranet

    当Web技术极限与特定公司的信息网络时,它就被称为intranet(企业内部网)。intranet 比 Internet 提供了更高的安全性。因为可以物理地控制公司内部服务器的访问。

    因为在浏览器方式下,升级是透明的、自动的(Java Web Start也是解决此问题的方式之一)。如果你身处这样的intranet之中,那么最有意义的方式就是选择一条能够使现有代码库的最短的捷径,而不是用一种性语言重新编写你的代码。

   1.13.3 服务器端编程

   前面的讨论忽略了服务器点编程的话题,他是Java已经取得巨大成功的原因之一。

   过去服务器端编程都是通过Perl、Python、C++或其他某种语言编写CGI程序而实现的,但却造成了从此之后更加复杂的系统。其中就包括基于Java的Web服务器,它让你用Java编写成为servlet的程序来实现服务端编程。servlet及其衍生物JSP,是许多开发网站的公司迁移到Java上的两个主要原因,尤其是因为他们消除了处理具有不同能力的浏览器时所遇到的问题。服务器端编程的话题在《企业Java编程思想》(Thinking in Enterprise Java)一书中有所论述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值