首页 » 科技 » 果壳中的Java —— Chapter 1

果壳中的Java —— Chapter 1

David Flanagan 是一个醉心与java写作的计算机程序员。《java in a nutshell》与《java examples in a nutshell》属于姊妹篇。本书是一本java的速查手册。 对于每一个初学java的人,我觉得这本书都会给你带来帮助。

Chapter 1

1.Java起步

主题:

为什么Java那么有趣呢?

A Simple Example

 

 

当Java在95年下半年被发明使用,它迅速地风靡Internent。

Java1.1在97年上半年发布,它把Java解释器(Interpreter)的速度缩短了一半,还添加了很多重要的新功能。随着新功能的加入,诸如对数据库访问,远程对象,对象构件模型,国际化,打印,加密,数字签名等技术的额外API(应用程序接口)支持,Java志在占领整个编程世界。

但不管如何对Java和1.1版新功能进行大肆宣传,有一点要谨记的是,Java在本质上只是一种编程语言,就像其他千千万万的语言一样,API就像是类库(class libraries),和别的语言无甚区别。Java真正有意思的地方,也是宣传广告的主要内容,是它所拥有的一些重要特性,让它成为在90年代后期,一种在大量网络连接通信而差异化的世界中理想的编程语言。在余下的章节中我们会讨论Java的有趣特性,并展示些简单的Java代码。在chapter 4,Java的新特点中探索了Java 1.1的API新功能。

 

1.1为什么Java那么有意思?

 

在早期的论文中,Sun如此形容Java:

Java:一种简单的,面向对象的,分布式,解释型,健壮,安全,架构中性(architecture neutral),可移植的(portable),性能优越,多线程的动态语言。

 

Sun承认这段文字未免过于冗长拖沓,但事实上这段话很恰当的描述了Java具有的特点。为了更好理解为什么Java那么有意思,我们来细细讨论一下这个冗长的句子背后所包含的Java语言特性。

 

面向对象

Java是一种面向对象的编程语言。作为一个程序员,这意味着你专注在应用程序的数据(Data)和对这些数据进行操作的方法(Method),而不是严格从过程(procedure)层面思考编程。如果你适应于基于过程(procedure based)的C编程,那么在使用Java的时候,你会发现你得尝试入阁去改变你设计程序的习惯。一旦你看见Java的范例如何强大的时候,你会很快适应他的。

 

作为一个面向对象系统,类是以数据和对数据进行操作的方法的集合。结合在一起,数据和方法描述了对象(Object)的状态和行为。类是有层次性的,所以子类可以继承父类的行为。类层次结构总会有一个根类(root class),这是一个具有普遍行为的类。

 

Java具有大量的类的集合,以包(package)的形式组织放置,你可以在程序中使用他们。例如,Java提供了图形用户见面的类(the java.awt package),控制输入输出的类(the java.io package),支持网络功能的类 (the java.net package)。Object类 (in the java.lang package) 是Java类层次结构的根。

 

不像C++,Java从一开始就是作为面向对象语言设计的。大部分Java的内容都是对象。原始数据类型如数字,字符,boolean型是唯一的例外。字符串String以对象的形式出现在Java中,正如别的重要的语言像线程一样构造(language constructs like threads?)。类是Java中编译和之星的基本单位,所有的Java程序都是类。

尽管Java被设计得和C++很像,你能发现Java去除了许多C++中复杂的东西。如果你是C++程序员,你有必要学习Java中面向对象的构造(object-oriented construct)。尽管语法和C++相似,但所表示的行为却不一定同样相似。如果希望了解对Java面向对象特性的描述,请看chapter 3,Java中的类和对象。

解释型

Java是一种解释型的语言:Java编译器生成字节码来让Java虚拟机(JVM)运行,而不是直接生成本地机器码。为了运行一个Java程序,你要用Java解释器去执行这些编译过的字节码。因为Java的字节码是依赖于平台的,Java程序可以在任何平台上运行,只要上面装了Java虚拟机。

