Java SE实践教程
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.1 讲解

1.1.1 爪哇岛的历史与演变

爪哇的诞生

书中我们所要讨论的爪哇岛其实与印度尼西亚的爪哇岛(Java)毫无关系,哈,它们只是碰巧同名罢了。我们将要讨论和学习的Java是一门程序设计语言,是一个程序开发环境,也是一个应用部署环境。虽然Sun公司直到1995年才正式发布其Java语言,但Java真正的诞生日期其实可以一直追溯到1990年底。当时以James Gosling为首的十多个人在Sun公司内部成立了一个名为Green Team的小组,旨在开发一种能够在诸如烤面包机、冰箱等的各类消费电子产品操作平台上运行且又独立于平台的软件,来解决对这些电子产品的控制与通信问题。最后,Green Team开发的一种名为Oak的语言解决了这一问题。Oak语言继承了C/C++的面向对象技术核心,同时摒弃了容易引发错误的指针、运算符重载,以及多重继承等语言特性,并且补充了C/C++所缺乏的垃圾回收机制等重要特点。这样一来,Oak语言在当时可用资源极其有限的嵌入式平台上就游刃有余了。但是由于嵌入式市场的前景不如预期,恰巧当时互联网又崭露头角,Green Team决定改造Oak语言,转投互联网市场。当Green Team进行商标注册时,发现Oak商标已经被一家显卡制造厂家注册了,所以Team决定将Oak语言重新命名为Java,一杯热气腾腾的爪哇咖啡。

爪哇的发展

Java最初是为了嵌入式设备而生的,但是阴差阳错地因为互联网的迅猛发展而迅速红火起来,随后由于其在企业应用中的卓越表现而奠定了其在市场中不可动摇的地位。Java除了其跨平台这一最为重要的特性之外,还有诸如面向对象、网络分布式计算支持,以及自动垃圾回收机制等很多很引人注目的优点。“Write Once,Run Anywhere”(一次编写,到处运行)的口号始终指引着Java向各个领域不断渗透。如今,Java被广泛应用于企业应用、桌面程序、手持设备等多方面的开发。

Java在1995年正式发布以后,于1996年1月23日又发布了其首个Java开发工具包,即Java Development Kit(JDK)1.0,其中包括了开发工具及运行环境,得到了世界各地的厂商及开发者的热烈追捧,这也使得1996年无疑成为Java相当成功的一年。一年之后的1997年,JDK 1.1的发布相对于1.0来说最大的改进要属隆重推出了Just-In-Time(JIT)编译器,为Java的跨平台特性提供了支持。1998年12月4日,JDK 1.2的发布可谓具有划时代的意义,因为它标志着Java进入了Java 2时代,随后平台的划分就显得更为明晰了。Sun公司在Java 1.2版以后将JDK 1.2改名为J2SDK,将Java改名为Java 2,此举既是出于市场推广的考量,也是平台市场细分的前奏。

在1999年Sun公司将其Java 2平台划分为3大领域的3个版本:J2SE、J2EE、J2ME。J2SE(Java 2 Standard Edition),Java标准版,主要用于桌面应用的开发,同时也作为J2EE的基础。J2EE(Java 2 Enterprise Edition),Java企业版,主要用于企业应用,支持分布式部署。J2ME(Java 2 Micro Edition),Java微型版,主要用于小型设备及消费类电子产品上的软件开发,基本属于J2SE的一个子集,但也有其特殊的类库支持。Java 2对其平台领域进行细分及准确地定位其目标群体,此举起到了良好的市场效果,对Java自身的发展及其被采用率的提高起到了实质性的推动作用。2000年Java发布了JDK 1.3,主要是针对J2SE 1.2进行查漏补缺及完善和拓展新的API(Application Programming Interface,应用程序编程接口),其应用已经涵盖了数据库、多媒体、网络、电话、加密等诸多信息技术领域。

