原创

Java核心技术--程序设计


Java“白皮书”的关键术语

Java的设计者已经编写了颇有影响力的“白皮书”,用来解释设计的初衷以及完成的情况,并且发布了一个简短的摘要。这个摘要用下面11个关键术语进行组织:

  1. 简单性
  2. 面向对象
  3. 分布式
  4. 健壮性
  5. 安全性
  6. 体系结构中立
  7. 可移植性
  8. 解释型
  9. 高性能
  10. 多线程
  11. 动态性

- 简单性

我们希望构建一个无须深奥的专业训练就可以进行编程的系统,并且要符合当今的标准惯例。因此,尽管我们发现C++不太适用,但在设计Java的时候还是尽可能地接近C++,以便系统更易于理解。Java剔除了C++中许多很少使用、难以理解、易混淆的特性。在目前看来,这些特性带来的麻烦远远多于其带来的好处。

的确,Java语法是C++语法的一个“纯净”版本。这里没有头文件、指针运算(甚至指针语法)、结构、联合、操作符重载、虚基类等(请参阅本书各个章节给出的C++注释,其中比较详细地解释了Java与C++之间的区别)。然而,设计者并没有试图清除C++中所有不适当的特性。例如,switch语句的语法在Java中就没有改变。如果你了解C++就会发现可以轻而易举地转换到Java语法。

Java发布时,实际上C++并不是最常用的程序设计语言。很多开发人员都在使用Visual Basic和它的拖放式编程环境。这些开发人员并不觉得Java简单。很多年之后Java开发环境才迎头赶上。如今,Java开发环境已经远远超出大多数其他编程语言的开发环境。

“简单”的另一个方面是小。Java的目标之一是支持开发能够在小型机器上独立运行的软件。基本的解释器以及类支持大约仅为40KB;再加上基础的标准类库和对线程的支持(基本上是一个自包含的微内核)大约需要增加175KB。

在当时,这是一个了不起的成就。当然,由于不断的扩展,类库已经相当庞大了。现在有一个独立的具有较小类库的Java微型版(Java Micro Edition),这个版本适用于嵌入式设备。

- 面向对象

简单的讲,面向对象设计是一种程序设计技术。它将重点放在数据(即对象)和对象的接口上。用木匠打一个比方:一个“面向对象的”木匠始终首先关注的是所制作的椅子,其次才是所使用的工具;一个“非面向对象的”木匠始终首先关注的是所用的工具。在本质上,Java的面向对象能力与C++是一样的。 开发Java时面向对象技术已经相当成熟。Java的面向对象特性与C++旗鼓相当。Java与C++的主要不同点在于多重继承,在Java中,取而代之的是更简单的接口概念。与C++相比,Java提供了更丰富的运行时自省功能。

- 分布式

Java有一个丰富的例程库,用于处理像HTTP和FTP之类的TCP/IP协议。Java应用程序能够通过URL打开和访问网络上的对象,其便捷程度就好像访问本地文件一样。

如今,这一点被认为是理所当然的,不过在1995年,主要还是从C++或Visual Basic程序连接Web服务器。

- 健壮性

Java的设计目标之一在于使得Java编写的程序具有多方面的可靠性。Java非常强调进行早期的问题检测、后期动态的(运行时)检测,以及消除容易出错的情况.....Java与C/C++最大的不同在于Java采用的是指针模型可以消除重写内存和损坏数据的可能性。

Java编译器能够检测许多在其他语言中仅在运行时才能够检测出来的问题。至于第二点,对于曾经花费几个小时来检查由于指针bug而引起的内存冲突的人来说,一定很喜欢Java的这一特性。

- 安全性

Java要适用于网络/分布式环境。为了实现这个目标,安全性颇受重视。使用Java可以构建防病毒、防篡改的系统。 从一开始,Java就设计成能够防范各种攻击,其中包括:

  • 运行时堆栈溢出,这是蠕虫和病毒常用的攻击手段。

  • 破坏自己的进程空间之外的内存。

  • 未经授权读写文件。

原先,Java对下载代码的态度是“尽管来吧!”。不可信代码在一个沙箱环境中执行,在这里它不会影响主系统。用户可以确信不会发生不好的事情,因为Java代码不论来自哪里,都不能脱离沙箱。

不过,Java的安全模型很复杂。Java开发包(Java Development Kit,JDK)的第一版发布之后不久,普林斯顿大学的一些安全专家就发现一些小bug会允许不可信的代码攻击主系统。

最初,安全bug可以快速修复。遗憾的是,经过一段时间之后,黑客已经很擅长找出安全体系结构实现中的小漏洞。Sun以及之后的Oracle为不断修复bug经历了一段很是艰难的日子。

遭遇多次高调攻击之后,浏览器开发商和Oracle开始越来越谨慎。Java浏览器插件不再信任远程代码,除非代码有数字签名而且用户同意执行这个代码。

注释:现在看来,尽管Java安全模型没有原先预想的那么成功,但Java在那个时代确信相当超前。微软提供了一种与之竞争的代码交付机制 ,其安全性完全依赖于数字签名。显然这是不够的,因为微软自身产品的任何用户都可以证实,一些知名开发商的程序确实会崩溃并对系统产生危害。

- 体系结构中立