在一个解释环境中,那些程序开发的标准过程基本都不存在。例如,Java有程序链接(link phase)阶段,这是装载新类进环境中的唯一过程了,而这是在程序执行时根据需要进行逐步装载(incremental)的轻量级(lightweight)过程。与之对比的是C++和C等语言的那种在缓慢而笨拙的“编译——链接——运行”周期。

架构中性和可移植性

因为Java程序是编译成架构中性的的字节码格式的,一个Java应用程序可以在任何系统上运行,只要系统实现了Java虚拟机。这一特性对于在因特网或者别的多元化的网络的应用程序来说特别重要。架构中性方案的应用要远远超出基于网络的应用程序这一范围。作为一个当今市场下的应用程序开发者,你可能会要开发多个版本的应用程序,在PC,Mac或者UNIX工作站上运行。面对多种操作系统的使用:UNIX,win95,winNT,还有Macintosh,要开发所有不同平台对应的软件变得越来越困难。如果你用Java写应用程序,那你可以在所有平台运行。

Java是解释型的,Java制定的标准,Java编译后的字节码格式,构成了可移植性的大部分要素。但是Java走得更远:它能确保语言具体细节中没有依赖于具体实现的(making sure that there are no "implementation-dependent" aspects of the language specification)。例如,Java显式地划分了每个原始数据类型所占空间的大小,和对应的算术运算。这个和C不同,例如,C的int类型可以是16位,32位或者64位的,取决于不同的平台。

当然,在Java可以写不可移植的程序,要避免用Java API写出“依赖平台实现”的代码,而写出“纯净的”Java程序还是相对简单的。Sun的“100%纯净Java”("100% Pure Java")项目帮助开发者确认他们的代码是可移植的。程序员只需要花少量的经历就可以回避不可移植的陷阱而写出复合Sun广告语的代码来“Write one, run anaywhere.”

动态和分布式的

Java是一种动态的语言。任何一个Java类随时可以装载进运行中的Java解释器中。这个动态加载的类可以被动态地实例化(根据需要随时被实例化)。本地代码库同样可以动态加载。类在Java中变现为Class类,你可以在运行时随时获得类的信息。额外介绍Reflection API将在chapter 12给出。

Java同样被成为分布式语言,这意味着,简单的说,它提供了一种对网络的高层次支持。例如java.net package中的URL类和OArelated类,使得获取远程文件和资源变得和在读写本地文件一样容易。类似的,在Java1.1中,远程方法调用(RMI)API允许Java程序调用远程的Java对象方法,就像调用本地的一样。(Java还提供了低层次的网络支持,包括数据包,和基于流的socket连接)

这种分布性和动态类载入能力相结合,着实让Java大放异彩。这些特性相结合,让Java可以下载并运行因特网上的代码。(在下面我们会看到,Java实现了强健的安全措施来保证代码的执行是安全的)因此Web浏览器可以下载运行Java小程序(applet)。应用场景可以变得更复杂些。试着想象一个多媒体的文字处理器用Java写出来了,当程序被要求显式某个之前没有遇到过的类型的数据,程序会动态地下载那个解释这种类型需要的类,然后又下载了一个类用来把数据显示在复合文档中(这个类可能是Bean)。这样的程序可以利用分布式的网络资源,并动态发展完善以满足用户需求。

简单

Java是一种简单的语言。Java设计者试图创造一种语言让程序员可以快速学习,所以语言的构造要素被维持在一个较低的水平。另一个设计目标是把语言弄的很亲切熟悉,至少对大部分程序员应该如此——方便他们转移过来。如果你是一个C或者C++的程序员,你会发现Java使用了许多和C/C++同样的语言结构。