随后几年,由于其安全性能及对分布式网络的支持,Java在企业平台上的发展如日中天。这也导致微软公司酝酿且推出了架构与Java十分相似的.NET平台,结束了Java在互联网平台上一枝独秀的局面。从此以后市场上关于“Java对决.NET”的平台优劣性比较及讨论就再也没有停歇过。人们发现Java的主要劣势在于其平台的性能问题,所以2002年J2SE 1.4的推出,主要目标是改善和提高Java平台的性能,如支持64位运算、改善反射机制、重写I/O API等。经过数年的发展,以及相互竞争和互相学习,无论Java平台还是.NET平台,从技术到构架都已经相当成熟,谁将争得更大的市场份额,谁将取得更大的成功,已经不由技术本身能提供些什么来决定了,单从技术本身来看Java和.NET所能提供的已经十分类似。此时Java关注于如何提高Java的易用性,更好地帮助开发人员快捷地开发高效易维护的程序代码,以此来提高用户及市场的忠诚度。

2004年10月J2SE 5.0的发布正是以“易用”为主题的。关于本次版本发布将名称从J2SE 1.5改成了J2SE 5.0,Sun公司是这样解释的:“从Java诞生至今已有9年时间,而从改名为J2SE算起也有5年了;在这样的背景下,将该版本号从1.5改为5.0可以更好地反映出新版J2SE的成熟度、稳定性、可伸缩性、安全性。”不过J2SE 5.0的内部版本号依然是1.5.0。总体来看,本次发布的J2SE 5.0从语言层面上对Java做了不少变更。不过这些改变并不是程序开发人员必需的内容,开发人员完全可以通过自己的办法来达成这些变更能实现的同样功能。但J2SE 5.0的目标就是让程序员能够更加方便地进行开发,更好地改善Java的易用性,来留住老用户,吸引新用户,从而赢得市场。对易用堆的追求,Sun公司把它继续保留到了2006年底Java SE 6的发布中,“易于开发”依然是主题之一。

不过随着互联网一如既往的高速发展,Java的对手已经不仅仅是微软的.NET一家了,众多高效敏捷的脚本语言,如PHP、Ruby、Python等,顺应开放源代码的潮流,一举占领了Java在企业应用方面的半壁江山。所以在保持提高性能和增加易用性的同时,Java SE 6在AWT/Swing、脚本支持、Web服务、XML、编译器 API、数据库、JMX、网络等方面提供了性能和功能的加强。技术在日新月异地发展,Java也是。Java SE 7也快正式发布了,一如既往的是一定会有更多的改善和提高伴随着Java SE 7的发布一起到来。

贴士:Java Standard Edition通常每2年发布一个主要发行版本。

爪哇的命名

如果细心留意的话,你会发现大多数J2SE的版本除了版本号外,还有一个有趣的项目名称。比如J2SE 5.0的项目名称叫猛虎(Tiger),Java SE 6叫野马(Mustang),即将发布的Java SE 7项目名叫海豚(Dolphin)。

从猛虎开始,每个版本在发布时拥有了2个版本号:一个是外部版本号,如5.0;另外一个是内部版本号,如1.5.0。

Java的主要发行版本(如1.4、1.5等)都是以动物的名称命名的,而那些非主要的发行版本(如1.4.1、1.4.2等)都是以昆虫的名称命名的,旨在表示此版本只是漏洞补丁(bug fix)而已。

如果你有兴趣的话,不妨去Sun的网站看看,http://java.sun.com/j2se/codenames.html,这个网页上列出了Java标准版的每一个发布的项目名称。

1.1.2 爪哇岛基本生存规则

爪哇岛是程序设计的乐园,但倘若想在岛上快乐地生存与交流,您还是得先了解岛上的生存环境并掌握好岛上的生存规则。

开发环境