编译器生成一个体系结构中立的目标文件格式,这是一种编译过的代码只要有Java运行时系统,这些编译后的代码可以在许多处理器上运行。Java编译器通过生成与特定的计算机体系结构无关的字节码指令来实现这一特性。精心设计的字节码不仅可以很容易地在任何机器上解释执行,而且还可以动态地转换成本地机器代码。

当时,为“虚拟机”生成代码并不是一个新思路。诸如Lisp、Smalltalk和Pascal等编程语言多年前就已经采用了这种技术。

当然,解释型虚拟机指令肯定会比全速运行机器指令慢很多。不过,虚拟机有一个选项,可以将执行最频繁的字节码序列转换成机器码,这一过程称为及时编译。

Java虚拟机还有一些其他优点。它可以检查指令序列的行为,从而增强其安全性。

- 可移植性

与C和C++不同,Java规范中没有“依赖具体实现”的地方。基本数据类型的大小以及有关运算的行为都有明确的说明。

例如,Java中的int永远为32位的整数,而在C/C++中,int可能是16位整数、32位整数,也可能是编译器开发商指定的任何其他大小。唯一的限制只是int类型的字节数不能低于short int,并且不能高于long int。在Java中,数值类型有固定的字节数,这消除了代码移植时一个令人头痛的主要问题。二进制数据以固定的格式进行存储和传输,消除了字节顺序的困扰。字符串则采用标准的Unicode格式存储。

作为系统组成部分的类库,定义了可移植的接口。例如,有一个抽象的Window类,并给出了在UNIX、Windows和Macintosh环境下的不同实现。

选择Window类作为例子可能并不太合适。凡是尝试过的人都知道,要编写一个在Windows、Macintosh和10种不同风格的UNIX上看起来都不错的程序有多么困难。Java1.0就尝试着做了这么一个壮举,发布了一个简单的工具包,为多个不同平台提供了常用的用户界面元素。遗憾的是,尽管花费了大量的心血,结果却不尽人意,这个库并不能提供在不同系统上都让人接受的结果。原先的用户界面工具包已经重写,而且后来又再次重写,不过跨平台的可移植性仍然是个问题。

不过,除了与用户界面有关的部分外,所有其他Java库确实能很好地支持平台独立性。你可以处理文件、正则表达式、XML、日期和时间、数据库、网络连接、线程等,而不用操心底层操作系统。不仅程序是可移植的,JavaAPI往往也比原生API质量更高。

- 解释型

Java解释器可以在任何移植了解释器的机器上直接执行Java字节码。由于连接是一个增量式且轻量级的过程,所以,开发过程也变得更加快捷,更加具有探索性。

这看上去很不错。用过Lisp、Smalltalk、Visual Basic、Python、R或Scala的人都知道“快捷而且具有探索性”的开发过程是怎样的。你可以做些尝试,然后就能立即看到结果。在Java发展的前20年里,开发环境并且没有把重点放在这种体验上。直到Java9才提供了jshell工具支持快捷而且具有探索性的编程。

- 高性能

尽管对解释后的字节码性能已经比较满意,但在有些场合下还需要更高的性能。

字节码可以(在运行时)动态地转换成对应运行这个应用的特定CPU的机器码。

使用Java的头几年,许多用户不同意“对性能已经比较满意”的说法。不过,现在的即时编译器已经非常出色,可以与传统编译器相媲美,而且在某些情况下甚至超越了传统编译器,原因是它们有更多的可用信息。例如,即时编译器可以监控哪些代码频繁执行,并优化这些代码以提高速度。更为复杂的优化是消除函数调用(即“内联”)。即时编译器知道哪些必要时,以后还可以撤销这种优化。

- 多线程

多线程可以带来更快的交互响应和实时行为。

如今,我们非常关注并发性,因为摩尔定律即将走到尽头。我们不再追求更快的处理器,而是着眼于获得更多的处理器,而且要让他们一直保持工作。不过,可以看到,大多数编程语言对于这个问题并没有显示出足够的重视。

Java在当时很超前。他是第一个支持并发程序设计的主流语言。从白皮书中可以看到,它的出发点稍有不同。当时,多核处理器还很神秘,而Web编程才刚刚起步,处理器要花很长时间等待服务器响应,需要并发程序设计来确保用户界面不会“冻住”。

并发程序设计绝非易事,不过Java在这方面表现很出色,可以很好地管理这个工作。

- 动态性

从很多方面来看,Java与C或C++相比更加具有动态性。它能够适应不断发展的环境。库中可以自由地添加新方法和实例变量,而对客户端却没有任何影响。

在Java中找出运行时类型信息十分简单。

当需要为正在运行的程序增加代码时,动态型将是一个非常重要的特性。一个很好的例子是:从Internet下载代码,然后在浏览器上运行。如果使用C或C++,这确实难度很大,不过Java设计者很清楚动态语言可以很容易地实现运行程序的演进。最终,他们将这一特性引入这个主流程序设计语言中。

注释:Java成功地推出后不久,微软就发布了一个叫作J++的产品,它与Java有几乎相同的编程语言和虚拟机。现在,微软不再支持J++,取而代之的是另一个名为C#的语言。C#与Java有很多相似之处,不过在一个不同的虚拟机上运行。

从入门到放手
书中颜如玉
  • 作者:管理员 (联系作者)
  • 发表时间:2020-03-05 12:22
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 公众号转载:请在文末添加作者公众号二维码
  • 评论