为了让语言保持小巧和亲切,Java设计者去除掉了C、C++中的好一部分特性。这些特性多是些会导致不良编程习惯的或者很少使用的。例如,Java不支持goto语句。但是它继续支持labelled break和continue语句还有异常处理。Java没有头文件,也没有C的预编译。因为Java是面向对象的,所以C的一些结构例如struct和union都被去除了。Java还去除了C++的操作符重载和多继承特性。

最重要的简化还是Java没有使用指针!指针是最容易导致C/C++程序漏洞的东西了。既然Java没有structures,数组和字符串是对象,那么指针就没有存在的意义了。Java为我们自动处理引用和废除对象。JAva还实现了自动资源回收,所以我们不需要担心内存管理的问题。所有这些让我们可以花更多的时间开发程序的功能。

如果这听起来像是Java是在切割C/C++,仅留下编程语言的内核。请且慢下这评论。我们会在第二章看到,“Java和C的区别”,事实上Java是一种功能完备,又非常优雅的语言。

健壮性/鲁棒性

Java是为高度可靠和健壮的程序设计所开发的编程语言。Java当然没有可能让软件质量保证这一行当失去存在的意义。用Java写出漏洞百出的程序还是有可能的。但是Java的确消除了好些类型的编程错误,让写出可靠的程序变得容易得多。

Java是一种强类型语言,允许扩展式的编译时潜在的类型不匹配错误检查。Java比C++的强类型要更进一步,因为C++继承了C中的编译时宽松处理(laxities),特别是在函数声明方面。Java要求显示的方法声明,而不支持C风格的隐式声明。这些严苛的要求保证了编译器可以捕捉方法调用的错误,生成的程序更可靠。

一个让Java变得简单的原因是Java去除了指针和指针运算。这个特性还减少了Java程序在退出关闭整个类时可能出现的指针相关的漏洞的可能。类似地,所有对字符串和数组的访问在运行时被检查来确保他们没有越界,消除越界导致的内存重写和数据损坏的问题。对象类型转换同样在运行时保证其合法性。最后也是很重要地,Java的自动资源回收防止了内存溢出和恶意漏洞和内存分配和重分配。

异常处理是另一个让Java变得更健壮的特性。异常像是一种异常情况时软件发出的信号例如“File not found”错误的发生。使用try/catch/finally语句,我们可以集中所有的的错误处理代码在一处,大大节哀离你人物画的错误处理和恢复。

安全性

Java最让人青睐的一个特点是:Java是一种安全的语言。因为Java的分布式特性,这点特别重要。如果没有了完全保证,我们就肯定不会愿意下载一段从不知道什么网站来的代码,而且还让它在我们的机子上运行。但是这正是大家在做的事情:天天下载Java applets!Java将安全完全融入设计,并提供几个不同层的安全控制以防范恶意代码。并允许用户自在地运行不信任代码(译者——未验证来源的代码),例如applet。

 

 

 

在最低层次上,安全性与健壮性是一个道儿的问题。我们可见,Java程序不可以伪造指针去访问内存,也不可以让数组溢出,更不能读取数组或者字符串越界的部分。这些特性是Java防范恶意代码的主要手段。禁止程序直接访问内存,那么整整一大类安全攻击都被彻底清除了。

第二层恶意代码防线是Java解释器,在进行不信任代码加载时,用到的字节码确认过程。这个确认步骤保证代码是格式优良的——不会上溢或者下溢栈或者含有非法字节码。如果这一步被跳过了话,未发现的损坏或者恶意嵌入的字节码可能会利用Java解释器在实现程序时的某弱点进行攻击。

最后,是一个可能的安全解决方案。通过附加一个数字签名到Java代码上,原始代码可以以一种通过加密保证安全、不可伪造的方法创建。如果你已经规定了你信任的组织或者个人,then code that bears the digital signature of that trusted entity is trusted, even when loaded over the network, and may be run without the restrictions of the sandbox model.(译者——这段话我看得懂意思,却不知道是他怎么这么说的,奇怪的语法- -b)