首先我们得理解什么是编译(Compile)。Java是一种高级程序设计语言,其代码比较接近于人类语言,但是计算机却理解不了,因为计算机只认识0和1。通俗来讲,要想让计算机明白程序员写了些什么,就得要靠javac这个Java编译器(Compiler)来对程序员所写的程序进行“翻译”和“转换”,此过程称为“编译”。但是由于Java是跨平台的程序开发语言,这意味着Java的编译器不能将程序员写的代码直接“翻译”成0和1组成的机器码,而是把它“翻译”成Java运行时环境(Java Runtime Environment,简称JRE)可以理解的中间代码——字节码(Bytecode)。这样一来,不管你用什么硬件平台,只要平台上安装了JRE,它就可以运行相同的Java 字节码了。JRE里面包含了Java的虚拟机 JVM(Java Virtual Machine),它相当于一个多国语言翻译,因为它承担了把 Java 字节码“解释”成特定硬件平台能够理解的机器码的翻译工作。如图1-1所示。

图1-1 Java编译及运行环境

要编译和运行Java程序,就得要建立Java开发环境,这就一定离不开JDK。当今市面上除了主流的由Sun公司所提供的JDK外,还有IBM、BEA(现已被Oracle收购)等几家提供的JDK可供选择,且每一款产品都各有其优势及侧重点。这个工具集提供了Java编译器、Java解释器等工具,但没有提供Java代码编辑器。以前,开发人员在进行Java程序开发时,大多都使用文本编辑器来编辑源代码,并将其保存为扩展名为“.java”的文件,然后再使用命令行的方式对其进行编译、调试和运行。这样做的缺点是开发效率比较低。而且,当在命令行的方式下进行开发时,为了使 java、javac等程序能够在系统中的任何目录下可以被找到和运行,以及为了让 Java 解释器知道到哪里去找须要引用的类,开发者不得不设置JAVA_HOME、Classpath、Path等系统环境变量。集成开发环境(Integrated Development Environment,IDE)出现后,这一切都发生了改变。可视化编程帮助开发人员提高了开发效率,并且 IDE 帮助程序员更好地管理和组织代码和文件。随着集成开发环境的层出不穷,各款产品间的竞争也变得愈加激烈。经过十多年的大浪淘沙,目前市场上主流的Java开发IDE主要有以下几个:开放源代码的NetBeans、开放源代码的Eclipse,还有JetBrains公司版权所有的IntelliJ IDEA。

生命周期

谈到程序开发,我们得了解通常程序开发有哪几个阶段,理解每个阶段到底要做些什么,这就是我们所说的程序开发的生命周期。Java程序开发的过程,当然也得符合普通程序开发的生命周期规律。

一般的程序开发,得经过如图1-2所示的问题定义、问题分析、算法设计、编码调试和测试等几个阶段。程序开发生命周期的意义在于让程序开发者能够通过经历一系列生命周期的阶段把一个复杂的问题最终化解成一堆可以运行的代码,使实际问题得以解决。

图1-2 Java程序设计生命周期

问题定义:程序员接到的任务往往是以“问题”的形式出现的,此阶段程序员得定义这个现实世界的“问题”,使其尽量清晰、明确且简单,这样才有助于问题的分析与解决。谚语有云:良好的开端是成功的一半。

问题分析:问题定义阶段往往完成的只是对一个现实问题的总目标的定义,明确了最后要达到什么结果才能解决问题。问题分析阶段,程序员得把这个总目标分解为一些更细化、更明确、更简单、更容易实现的子目标。

算法设计:经过上面两个阶段,问题已经被定义和分解了,此时程序员得把它以计算机可以理解的一步一步的过程表达出来。此阶段可以借助流程图或伪代码等工具来帮助设计。

编码调试:依照上阶段算法设计的结果,程序员得把设计细节用Java特定的具体语句来实现,并且随时编译调试,来找出编码中的疏漏并且修正。

测试:通过编码调试,程序员写的代码已经通过了Java编译器这一关的检查,但是不排除其还存在设计上的疏漏,可能会在运行时出错。所以得通过测试来发现运行时有什么缺陷(Bug),并通过修改源代码来修正错误。

语言基础

数据类型

