品过第一杯咖啡后,你肯定急于了解Hello World!程序是如何编写并工作的,以及如何编写其他Java程序。在这章中,让我们回味第一杯咖啡,并且深入分析Java程序的结构。
之所以把Java注释和文档功能放在最前面介绍,是因为Java程序的理念使然——所谓兵马未动粮草先行。
几乎所有编程语言都提供在源代码中添加注释的功能,开发者通过注释给自己或代码的阅读者进行备忘或提示,好比读书时在书上的空白处写笔记,或在屋子里使用N次贴。Java语言一个优秀思想便是——编写源代码并非唯一重要的工作,给源代码加上详细的注释同样重要。道理很简单,源代码和Java的字节码不同,字节码是给电脑看的,而源代码是给人阅读的,没有好的文档与注释,阅读源代码必须猜测源代码作者的意图,势必枯燥而且效率低下。
Java中的注释一共有两种,我们的Hello World!程序麻雀虽小但是五脏俱全,全部都用到了。下面是Hello World!程序的源代码:
/*
* Created on 2004-6-4
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
/**
* @author gary chan
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class HelloWorldApp {
public static void main(String[] args) {
// 打印Hello World!字样
System.out.println("Hello World!");
}
}
第一种注释是从C语言继承过来的风格,注释从/*开始,到*/结束,它们必须成对使用,之间可以换行。Hello World!程序开头部分就是这种风格的注释,记载着这个源程序的创始时间和一些提示。许多程序员为了美观,喜欢在多行注释前加入一个*符号,从而就形成了上面的格局。当然,这个注释的内容是Eclipse自动生成的,你可以通过修改Eclipse的代码模板来修改自动生成的内容。
第二种注释是从C++语言继承过来的单行注释风格,注释从//开始,一直到这行结束。这种风格的注释非常容易使用,你不必低头在键盘上连续寻找/和*键,只需要连续按下/键两次。同时,不需要像C语言风格注释那样特意使注释符号配对。Hello World!程序中“// 打印Hello World!字样”就是这种风格的注释。
如果你的洞察力敏锐,你会发现Hello World!程序中还有一处用/**和*/包裹起来的的代码并不属于以上任何一种注释。没错,这是Java文档(Java documentation)。文档与注释不同,注释一般比较随意,反映的是局部语句的功能或声明,而文档是与代码的结构相关的,好比是代码的摘要,给人一个结构化的总体观念。特别地,Java文档所注释的,是紧随其后的类、变量或方法。
我们还是结合Eclipse来说明Java文档的应用。首先在Eclipse中打开Hello World!程序。试试看把鼠标移动到HelloWorldApp字符上面去,是不是显示了如图1所示的效果(图1 Eclipse自动显示Java文档的功能)?
没错,当你把鼠标移动到一个Java类、变量或方法上,Eclipse将通过代码分析技术在源代码中萃取出相应的Java文档并且显示给你看,如果该Java元素有文档的话。
下面让我们为main方法编写Java文档来亲自体验一下。首先把光标移动到public class HelloWorldApp {之后并回车以便插入一空白行。然后,输入/**并且回车,你会发现Eclipse自动为你生成如一个Java文档块,并且自动识别出main方法有一个名为args的参数(很神奇吧?)。把该文档改写成这样:
/**
* 这是主函数,程序将从这里开始运行。
* @param args 命令行参数
*/
然后你把鼠标移动到main上面,是不是得到明明白白的文档信息了?
实际上,Java文档功能是贯穿于Java语言中的重要功能。但当你把光标移动到System.out.println("Hello World!")语句上,却得不到有用的含义以及参数的用法,该语句还是Java内置的API呢。怎么会这样子?
聪明的你一定想到答案了——一定是Java API的Java文档没有配置好嘛。没错,J2SE SDK并不包含Java API的Java文档,需要单独下载。你可以从http://java.sun.com/j2se/1.4.2/download.html下载到J2SE 1.4.2的文档,如果你从国外下载不方便,还可以到http://garychan.3322.org的Java资源栏目下载,约32.80MB。下载以后请把压缩包中的doc目录解压缩到C:\j2sdk1.4.2_04\中。
Eclipse默认使用JRE作为Java虚拟机。然而,使用J2SE SDK本身是更好的选择,因为你可以开启查看Java API文档的重要功能,这对于提高软件的开发效率以及深刻体验Eclipse,有着重要意义。方法如下:
1.依次点击Eclipse菜单项中的Windows、Preferences。
2.展开Java/Installed JRE,按下Add,按照图2所示填写参数(图2 完成后按下OK键)。
3.在Installed JREs对话框中的J2SDK 1.4.2_04前面打上勾,按下“OK”关闭Preferences对话框。Eclipse会提示你需要重新编译一次,“OK”即可。
好了,现在把光标移动到println上看看是不是和图3所示一样呢(图3)?
怎么样,该方法的详细使用说明都有了吧?如果内容比较多,按下F2锁定之后便可以察看全部的信息。以后有什么API不明白,不用苦苦上网搜索了,Java API文档本身就是Java API的大百科,再配合Eclipse的自动显示功能,实在方便得不行。
顺便说一句,Java还提供了从源代码中自动萃取Java文档,生成HTML文件以便单独阅读的机制,那就是J2SE SDK提供的javadoc工具。在Eclipse中,可以通过File菜单中的Export选项进行操作。
Just do it
试试把HelloWorldApp的Java文档改得更有调理,并且修改author属性成为你的名字。然后通过Eclipse内置的javadoc输出功能生成该项目的Java文档,感受一下Java文档代码并重的开发理念。
Java文档是一门学问。除了上面用到的param和author标签,Java文档还支持许多特定的标签,可以直接内嵌HTML代码以便得到优美的输出,还可以通过doclets自行扩展javadoc的处理机制。完整的说明文档请参考C:\j2sdk1.4.2_04\docs\tooldocs\windows\javadoc.html。
在品味第一杯咖啡时,我们说Hello World!程序定义了一个HelloWorldApp类(class)。
类是Java等面向对象语言的基础单位——一个定义了从类生成的实例(instance)中的数据和行为的关系的模板。当你实例化(instantiate)一个类以后便得到一个该类的对象(object),拥有类的全部数据和行为。一般我们把类和对象的数据称为变量,把行为称为方法。Java语言使用class关键词来定义一个类,之后的一对大括号定义了该类的变量和方法。我们的HelloWorldApp类没有变量,只有一个main方法。
类和对象的关系很好理解——类是一个抽象概念,好比“人”,而对象是一个具体的人,比如小布什、普京,他们作为人都有七情六欲(变量),都会衣食住行(方法)。
在第二篇连载《第一杯咖啡》中,为了避免类和对象的概念,我直接把HelloWorldApp称作了对象。现在你应该明白,这个说法是不准确的,HelloWorldApp是一个类,而main是这个类的方法。现在正式拨乱反正。
每个Java应用程序都必须包含一个main方法,语法如下:
public static void main(String[] args)
main方法包含三个修饰词:
(1)public:表示main方法可以由任何对象调用。
(2)static:表示这是一个类方法,区别于实例方法,与具体的对象无关。
(3)void:表示main方法没有返回值。
main方法是Java语言中非常特殊的方法,类似于C/C++中的main函数。当Java解析器执行Java应用程序,它首先执行这个Java类的main方法。你应该把程序的逻辑,比如打印Hello World!字样,写在main里面。
main方法有一个参数,即args,它是一个字符串数组,操作系统通过这个机制传递命令行参数。由于Hello World!程序忽略命令行参数,所以这里不展开讨论了。
让我们以Hello World!程序来详细解释类和对象的使用。
Hello World!程序很小,只定义了最基本的HelloWorldApp类。虽然如此,它的确使用了其他类——System类:
System.out.println("Hello World!");
System类是Java API的成员之一,提供了操作系统无关地操作操作系统相关功能的能力,很拗口,不过的确如此。out是System的类变量(与前面提到的类方法的意思一致)。实际上,System的所有变量都是类变量,所有方法都是类方法——都是用static修饰的,你可以通过“.”操作符直接访问。比如,System类有一个getProperty类方法可以获取操作系统属性,至于具体是什么操作系统,你无需事必躬亲了。若把Hello World!程序的main方法修改成:
public static void main(String[] args) {
System.out.print("Hello ");
System.out.println(System.getProperty("user.name"));
}
运行程序,便会得到“Hello Gary Chan”的结果。呵呵,我们的程序可以认人了,长大了许多啊!
下面说说类变量的原理。Java应用程序装载System类的时候,一看到out是System的类变量,便自动初始化PrintStream类得到一个PrintStream对象,并且把这个对象赋给out变量。从而,你调用out的println方法,实际上是调用一个对象的实例方法。这样,Hello World!字样便输出了。
总结一下类变量、类方法和实例变量、实例方法的关系:
(1)类变量或者类方法是和特定的类相关的,Java将给每个类分配一个类变量,无论这个类有多少实例。可以通过类名来操作类变量和类方法。
(2)实例变量或者实例方法是与特定的对象(类的实例)相关,每个对象都有自己专用的实例变量。可以通过实例名来操作实例变量和实例方法。
这回我们把Hello World!程序剖析得淋漓尽致。虽然一个小小的Java程序就有那么多门道,但是,不经历风雨怎么见彩虹,希望你能够透彻感受Java语言的点滴道理,从而快速步入Java的圣堂。
不要小看Java文档的重要性。Java有许多值得尊敬的理念,所谓没有规矩不成方圆,你应该理解并且贯彻它,这样才能够写出漂亮的代码。