概述
从宏观上看,编程技术的发展在一定程度上映射了历史的发展。正如人类社会起源于极其简单的原始社会,早期的编程技术具有同样的规律;正如伟大的文明要经历萌芽、繁荣和衰落的过程,编程语言也同样会经历这些过程。国家的兴亡交替促进了人类的进步。同样,编程技术也处于不断的新旧更替之中:新的编程语言取代原来的编程语言。纵观人类历史,总不乏一些关键性事件,例如罗马帝国的颠覆、1066年的不列颠入侵,还有第一次核爆炸,它们都彻底改变了原来的世界。对于编程语言来说,虽然变革的规模较小,但同样改变了编程技术的发展进程。例如,FORTRAN语言的发明彻底改变了计算机编程的方式。Java的发明,则是另一个重大事件。
Java是标志编程进入Internet时代的里程碑。Java的设计初衷就是用来创建可以在Internet上随处运行的应用程序,其“一次编写,随处运行”的理念定义了一种新的编程规范。Gosling等人最初将其视为小型问题的解决方案,但后来却成为下一代程序员规划编程前景的动力。Java从根本上改变了人们对于编程的认识,因此计算机语言的发展历史可划分为两个时代:Java前时代和Java后时代。
Java前时代的程序员编写在单机上运行的程序;而Java后时代的程序员则为分布式网络环境编写程序。程序员不再只考虑单机的需求;相反,如今“网络就是计算机”的理念非常流行,程序员应该以服务器、客户端和主机的概念进行思考。
虽然Java的发展是由Internet所驱动的,但Java决不只是一种“Internet语言”。相反,它是一种特征(featuree)完备、为现代网络世界设计的通用编程语言。这意味着Java适合于几乎所有类型的编程。尽管有时候Java受限于网络性能,但它仍然包容了许多推进编程技术发展的新特征。这些特征不断影响着如今的计算模式。例如,Java提出的许多原理后来被C#所模仿。
本书将通过各种类型的应用程序来全面阐述Java语言的功能。其中一些应用程序展示了Java语言独立于网络属性(attribute)的强大功能,即所谓“纯代码”的范例,因为它们展示了Java语法的表示方法和设计思想。一些应用程序展示了如何使用Java语言及其API类简化复杂的网络编程。所有这些应用程序都说明了Java语言的强大功能和广泛应用范围。
在开始本书的Java教程之前,本章会用一些篇幅指出Java的一些特征,它们是Java作为一种优秀编程语言的标志。同时,这些特征也是将本章命名为“Java精髓”的原因所在。
设计一种面向对象语言所面临的最大挑战,就是如何平衡对象和简单数据类型之间的抉择。从纯理论的观点来看,每种数据类型都应该是一个对象,并且都应该从一个共同的父对象派生而来。这就使得所有数据类型以相同的基本模式运作,共享一个公共的基类属性集合。现在的问题在于,如果将简单数据类型(如int和double)作为对象处理,那么对象机制所引起的额外开销会导致性能(performace)的下降。由于简单数据类型通常用于循环控制和条件语句,所以这些额外开销将带来广泛的负面影响。诀窍就是如何在“一切都是对象”的理想和“性能衡量”的现实之间找到正确的平衡点。
Java非常巧妙地解决了对象与简单数据类型之间的问题。首先,Java定义了8种简单类型:byte、short、int、long、char、float、double和boolean。这些类型能够直接转换为二进制代码。因此,CPU可以直接处理int类型的变量,而无需任何额外开销。在Java中,处理简单数据类型和其他语言一样快速高效。因此,由int
类型变量所控制的for循环可以高速运行,而不受任何对象化所带来的负面影响。
除了这些简单数据类型,Java中的其他数据类型都从一个共同超类(Object类)派生而来。因此,所有这些数据类型都共享从父类继承而来的方法和属性集。例如,所有对象都有toString()方法,因为toString()是父类Object中定义的方法。
由于简单数据类型不是对象,因此Java可自由地以略有不同的方式处理对象和非对象。这就是Java的真正精髓所在。在Java中,所有对象都通过引用访问,而非直接访问;只有简单数据类型才可以直接访问。因此,Java程序绝对不会直接操作一个对象。这种策略可以带来很多好处,最直接的好处就是能够高效地实现垃圾回收。因为所有对象都通过引用访问:当一个对象没有被引用时,它将被回收。另一个好处是,每个Object类型的指针可以引用系统中的任何对象。
当然,通过引用访问对象将产生额外开销。因为一个引用实际上是一个地址(即指针)。于是对每个对象的访问不是直接进行的,而是通过地址间接完成的。尽管现代CPU可以高效地处理间接访问,但是间接访问总是不如直接处理数据本身快,简单数据类型即是通过直接方式进行的。
尽管简单数据类型的处理非常高效,但是有些时候仍然需要使用跟某个简单类型
等价相当的对象。例如在运行时创建一个整型链表,并在不再使用时将其回收(垃圾回收)。为了处理此类情况,Java
定义了为简单类型(
如
Integer
和
Double)
定义了包装器(wrapper)
,例如
Integer
和
Double。
这些包装器使得简单类型在必要时可参与到对象层次的操作中来。Java关于对象和简单数据类型的平衡问题。它支持编写高效程序,同时又完美地解决了允许实现对象模型,而不用担心对简单数据类型的性能会产生负面影响。
垃圾回收作为一种内存管理技术已经存在了很长时间,但是Java使它焕发出崭新的活力。在C++等语言中,内存必须人工管理,程序员必须显式地释放不再使用的对象。这是问题产生的根源,因为忘记释放不再使用的资源,或者释放了正在使用的资源都是很常见的事情。Java代替程序员完成了这些工作,从而防止了此类问题的发生。在Java中,所有的对象都是通过引用访问的,这样,当垃圾回收器发现一个没有引用的对象时,就知道该对象已经不被使用,并且可以回收了。如果Java允许对象的直接访问(与简单数据类型的访问方式类似),那么这种有效的垃圾回收方法将无法实现。
Java的垃圾回收策略在普遍意义上反映了Java的理念。Java设计人员花费了大量的精力,来防止其他编程语言经常出现的典型问题,例如程序员经常忘记释放资源,或者错误地释放正在使用的资源。因此,使用垃圾回收策略有效地避免了此类问题的发生。
Java的设计者所提供的编程特性,包括对多线程多任务的语言级支持。多任务具有两种类型:基于进程的多任务和基于线程的多任务。在基于进程的多任务中,最小的可调度单元是进程。进程实际上就是正在执行的一个程序。因此,基于进程的多任务就是允许计算机同时运行两个或多个程序的特性。在基于线程的多任务中,最小的可调度单元是线程。线程定义了一个程序内的某条执行路径。因此,一个进程可以包含有两个或更多的执行线程,而多线程程序可以有两个或更多个可以并发执行的部分。
尽管基于进程的多任务通常是操作系统提供的功能,基于线程的多任务却可以极大地受益于
语言级程序设计语言级别的支持。例如,C++没有对多线程编程提供内置支持,于是就必须依赖于操作系统来处理多线程任务。这就意味着创建、启动、同步和结束线程都必须通过对操作系统的多次调用来实现。因此C++中的多线程代码是不可移植的。这也使得C++编程中的多线程没有得以广泛应用。
由于Java内置了对多线程的支持,哪些在其他语言中必须由手工完成的工作,现在都可以由Java自动处理。Java多线程模型中最有特色的部分之一,就是其实现同步的方式。同步建立在两种创新的特性之上。首先,在Java中,所有的对象都有充当互斥锁的内置侦听器。在给定的时刻,任何侦听器只能由一个线程拥有。通过使用synchronized关键字对方法进行修饰,可以启用锁定特性。在调用同步方法时,该对象就被锁定,而试图访问该对象的其他线程就只能等待。其次,Java对同步的支持也可以从所有类的共同超类Object中体现。Object声明了下面三个同步方法:wait()、notify()和notifyAll()。这些方法支持线程间通信。因此,所有的对象都对线程间通信有内置的支持。通过和同步方法结合使用,这些方法可以为线程的互操作提供高级别的控制。
通过将多线程作为语言的一个易于使用的内置特性,Java改变了人们关于程序基本体系结构的观念。在Java出现之前,大部分程序员将程序看成是,只有一条执行路径的单块结构。在Java出现之后,程序演变为多个可互操作的并发任务的集合。这种并发机制的改变对于计算产生了深远的影响,但是其最重大的影响可能是使得软件组件的使用更为便捷。
异常(exception)的概念性框架出现在Java产生之前。因此,在Java出现之前,其他编程语言就已经提出了异常的概念。例如
异常出现在C++
提出异常概念中的时间,就比Java诞生的时间早了许多年。
Java
中的异常在Java的最初设计中就已经引入了,而不是在Java产生之后才加入的,因此Java对于异常机制的实现就显得非常重要。异常机制是在Java语言中完全集成的,
这是Java的基本特征之一。
Java异常机制的关键在于异常是必须使用的,而不是可选的。通过异常处理错误是Java语言的规则,这与C++是有区别的。例如,C++同样支持异常机制,但是这种机制并未完全集成到整个编程环境中。考虑打开或者读取一个文件的操作。在Java中,如果某个操作发生错误,将抛出一个异常。而在C++中,打开或者读取文件的方法会返回一个专用错误代码,报告操作中发生的错误。因为C++库仍然依赖于错误返回代码而不是异常,所以从本质上来说,C++并不支持异常,程序必须不断地进行人工检查,以避免可能出现的错误。但是在Java中,程序员只需要简单地使用一个try/catch代码块,就可以自动捕捉到任何错误。
多态性(polymorphism)是面向对象编程的属性,它允许多个方法使用同一个接口。Java从多个方面支持多态性,其中两个方面最为突出。第一个是每个方法(标记为 final的方法除外)都可以被子类重写;第二个是设立interface关键字。下面将给出这两方面的详细介绍。
由于超类中的方法可以在派生类中重写,因此创建类的层次结构非常简单。在类的层次结构中,每个子类都将它的超类特化(
specialization)。大家知道,超类的一个引用可以引用它的任何一个子类,而且通过超类的引用调用某子类对象的一个方法时,会自动执行由该子类重写后的版本。因此,可以用超类来定义对象的形式并提供对象的默认实现,而子类根据这种默认实现进行修改,以更好地适应具体情况的要求。因此,在超类中定义的一个接口可以作为多个不同实现的基础。
当然,Java进一步采取了“一个接口,多个方法”的概念。它定义了interface关键字,这样就可以将类的方法和类的实现完全分离。尽管接口是抽象的,但是仍然可以声明接口类型的引用。这个概念非常重要,因为它可以改进多态性的应用。只要某个类实现一个接口,并且该接口提供了某种功能,那么任何需要这种功能的代码都可以使用这个类的对象。例如,假设某个接口的名称为MyIF,考虑下面的方法:
void myMeth(MyIF ob) {
// ...
}
任何实现了MyIF接口的对象都可以传递给myMeth()方法。该对象的其他功能无需考虑。myMeth()方法可以对任何实现了MyIF接口的对象进行操作。
尽管Java有许多功能强大的特性,但是如果没有字节码(byte code)这一特征,那么Java只不过是编程技术发展进程中的一个足印。字节码是Java语言的一个重要组成部分,它对程序员而言,几乎是透明的。所有的Java程序员都知道,Java编译器的输出不是能够直接由CPU执行的机器指令,而是一种经过高度优化的可移植的指令集合,这种指令集合称为字节码,它只能由Java虚拟机(Java Virtual Machine,JVM)执行。最初,JVM只是一个简单的字节码解释器,现在,JVM也将字节码的on-the-fly编译技术应用到可执行代码中。无论字节码的执行采用何种方式,它的优势对于Java的成功都是至关重要的。
字节码的第一个优势是可移植性。无论计算机使用何种类型的CPU(或操作系统),只要具有JVM,那么由Java程序编译而成的字节码就可以在其中执行。换而言之,只要为某个特定环境实现了JVM,那么每个Java程序都可以在该环境运行。没有必要为每个不同的环境创建都单独执行代码,因为同一种字节码可以在所有环境中运行。因此通过使用字节码,Java为程序员提供了“一次编写,随处运行”的能力。
字节码的第二个优势是安全性。由于字节码在JVM的控制下执行,因此JVM可以防止执行恶意操作的Java程序。保证主机安全的能力对于Java的成功是至关重要的,因为它允许创建Applet。由于Applet是可以通过Internet动态下载的小程序,因此避免Applet破坏主机的机制是非常必要的。字节码和JVM的结合,还保证了Applet的安全下载。可以说,如果没有字节码,那么Web可能根本无法达到今天的地位和影响。
从概念上来讲,计算机语言由两部分组成。一是语言本身,由关键字和语法定义;二是标准库,包含一组面向程序员的类、接口和方法。尽管现在所有的主流编程语言都提供了大量的库,但是Java定义的库由于更为丰富和多样显得非常突出。人们在最初创建Java时,它的库包括一组核心程序包,例如java.lang、java.io和java.net。随着Java不断发布新的版本,新的类和程序包也被不断加入。如今的Java已经为程序员提供了功能极其强大的库函数。
从Java创建之初,Java函数库就与其他语言的函数库有所不同,其中一个关键不同之处,在于Java库对网络的支持。在开发Java的时候,其他语言(例如C++)并没有提供(现在仍然没有提供)处理网络的标准函数。Java通过提供相应的类,使得连接和使用Internet的处理非常方便,从而有力地推动了Internet革命的进程。Java向所有的程序员开放了Internet,而不仅仅局限于精通网络编程的那部分人。java.net的功能改变了计算的形式。
Java核心库中的另外一个关键的程序包是java.awt,它支持抽象窗口工具集(Abstract Window Toolkit,AWT)。程序员可以用AWT创建可移植的、基于GUI的代码。也就是说,程序员用AWT类可以创建一个基于视窗的应用程序,并在程序中使用各种标准的GUI元素,例如滚动条、复选框和单选框等。由于AWT的存在,程序员创建的GUI应用程序可以运行在任何支持Java虚拟机的环境中。而这种层次上的GUI移植性,在Java之前是从来没有过的。
在Java中加入AWT彻底改变了程序员思考应用程序环境的方式。在Java前时代,基于GUI的程序必须明确指出其执行环境。这意味着任何Windows程序需要重新编译才能够在一台Apple机上运行。Java通过一个可移植的GUI提供统一的编程环境。
后来Java:Swing也被加入Java中,这是AWT的一个轻型实现。Swing组件包含在javax.swing及其子程序包中。Swing为程序员提供了一组丰富的GUI组件。与AWT相比,它们的可移植性更高。本书将通过许多例子来演示AWT和Swing如何为程序员提供函数,使他们具有编写高效、可移植的GUI应用程序的能力。
如今,Java库已经基于最初的核心库得到了极大发展。Java的每个新版本都会提供一些新的库。新的程序包不断增加,新的功能也不断加入已有的程序包中。Java库的发展过程处于一个连续的状态,因为Java必须能够适应快速演变的计算环境。这种在短期内适应和变化的能力也是Java的精髓之一。
Applet是Java最具有革命意义的特征之一,因为它能够创建可移植的、可动态下载的、能够在浏览器的限定下安全执行的程序。人们如今已经普遍接受这一观点,但是在Java前时代,这种可执行内容(executable content)受到广泛置疑:一个疑问是,恶意程序是否会对客户机造成伤害;另外一个疑问是:为某种类型的CPU和操作系统编译的代码在另一种系统上可能无法正常运行。由于连接到Internet的CPU和操作系统种类繁多,那么对于某个程序,为每一类型的环境都创建一个独立的运行版本是不切实际的。Java Applet为以上两个问题提供了一套很好的解决方案。通过使用Applet,Web程序员可以方便地在静态的HTML页面中添加动态的内容。Java Applet使网页变得生动起来,从此告别了静态网页的年代。
除了改变人们对于Web内容的思维方式之外,Applet还有一个重要的影响——它推动了组件软件开发的发展(也可能是一个副作用)。由于Applet是小程序,因此它们通常代表很小的功能单元;而软件组件正是基于这种思想。只要按照Applet的思维考虑问题,那么就向Beans的思想迈出了一小步,甚至更多。在面向组件的体系结构中,一个应用程序由一些互相作用的组件构成。如今这种体系结构已经大量取代了以往编程模式中常见的统一模型。
Java的精髓还体现在另外一个方面,尽管它实际上并不属于Java语言的一部分。Java引入了一种乐于接受新思想的创新文化,以及一个能够迅速吸收这些新思想的过程。虽然很多计算机语言变化缓慢,但是Java却处于不停地发展和适应的过程之中。同时,这个过程通过Java社团(JCP)向整个Java团体公开。JCP提供了一种机制,Java用户可以通过该机制协助决定Java语言、工具和相关技术的未来发展方向。因此,实际使用Java语言的人们可以参与到它的发展中来。
从诞生之初开始,Java就为编程领域带来了变革
—— 并且这个变革仍然没有停止。Java仍然处于计算机语言发展的前沿,它在计算发展史上已占有了永恒的地位。
最后
以上就是甜甜红牛为你收集整理的Java 精髓的全部内容,希望文章能够帮你解决Java 精髓所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复