数据是有属性的。若光给出一个数字“100”,它也许是指小明这次数学考试的分数,也许是指当前人民币的最大面额。离开了属性,数字将毫无意义。数据类型就是对数据属性的归类。Java数据类型基本可以分成基本数据类型(Primary Data Type)和引用数据类型(Reference Date Type)两大类。Java语言本身提供8种基本数据类型,它们是byte、short、int、long、float、double、char、boolean。但这也正是为何说Java不算纯粹的面向对象语言的原因,因为这些基本数据类型本身不是对象。基本数据类型的引入是早期 Java 出于对执行效率的权衡考虑,“一切皆对象”的口号在这里为运算性能悄悄地打了个擦边球。不过Java为这8种基本数据类型提供了8种相对应的包装类,用来实现基本数据类型和引用数据类型之间的转换,它们分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean。这也从另一个侧面完善了“一切皆对象”的编程思想。

Java的8种基本数据类型中有6种数字类型(4种整数型、2种浮点型),1种字符类型,还有1种是布尔型,具体如表1-1所示。

表1-1 Java基本数据类型

变量

Java有4种不同形式的变量。

1. 局部变量。

这和过程语言时代的C一样(比如:int i=0; String s=null;),它们通常是在需要的时候定义(如果你愿意,也可以统一在方法的开头统一定义,这要看你喜欢哪种风格了),而且正如你所看到的,Java支持在定义变量的同时对变量进行赋值。

2. 参数。

参数是指方法签名中的变量,所谓的方法签名由4部分构成:修饰符、返回值类型、方法名和参数表,例如:

这里的args就是参数,它的类型是String[],字符串数组。参数在使用时和局部变量相同,唯一的区别是不用单独定义(已在参数表中进行声明)。

3.实例变量。

对象的方法用于实现算法逻辑,而实例变量则用来存储数据。相对于类变量来说,实例变量因实例不同而不同(非静态变量),也就是说,同一个类的不同实例会拥有各自的实例变量,各实例变量之间相互独立,并无影响。

4.类变量。

类变量是一种静态变量,它隶属于静态的类(相对于非动态的实例而言),因此,拥有类变量的类的多个实例,共享同一组类变量,无论是直接通过类访问类变量,还是通过任一实例来访问类变量,所访问的变量都是同一个变量,同样的数据。为了和实例变量区分,类变量必须以static修饰。

无论是基本数据类型,还是引用数据类型,其变量定义方式均相同,而且,都要进行初始化(赋予初始值)方可使用。JVM会对实例变量和类变量进行默认初始化,基本数据类型中除了布尔型默认初始化回为false 外,其他类型均默认初始化回为0,而引用数据类型则统一初始化为null。

数组

数组表示一组相同类型的数据,其定义方法如下:

    int[] numbers;

Java通过方括号“[]”来标识数组,和C语言一样,Java的数组变量定义和内存分配是分离的,也就是说这个例子中定义的numbers没有对应的内存空间,因此还不能用来存储数据,下面的代码则对numbers进行了资源分配:

    numbers = new int[5];

这里为numbers分配了5个整数存储位,现在便可以对数组中的元素进行操作了:

    numbers[1] = 3;

这里我们为numbers数组的第2个元素赋值整数3,方括号中的1我们称之为下标,由于Java的数组访问是从0开始的,所以拥有5个元素的numbers其有效下标为0、1、2、3、4。

为一个数组分配资源之后,其数据元素由JVM进行默认初始化,其初始化规则和前文所述的实例变量默认初始化一样,基本数据类型中除了布尔型默认初始化为false外,其他类型均默认初始化为0,参考数据类型则统一初始化为null。

方法

方法是隶属于对象的函数,配合实例变量,它帮助对象实现了对数据及其对应的算法和逻辑的封装。

方法的定义由4部分组成,它们分别是修饰符、返回值类型、方法名和参数表,如下所示:

修饰符标识了该方法的访问级别,其可选择的值有以下几个。

1. private(私有的):表示该方法仅可被所属类、所属类的外围类或内部类直接访问。在其他场合调用拥有private修饰符的方法,会导致编译错误。

2.包访问权限:任何没有修饰符的方法均为包访问权限(也叫“默认访问权限”),表示该方法只能在其所属的包中访问。

3. protected(保护的):表示该方法仅可以被所属类的子类及同一个包下的类访问。

