
1.3 Java应用程序
下面开始编写我们的第一个Java应用程序——HelloWorld。在编写、编译以及运行程序的过程中如果遇到问题,读者可以参考1.3.4小节的常见问题解答。
1.3.1 编写源代码
打开UltraEdit文本编辑器,新建一个文件,并输入例1.1中的源代码,如图1.8所示。

图1.8 编写源代码
例1.1 HelloWorld.java
/** * HelloWorld * 在输出窗口显示"Hello World!" */ public class HelloWorld{ public static void main(String[] args){ //在屏幕上输出 "Hello World!" System.out.println("Hello World!"); } }
注意:由于Java编译器和解释器对于代码中的字符是大小写敏感的,所以在按照本书内容输入代码、命令以及文件名时,应注意大小写是否正确。
代码输入完毕后,将其保存成一个文件,取名为HelloWorld.java,并存放到一个指定的目录中去(如E:\Chapter01\code)。
注意:该文件名必须是HelloWorld(与公开类的类名相同,并且大小写也要一样,这是由Java编译器和解释器是大小写敏感而决定的),并且扩展名一定是.java。
打开一个DOS窗口,进入HelloWorld.java文件所在的目录,例如:
cd E:\Chapter01\code
然后,在命令行输入如下命令:
DIR
按Enter键后,可以发现目录E:\Chapter01\code中有一个文件,名字为HelloWorld.java,这就是我们刚才保存的源代码文件,如图1.9所示。

图1.9 源代码文件
1.3.2 编译源代码
可执行文件javac.exe位于Java安装目录的bin子目录中,称为Java编译器(Java Compiler ——javac名称的由来),用于对指定的Java源代码进行编译工作。
如图1.10所示,在命令提示行输入以下命令并按Enter键:

图1.10 编译源代码
javac HelloWorld.java
如果屏幕上没有出现错误提示,则表示已经正常完成了编译工作。再次使用DIR命令,可以发现目录下多了一个文件HelloWorld.class,即编译好的中间字节码(bytecode)文件,如图1.11所示。

图1.11 编译结果
编译好的中间字节码可以在不同平台的Java虚拟机上运行。正是使用了这种将源代码编译成中间字节码状态的技术,使得Java具备了跨平台的能力。
1.3.3 运行程序
可执行文件java.exe同样位于Java安装目录的bin子目录中,称为Java解释器,用于对指定的Java中间字节码进行解释并加以执行。
在命令提示行输入以下命令并按Enter键:
java HelloWorld
Java解释器将对中间字节码HelloWorld.class进行解释并执行,该程序的运行结果是在屏幕上输出“Hello World!”,如图1.12所示。

图1.12 执行程序
至此,我们已经完成了一个应用程序的开发过程。更复杂的应用程序无非是要编写更多的程序代码,基本步骤是一样的。
1.3.4 常见问题解答
虽然编写、编译以及运行例1.1是一个相对简单的工作。但对于初学者来说,仍可能出现各种错误。这里我们对初学者常会遇到的问题进行汇总,请读者特别注意以下几点。
(1)Windows系统对于DOS命令中字符的大小写是不敏感的。例如:输入DIR、dir或是Dir得到的结果是相同的。
(2)Java编译器和解释器对于代码中的字符是大小写敏感的,所以在输入代码时要特别注意字符的大小写,例如HelloWorld和helloWorld是不同的,同样public和Public也是不同的。
(3)保存源代码为文件时,要注意文件的命名。文件名一定要和源代码中公开类的类名一致(包括大小写),并且文件扩展名必须为.java。注意,如果将例1.1中的public class HelloWorld改为class HelloWorld(即HelloWorld不再是公开类),则可以将其保存为任何一个合法的并以.java为扩展名的文件,例如NotHelloWorld.java。在编译时使用命令:
javac NotHelloWorld.java
注意,编译得到的结果并不是NotHelloWorld.class,而是HelloWorld.class。因此,运行时,仍须使用如下命令:
java HelloWorld
如果用户使用:
java NotHelloWorld
系统将报如下错误:
Exception in thread "main" java.lang.NoClassDefFoundError: NotHelloWorld
这表示系统找不到类NotHelloWorld。理应如此!虽然我们将源代码保存为文件NotHelloWorld.java,但是其中确实只是定义了HelloWorld类,编译得到的中间字节码文件也是HelloWorld.class。
(4)如果在进行编译时报类似如下错误(如果读者使用的是英文版的操作系统,错误信息将是英文):
'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件。
则表示系统不能正确定位编译器javac.exe,原因是未能正确设定Path环境变量。请参考1.2.2小节关于环境变量的设定。
(5)编译时,需要用文件的全名,例如javac HelloWorld.java;解释运行时只需要用类名,而不需要带上.class,例如java HelloWorld。如果输入:
java HelloWorld.class
那么系统将报如下错误:
Exception in thread "main" java.lang.NoClassDefFoundError:HelloWorld/class
这是因为Java解释器将HelloWorld当作一个包(Package)名,并将class当作HelloWorld包中的一个类,从而产生错误。具体参见第4章中介绍包(Package)的章节。
1.3.5 理解例子
下面我们来详细分析一下例1.1。
在程序中加入适当的注释是一个良好的开发习惯,对于日后的维护具有重要的意义。例1.1的源代码中包含了两个注释块:
/** * HelloWorld * 在输出窗口显示"Hello World!" */
和
//在屏幕上输出 "Hello World!"
Java代码中具有以下3种类型的注释。
1. 单行注释
单行注释的结构如下:
// comments
从//至该行结束的内容是注释部分,编译器予以忽略。
2. 多行注释
多行注释的结构如下:
/* comments */
在/*和*/之间的所有内容均为注释部分,位于/*和*/之间的内容可以是一行或是多行。
3. 文档注释
文档注释的结构如下:
/ ** comments line 1 * comments line 2 * ... * comments line n */
这种类型的注释称为文档注释,同样编译器在编译过程中会忽略。文档注释一方面能够起到注释程序的作用,另一方面就是当使用JDK的文档生成工具javadoc.exe(位于Java安装目录下的bin子目录中)进行处理时,可以自动产生应用程序的文档。
public class HelloWorld{ ... }
上述代码块称为类定义块,用于定义一个类。类是面向对象设计中的一个基本概念(没有面向对象概念的读者可以参看后续章节中关于面向对象概念的描述),也是面向对象程序设计中的基本构建块。类是对特定类型对象所具有的属性(变量)和方法的蓝图性描述。实例化一个类就可以得到一个对象,该对象具有类所定义的属性和方法。举个例子来说,我们可以定义一个长方形的类,由于任何一个长方形都具有长度和宽度,所以长方形类可以含有两个属性:长和宽。此外,长方形类还可以有一个方法用于计算其面积。在定义好长方形类后,我们就可以实例化它,用于表示任何特定的长方形对象,如桌面、书面等。
在Java编程语言中,是这样定义类的:
modifier class name{ ... }
modifier是类的访问修饰符,在例1.1中是public,表示HelloWorld是一个公开类。关键字class表示开始一个类的定义。name是所定义的类名,例1.1中为HelloWorld。变量和方法的定义都必须包含在类定义块的一对大括号之间,例1.1中没有定义变量,并且只有一个方法main。
下面我们来看看HelloWorld类中唯一的main方法。实际上每个Java应用程序中必须包含一个这样的main方法,因为这是应用程序的入口,也就是说,应用程序是从起始类的main方法开始运行的。
注意:一个实际的应用程序往往由多个类构成,因此需要指定从哪个类开始运行,这个类就是起始类。例如java HelloWorld,则HelloWorld称为应用程序的起始类。
public static void main(String[] args)定义了main方法,该方法的定义中包含了三个修饰符:public、static以及void。public表示该方法是一个公开的方法,任何其他对象都可以调用该方法。static表示该方法是静态方法,也就是不需要生成该方法所在类的实例对象就可以直接调用。void表示该方法没有返回值。
当在命令行输入java HelloWorld并按Enter键后,Java解释器将调用HelloWorld的main方法,从而开始应用程序的运行。
main方法的参数是一个字符串类型的数组,用于接收命令行参数。
例如,如果在main方法中包含如下两行代码:
System.out.println("命令行参数1是 "+args[0]); System.out.println("命令行参数2是 "+args[1]);
编译完成后,在命令行输入:
java HelloWorld a b
按Enter键后,可以发现程序运行输出:
命令行参数1是 a 命令行参数2是 b
不重新编译程序,继续在命令行输入:
java HelloWorld b a
按Enter键后,可以发现程序运行输出:
命令行参数1是 b 命令行参数2是 a
至此,可以看出:从命令行输入的参数是存储在main方法的字符串类型数组参数中的。可以在不修改程序的条件下,通过使用不同的命令行参数来改变程序的运行输出。
注意:如果在阅读下面关于System.out.println的内容时存在困难,可以暂时先跳过。等学习完类和对象的概念后,再来阅读。
我们再来仔细看看main方法中唯一的一行代码System.out.println("Hello World!")。System是一个系统提供的类,在这个类中有一个变量out,该变量表示系统标准输出流,“.”表示引用类中的变量或是方法。需要注意的是,我们没有实例化System类就直接引用了其中的out变量,像这种不需要实例化直接通过类名就可以引用的变量称为类变量;类似地,不需要实例化就可以直接引用的方法称为类方法。而必须实例化成对象后才能使用的变量(方法)称为实例变量(实例方法),要引用实例变量或是实例方法必须通过对象来引用。该例子中out是System的类变量,指向的是系统标准输出流PrintStream,当System类被装载时,就会实例化一个PrintStream对象并赋值给out,这时候再调用out的实例方法println,将参数字符串打印到标准输出设备上(这里是屏幕显示器)。
这里我们还可以看出,实例方法/实例变量的引用类似于类方法/类变量的方式,都是通过“.”来引用。不同之处是类方法/类变量不需要生成实例,直接通过类名就能引用,而实例方法/实例变量必须实例化成对象后才能引用。
至此,可以发现,语句System.out.println("Hello World!")的作用就是将字符串“Hello World!”显示到显示器屏幕上。
注意:类方法或是类变量与一个特定的类相联系,不管一个类生成了多少个实例,运行系统只给该类分配一个类变量。通过类来引用类方法或是类变量。实例方法或是实例变量与一个特定的对象相联系,一个类生成了多个对象,每个对象都有独立的一份实例变量。只能通过对象来引用实例方法或是实例变量。