当然,安全并不是一个黑白分明的东西,就像一个程序从来不保证100%的没有bug,没有语言或者环境可以保证100%安全。但是前面说过的话,看起来Java为大部分程序提供了实践层面上的安全性(a practical level of security)!它预测和防范大部分过去用来让软件行为失常的技术,这是被安全专家和黑客都细细审查过了的。有些安全漏洞在早期的Java版本中被发现但是都马上被修补好了。可以预计未来发现的漏洞也会很快被修补好的:)

性能卓越

Java是一种解释型语言,所以不可能像C这样的编译型语言那么快。Java1.0是C速度的20分之1,Java1.1是1.0的两倍。但在你厌恶地举手放弃之前,你要意识到这个速度足以应付交互式,GUI(用户图形接口)或者基于网络的应用程序,这些程序总是闲置或者等待用户输入或者等待因特网的数据传过来。还有,在那些对速度要求很高的Java运行环境,例如进行字符串拼接和比较,都是用高效的本地码实现的(native code)。

最为一个深层次的性能提升,许多Java解释器可以在运行时使用“just in time”编译器,可以把字节码转换成机器码供特定的CPU运行。Java的字节码在设计时考虑过“just in time”编译器的,所以这个转换过程还是挺有效率的而且也能产出相当好的代码来。事实上,Sun生成字节码转换成机器码做得和原本C/C++做得一样好。如果你希望牺牲代码的可移植性来获得速度的话,你可以用C、C++写程序然后使用Java的native method作为这些native代码的接口。

当我们考虑性能,我们应该考虑Java在整个整个编程语言领域Java所处的位置。在领域的一端,是高级,全解释型的脚本语言例如Tcl和UNIX shell。这些语言适于原型开发而且是高度可移植的。但是很慢。在另一端是底层的编译语言例如C,C++。这些语言提供了高性能,但是存在可移植性和可靠性等问题。Java在这个领域的中间。。Java字节码的性能比高层次语言要快得多(即使是Perl),但是却保有这些语言的简洁性和可移植性。

 

多线程

在一个基于用户图形界面的的网络应用程序中,例如网页浏览器,很容易想象到好几种东西在同时进行着,不是吗?一个用户可以在听一段音频剪辑的同时滚动页面,而在后台浏览器还在下载着图像。Java是一种多线程语言,它能够支持多线程(有时候被称作轻量过程)同时执行多个任务。多线程的一个重要的优越之处在于它能够改善图形化应用程序与用户间的交互性能。

如果你已经尝试过在C/C++中开发进程的话,你就知道这件事情做起来有多困难!Java让线程编程变得简单得多,因为它为线程提供了内置的语言支持。java.lang package提供了线程类,支持开始,停止进程,设置进程优先级等等。在Java的语法中直接支持线程,有关键字“synchronized”。这个关键字使用方便,既可以标一段代码,也可以标整个方法,表示所标区域在同一时间只能有一个进程在访问。

虽然线程在C和C++中是“魔术师级别”的应用,它们在Java中使用起来却是寻常可见。因为Java让线程变得易于使用,Java的类库也在好几处用上了线程。例如,所有applet在调用动画的时候都会用到线程。类似地,Java不支持通过信号或中断发送公告来实现异步的、无独占(non-blocking)式I/O——你必须创建线程来抢占你所要使用的每一个I/O信道。


【本文翻译仅为外语学习及阅读目的,原文作者个人观点与译者及译言网无关】

0

返回正文评论

      “果壳中的Java”是直译吧?

      这本书的第五版O'Reilly在2006年已经出了中文版,中文名叫《Java技术手册》。地址:http://www.oreilly.com.cn/book.php?bn=7-5641-0560-7

      in a nutshell 译成“果壳中”实在是别扭,此风可能来自霍金的The Universe in a Nutshell,中译名为“果壳中的宇宙”。

      “果壳”的翻译是完全错误的,就像real property不能翻译成“真实财产”一样
      in a nutshell,是一个短语,意思是:
      To explain in a few words; to be capable of easy solution