4. public(公开的):表示只要能访问其所属类,就能访问该方法。

返回值类型用于限定该方法返回值的类型,通常为某一个基本数据类型或参考数据类型,当该方法没有返回值时,则把返回值类型设为void。

在同一个对象内定义的,名称和参数表相同的方法,我们称之为方法重载,Java虚拟机会根据调用时参数类型的不同而自动选择调用正确的方法。

    public class Overload {
        public void method(int arg){
            System.out.println("argument is an integer: "+arg);
        }
        public void method(String arg){
            System.out.println("argument is a string: "+arg);
        }
        public static void main(String[] args){
            Overload o = new Overload();
            o.method(1); // 系统自动识别参数类型,并调用method(int arg)
            o.method("1"); // 系统自动识别参数类型,并调用method(String arg)
    }
    }

上述程序的输出结果为:

    argument is an integer: 1
    argument is a string: 1

控制流

流程控制语句用于在程序中对逻辑流程的控制,主要包括如下3种语句。

1. 条件控制:if-then、if-then-else、if-then-else if-then、switch-case

2. 循环控制:for、while、do-while

3. 分支控制:break、continue、return

其中break和continue必须配合循环控制使用,其具体用法和C语言并无二致。

包简介

若能灵活地使用Java语言提供的API,程序员可以方便地编写出复杂的、功能强大的应用程序。为了更有效地组织API并防止名称冲突,Java提供了包(package)这种方式。一个包对应磁盘上的一个文件夹,包中的类就放在这个文件夹里。

Java语言中最基本的包就是Java语言核心API,它们包括:

java.lang、java.bean、java.rmi、java.security、java.io、java.util、java.net、java.awt、java.applet、java.sql、java.text等。

下面,我们对其中一小部分常用的包做一个简单的描述,以帮助大家更好地理解它们,方便大家在需要时使用。

1. java.lang:它是Java语言中最核心的包,它提供了整个Java编程语言的基础。

2. java.io:它通过数据流、串行化及文件系统提供Java语言的标准输入/输出。

3. java.util:它是Java的实用工具库,提供了一些实用的方法和数据结构。例如,Java提供日期(Data)类、日历(Calendar)类来产生和获取日期及时间,提供随机数(Random)类产生各种类型的随机数,还提供了集合(Collection)、映射(Map)等常用数据结构的类。

4. java.net:这是使Java具备网络处理功能的包,它提供了一些实施网络应用的类,使用这个包就可轻松地创建、连接套接字(socket)、可以编写出自己的Skype、QQ等程序。

5. java.sql:它提供了访问和操作数据的接口,使用它可进行数据库应用程序开发。

命名标准与编码规范

根据 Sun公司的调查研究,一般代码的生命周期中只有20%是属于原始的开发和测试,另外 80%是对代码的维护和改进。因此,为了让代码更容易被读懂和维护,好的命名标准和编码规范对程序开发人员来说就显得尤为重要了。

Sun公司提供了Java程序设计基本的命名标准供大家参考。

类和接口(Classes and interfaces)

第1个字母须大写,若它是由好几个单词组成的,每个单词的首字母要大写,类名通常为“名词”形式,接口名通常为“形容词”形式。例如:

方法(Methods)

首字母小写,其后每个单词的首字母大写。方法名通常为“动词+名词”的形式,例如:

    getInvoiceNumber
    doTranslation

变量(Variables)

变量的命名规则和方法相似,唯一不同的是变量名通常是“名词”形式,例如:

    bankAccountNumber
    myBook

常量(Constants)

Java中常量是用来使变量static和final的。常量名通常全部用大写字母并用下划线做隔断。

例如:

    MAX_VOLUME

仅仅有规范的命名是远远不够的,编码也得遵循规范才能使得编写出来的程序真正易读易维护。Sun公司提供了官方的Java编码规范,有兴趣的读者可以通过以下网址学习借鉴, http://java.sun.com/docs/codeconv/

编程思想

我们在学习编程语言的过程中,不仅要学习和掌握它的基本语法规则,更重要的是要体会和领悟其编程思想。掌握了编程的核心思想以后,将来再有机会去学习其他类似的编程语言时,无非就是学习一种新的语法格式了。编程思想的理解对编程语言的学习与掌握起到至关重要的作用,它往往能帮助你事半功倍。

老式的程序设计思想是由数据(Data)与过程(Procedures)构成面向过程(Procedure-Oriented)的编程思想。而 Java 则主要是用对象(Object)来描述世界的,采用的是面向对象(Object-Oriented)的编程思想。在面向对象的爪哇岛上,一切皆可看作对象,而且每个对象都有其状态(Status)和行为(Behavior)。关于面向对象的编程思想,我们要重点掌握,但是要学的东西很多,例如抽象、继承、封装、多态、重载、构造方法、接口等。在下一章中,我们将会详细介绍面向对象的基本知识。

1.1.3 爪哇岛上新人新风尚

Java技术经过10多年的发展,其应用领域已经从传统的桌面、企业及移动应用拓展到了几乎每一个领域。现如今,您可以在各行各业各种介质上看到Java的存在,Java可以配合电子书阅读器为您提供无纸化移动阅读,Java可以配合蓝光碟片(Blu-Ray Disc)为您提供高保真数字多媒体体验,Java可以为您提供有趣的手机小游戏帮您打发无聊间隙,Java也可以直接植入最微小的感应器,部署到数以亿计的各种设备上来实现应用功能。随着技术的发展, Java早已经无所不在。

众所周知,Sun在Java发展的各个阶段起到了相当关键的作用。如今Java在开源领域扮演如此重要的角色,与Sun的大力支持也是密不可分的。Sun公司自2006年免费开放Java的部分源代码以后,又于2007年5月开放了几乎所有的Java核心源代码。Java的开源意味着Java的发展不再由Sun或IBM等几家供应商说了算,它的前途与发展将掌控在我们普通开发者自己手中。对Java类库、javac,甚至JVM本身都采用了GNU GPL(GNU General Public License)协议,Sun此举推出的OpenJDK项目引领了创新的新潮流,意图把Java的发展推向一个前所未有的新环境。我们可以预见,爪哇岛将变得越来越开放与自由,将在真正意义上成为一个任您驰骋的自由空间。

Java SE最新的正式发行版Java SE 6(Mustang)早在2006年底已经发布,按照以往大致每两年会发布一个Java SE新版本的惯例,Java SE 7应该已在紧锣密鼓地开发与测试中了。按照Sun公布的路线图,Java SE 7将于2009年发布。

为什么我们放着最新的Mustang不去认识,而要了解相对已经较老的Tiger呢?原因很简单:在以往各版Java的升级中,更多的是修正一些漏洞或增加和改进一些库函数,而J2SE 5.0对Java语言直接从语法层面上进行了增强。Tiger是Java自1995年发布其1.0版本以来,就语言本身来讲变动最大的一次版本发布。让我们再次来简单回顾一下截至J2SE 5.0,Java语言各版本的变化。

表1-2 Java语言各版本的变化

下面将一一介绍J2SE 5.0 Tiger为Java带来的语言新特性。(由于大部分新特性要用到面向对象的知识,笔者建议读者可以不求甚解地先大致浏览一遍本节,等学完第2章关于面向对象的知识后你就能更好地理解本节了。)

Tiger的语言新特性

J2SE 5.0 Tiger新增了一系列新的语言特性,把很多繁琐的原本得由程序员来完成的工作交给了Java编译器去完成,其目的是使开发人员能更容易地开发出更清楚、更简短、更稳定的程序代码。

泛型(Generics)

泛型是对类型的抽象,有点类似于C++中的模板,使得同一种操作可以适用于多种数据类型,其本质是参数化类型,也就是可以把操作的数据类型指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。示例如下:

    //J2SE1.4之前不使用泛型
    List number = new ArrayList();

    //J2SE 5.0之后使用了泛型
    List<Integer> number = new ArrayList<Integer>();

泛型提供了一种方式让你的代码可以告诉编译器,你的集合是什么数据类型的。采用泛型的好处正在于可以在编译时尽早发现类型错误,提高类型安全性,避免了运行时抛出ClassCastException的类型转换异常,同时由于采用了泛型,也消除了代码中赋值时的类型转换,可以简化代码,增强代码可读性。

泛型是J2SE 5.0引入的最为重要的语言新特性之一。本书后面有章节专门介绍它。

注释(Annotation)

在越来越多的Java程序框架及应用开发中,尤其是企业应用中,XML起到了举足轻重的作用。为了降低耦合度,提高可扩展性和可维护性,配置文件或部署脚本往往采用XML文件的形式存放。但是其副作用也随之而来了,一来XML文件在Java编译器检查范围之外,安全性降低,再者,程序员光看Java源代码不足以清楚地理解程序的运行逻辑。为了避免这些副作用, J2SE 5.0 引进了注释(Annotation),它允许对方法(method)、字段(fields)、类(class)进行标记,允许开发和部署工具通过反射机制以编程方式读取这些标记,并以某种形式处理它们。例如,生成Java源程序、XML配置文件等。注释也叫元数据(Metadata),从字面理解,就是关于数据的数据。注释可以被工具从源代码中读取,从编译后的.class文件中读取,也可以通过反射机制在运行时读取。提供了便捷的同时,注释有时会使你的代码更难理解,如果在编程的时候不小心漏了一两处注释,往往会使整个程序的执行逻辑发生改变,而这恰恰又是编译器很难发现的,所以在使用时还是得注意场合,防止滥用。注释的引入倡导了一种“声明式”的编程风格,也就是程序员只要声明要做什么,而由工具生成代码来具体执行。J2SE 5.0中预定义了3种标准注释:@Override、@Deprecated和@SupressWarnings。@Override只能用在方法上,说明某个方法覆盖了它父类的同名方法。@Deprecated则注释了某个方法或字段已过时,不应该再使用。@SupressWarnings 允许你关闭类、方法、域在编译期的警告。除了预定义的注释以外,J2SE 5.0还允许使用如下的用户自定义注释:

    public @interface Marked {}

注释类型的定义十分简单,和接口(Interface)的定义相似,只是在接口的关键字 interface前面再加一个@。当我们用定义好的注释类型来具体注释一个声明的时候,可以把它当作我们平常所用的public或private等修饰符(Modifier)一样来用,只是它通常放在整个声明的最开始处。使用时只须在注释的类名前加上一个@,然后加上一组在括号里面的“name-value”对。具体语法和用法可以查询Java文档,例如:

    @Marked public class Paint{name1=value2,name1=value2… name=value}

J2SE 5.0还为注释本身提供了4种“注释的注释”,称为元注释(Meta-Annotation),分别为:@Retention(用来注释信息保存多久,其值可以是SOURCE、CLASS、RUNTIME);@Target(对注释使用的限制,用来指定Annotation类型可以用在哪一些元素上,如TYPE(类型)、FIELD(字段)、METHOD(方法)等;@Documented(标注会在javadoc中显示的注释);@Inherited(被此注释标注的类会自动继承父类的注释)。

自动装箱/拆箱(Autoboxing/Auto Unboxing)

Java不是完全的面向对象,这一点自从它发布以来就一直广受争议。具体来说,Java的基本类型本身却不是对象,如int、char、boolean等。你不能像对待其他引用类型那样来对待它们,例如你不能直接把基本类型的值装入集合(Collection)中,因为它只接受引用类型的对象,此时你就须要通过将它转换成相应的包装类(wrapper classes),如Integer、Character、Boolean来完成此操作。J2SE 5.0引进了“自动装箱/自动拆箱”机制,它免去了在基本类型(如int)及包装类(如Integer)之间进行手工转换的繁琐。

    //J2SE1.4之前版本
    Integer i = new Integer(100);
    int i2 = i.intValue();   //手工通过包装类转换

    //J2SE 5.0之后
    Integer i =100;  //自动装箱,基本类型自动转为包装类(int  –>  Integer)
    int i2=i;        //自动拆箱,包装类自动转换为基本类型(Integer  –>  int)

“自动装箱/自动拆箱”是由J2SE 5.0提供的一种基本数据类型和其相应的参考数据类型之间的自动转换机制,但是它的自动转换势必带来一些额外的系统开销,因此并不建议将它使用在科学计算或循环语句中。当你享受 Java提供的这个新特性带来的便利时,要问一下是否使用得当?毕竟此特性的引进不是为了让基本数据类型(如 int)完全代替其相应的包装类(如Integer),反之亦然。它们各有各的长处和用武之地。

增强的for 循环(“for-each”)

为了简化对集合和数组的遍历,以及尽量减少迭代过程中的出错几率,J2SE 5.0提供了一个简单的增强型循环语句结构,“for-each”循环。其语法如下:

    for(variable : collection);

其实“:”读作“in”,整个for-each循环可以读作for each variable in collection

举例如下:

    //J2SE1.4之前版本
    int sum = 0;
    Integer[] numbers = calculateNumbers();
    for(int i=0; i < numbers.length ; i++) //普通for循环
    sum += numbers[i];

    //J2SE 5.0之后
    int sum = 0;
    for( int number: calculateNumbers())  //for-each循环
    sum += number;

for-each循环是为迭代而生的,尤其是对嵌套的循环更为适用。它隐藏了迭代和数组中的游标,减少了出差错的机会,也使得代码更为整洁。但是正是由于它对程序员隐藏了游标,当你要对循环中的某个具体对象进行操作时,for-each就无能为力了,此时你还是得用回其他循环控制结构。

枚举类型(Enumeration)

J2SE 5.0新增了枚举类型enum,它是作为一种特殊形式的“类”引进的,非但允许枚举一组特定的常量,而且允许在枚举类型中加入自己的任意形式的方法和字段,而且全部都是以类型安全的形式来表示的。enum会自动继承java.lang.Enum,而且提供了一些常规的方法:如name():枚举值的名;ordinal():其在枚举类中的位置。针对集合和映射,Java还特别提供了java.util.EnumSet和java.util.EnumMap这两个特殊的子类。如果你能预知集合只包含枚举类型,那么应该尽量使用这类专门的集合来代替HashMap或HashSet,这样更安全和高效。看个例子:

    public enum Grade {
        HD(100, 85), D(75, 84), C(65, 74), P(50, 64), CP(45, 49), F(0, 44);
        private int min, max;
        private Grade(int min, int max){
            this.min = min;
            this.max = max;
        }
    }

静态导入(Static import)

在引进“静态导入”这一概念之前,当要访问静态方法或静态变量时,我们必须给出完整的包及类的名称。引入了“静态导入”后,被导入类的所有静态变量和静态方法在当前类内可以被直接调用,不用再给出导入类的类名作为前缀。例如:

    import static java.lang.System.out;
    ...
    out.println("你好"); //不用再写System.out.println("你好");

只有当你要频繁地访问某个类中的静态成员时,你才值得使用静态导入特性,不然的话它将只会搞乱你的命名空间,使得你的程序可读性变差。所以要小心使用!

可变参数(Varargs)

在J2SE 5.0发布以前,要是你想模拟一个接受可变参数的方法,就要手工创建一个数组(或集合),然后将要传递给方法的值手工放入这个数组(或集合)。可变参数的引入简化了程序员的工作。调用具有不等长参数表的方法时,不用再由程序员把参数全都预装入数组,而由编译器帮你自动完成这一过程。可变参数的形式如下:

    public static String format(String pattern,Object... arguments);

最后的参数类型后面的3个点代表这个参数可能是以一个数组或一系列参数的形式传递进来的。注意,可变参数只可以用在最后一个参数的位置上。

Tiger的其他新特性

J2SE 5.0的新特性和提高还有很多,诸如函数库的变化、JVM性能的提高等,详情可以查看Sun的官方说明:http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html

提示:关于新增加的语言特性的具体语法,可查看Sun提供的Java文档。