在讲授计算机编程的知识之前,我首先做如下假设:
我假设您目前对计算机编程一无所知。如果您已经懂一些编程知识的话那么本文的开始部分对您来说就会显得十分简单。尽可放心跳过这些章节,从新知识处开始学习。
我假设您对计算机的使用有一些了解。具体说就是我假设您已经知道如何编辑、复制、删除和重命名文件,以及如何获取有关您的系统的信息等等。
为简单起见,我假设您的机器运行Windows95、98、2000、NT或XP操作系统。使用其他操作系统的用户将这里学到的概念运用到自己的系统中应该也是比较容易的。
我假设您有学习的欲望。
进行Java编程需要的所有工具都可以轻松在网上免费获得。网上还有大量的Java学习资料,所以学完本文以后您可以很容易去学习更多内容以继续提高水平。在这里学习的Java编程在编译器、开发环境、阅读材料等等上没有任何花销。学会了Java再学习其他的语言就变得容易了,所以这里是个不错的起点。
交待完这些事情,我们就准备好了。让我们开始吧!
编程术语
记住,我假定您不懂编程。下面是一些术语,它们将有助于您的理解:
计算机程序——计算机程序是一组指令,告诉计算机应该怎么做。指令可以告诉计算机将几个数相加,或比较两个数字并根据比较的结果作出决定,如此之类。计算机程序只是面向计算机的一组指令而已,正如菜谱是厨师的指令,乐谱是乐师的指令一样。计算机准确地执行这些指令的同时也就完成了有用的工作,如计算支票簿收支,或者在屏幕上显示一个游戏,或运行一个字处理程序。
编程语言——为了能使计算机辨识您给它的指令,这些指令需要以一种计算机能够理解的语言书写,即编程语言。有很多计算机编程语言:Fortran、Cobol、Basic、Pascal、C、C++、Java、Perl,正如有很多人类语言一样。它们都是用不同的方式来表达类似的概念。
编译器——使用人可以阅读的编程语言(如Java)写好程序后,还要用编译器将其翻译成计算机可执行的形式。您很可能在您的计算机上见到过EXE文件。这些EXE文件就是编译器输出的结果。它们是可执行文件——从人可读的程序翻译而成的机器可读的程序。
使用Java语言编程就需要一个Java编译器。下一节将指导您下载并安装一个编译器。一旦有了编译器我们就可以开始学习编程了。下载和安装过程将会持续几个小时,大部分时间用来下载几个很大的文件。您还需要有大约40兆字节的空闲磁盘空间(开始前请确定有足够的空间)。
下载Java编译器
为了在您的机器上配置起一个Java开发环境——您将使用一个“开发环境”来“开发”(编写)程序——您需要完成以下这些步骤:
1.下载一个包含Java开发环境(编译器和其他工具)的大文件。
2.下载一个包含Java文档的大文件。
3.如果您的机器上还没有安装WinZip(或可执行相同功能的程序),那么您需要下载一个包含WinZip的大文件并安装之。
4.安装Java开发环境。
5.安装文档。
6.调整环境变量。
7.全面测试。
为了方便,开始前最好在您的临时目录中创建一个新目录用于保存将要下载的文件。我们将它称为下载目录。
步骤1——下载Java开发环境
步骤2——下载Java文档
步骤3——下载并安装WinZip
步骤4——安装开发工具包
运行第一步下载的j2sdk-1_4_1-*.exe文件。他将自动解压并安装开发工具包。
步骤5——安装文档
阅读安装说明文档。它会要求您将文档文件移至刚才开发工具包的安装目录。将文档解压缩,文件就会被安排到适当的位置。
步骤6——调整环境变量
按照此页的要求,您需要改变路径变量。最简单的办法是打开一个MS-DOS窗口键入PATH看看当前的路径变量是什么,然后用记事本打开autoexec.bat按要求修改PATH环境变量。
步骤7——测试
现在您应该可以打开另一个MS-DOS窗口并键入javac了。如果一切设置妥当,那么您将看到屏幕将输出两行文字告诉您如何使用javac。这意味着一切已经准备就绪了。如果您看到“错误的命令或文件名”这条消息,则说明还没有准备好。请重新阅读安装说明检查哪里出了问题。确定PATH被正确设置并可用。回头重新阅读上面的步骤,问题不解决不要轻易放弃。
现在您已自豪地拥有一台能够编译Java程序的机器了。您已经准备好开始编写软件了!
顺便指出,刚才您解压缩的内容包括一个demo(演示)目录,其中包含许多精致的例子。所有的例子都可以立即执行,所以您不妨找到这个目录试运行一下其中的某些例子。许多例子都会发声,所以请打开扬声器。要运行例子,找到名如example1.html的网页文件并使用您常用的浏览器打开即可。
示例:创建一则简单java程序
您的第一个程序将是小巧可爱的。它将建立一个绘图区域并在其上绘制一条对角线。创建此程序您需要:
1.打开记事本键入(或复制粘贴)程序
2.保存程序
3.使用Java编译器编译程序生成一个Java程序
4.排除问题
5.建立一个HTML网页“包含”刚创建的Java程序
6.运行Java程序
这里是本节的示范程序:
import java.awt.Graphics;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
g.drawLine(0, 0, 200, 200);
}
}
步骤1——录入程序
建立一个新目录以保存程序。打开记事本(或其他可以创建TXT文件的文本编辑器)。将范例程序录入或复制粘贴到记事本窗口中。切记:输入程序的大小写敏感。因此必须按照范例程序中字母的大小写输入。重审以上编程步骤。如果录入内容和范例程序不是完全一致,则程序将无法正常运行。
步骤2——保存文件
将文件在第一步创建的路径下保存,文件名为FirstApplet.java。文件名大小写敏感。请确保字母“F”和“A”大写,其他字母小写,如前所示。
步骤3——编译程序
打开一个MS-DOS窗口。改变至包含FirstApplet.java的路径下(cd),键入:
javac FirstApplet.java
记住大小写敏感!或者编译成功,这时屏幕不输出任何信息,或者有错误发生。若没有错误,则会在目录里生成一个名为FirstApplet.class的文件与FirstApplet.java并列。
(请确保程序保存的文件名为FirstApplet.java而不是FirstApplet.java.txt。最简单的办法就是在MS-DOS窗口下键入dir然后查看文件名。若扩展名是.txt则请重命名文件去掉此扩展名。也可以运行Windows资源管理器在“查看”菜单下点击“选项”。确保“隐藏已注册的MS-DOS文件扩展名”选项处于未选中状态,然后在资源管理器中查看文件名。若需要则将文件改名。)
步骤4——排除问题
若有问题产生则想办法解决。将您的程序与上面的范例程序对比,使之完全相同。修改过程中不断编译程序,直到没有错误发生。若javac似乎不能工作,请回头参照上节内容检修安装的问题。
步骤5——建立HTML页面
创建一个HTML页面来包含小程序。另开一个记事本窗口。录入下面的内容:
将此文件存于同一目录中,文件名为applet.htm。
步骤6——运行程序
在您的MS-DOS窗口中键入:
appletviewer applet.htm
应该可以看见一条从左上角到右下角的对角线:
将小程序查看器的窗口拉大一些以查看整条对角线。您也可以将此HTML网页装载到任何现用的浏览器中,如NetscapeNavigator或微软IE,看到的结果是大致相同的。
至此您已经成功创建了您的第一个程序!
Java程序解析
那么刚才您到底都做了些什么呢?首先,您编写了一个极其简单的Java程序。该程序是能在网络浏览器中运行的Java程序,它和能在您的机器上独立运行的Java应用程序不同。(Java应用程序稍微复杂一些,而且也不如小程序流行,所以我们从小程序开始。)然后我们使用javac编译了这个小程序。接着我们创建了一个极其简单的网页来“包含”这个小程序。最后我们用appletviewer运行了小程序,当然您也可以方便地使用浏览器运行。
程序本身约有10行:
import java.awt.Graphics;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
g.drawLine(0, 0, 200, 200);
}
}
这大概是您能创建的最简单的Java小程序了。要完全理解此程序您需要学习很多知识,尤其是在面向对象编程技术的方面。既然我假定您毫无编程经验,因此我请您将注意力暂时集中到程序中的一行上:
g.drawLine(0, 0, 200, 200);
本程序的工作就是这一行完成的。它画出对角线。程序的其他部分都是为这行而做的准备工作,我们可以暂时忽略这些准备工作。这行代码告诉计算机从左上角(0,0)到右下角(200,200)画一条线。然后计算机就按照我们的指令画线。这就是计算机编程的基本要素了!
(还要注意的是,在上面的第五步我们将HTML页面中小程序的窗口设置为宽200高200。)
本程序中我们调用了一个drawLine方法(或称函数),并且传入了四个参数(0, 0, 200,200)。该行以一个分号结束。分号的作用相当于句子结尾的句号。该行开始处的g.说明我们调用的是特定对象g的方法drawLine(该行再上面一行表明g是属于Graphics类的对象——我们将在本文后面具体介绍类和类的方法)。
方法就是一条命令,它告诉计算机完成某件事情。本例中的drawLine告诉计算机在指定的两点(0, 0)和(200,200)之间画一条线。您可以认为窗口的原点(0,0)位于左上角,X和Y轴的正向分别指向原点右侧和下侧。屏幕上一个点(像素)就是数轴上的一个单位。
试着用不同数字代替四个参数。改变一两个参数,保存修改,然后用javac重新编译并用appletviewer重新运行每次修改的结果。看看您能发现什么。
除了drawLine还有什么其他函数呢?可以通过查阅Graphics类的文档来获得信息。在您安装Java开发工具包并将文档文件解压缩的过程中,一个名为java.awt.Graphics.html的文件就被安装到了您的机器上。此文件即是Graphics类的说明文档。这个文件在我的机器上的具体路径是D:jdk1.1.7docsapijava.awt.Graphics.html。在您机器上这个路径很可能会略有不同,但基本相似,这取决于您安装的具体位置。找到此文件并打开。文件的开始部分有一节叫做“方法索引”。它列出了这个类支持的所有方法。drawLine方法是其中之一,但是还有许多别的方法。您可以画出的内容包括但不限于:
直线
圆弧
椭圆
多边形
矩形
字符串
字符
请阅读这些不同方法的说明并加以试验,从中发现您可以用它们做什么。例如,试试下面的代码:
g.drawLine(0, 0, 200, 200);
g.drawRect(0, 0, 200, 200);
g.drawLine(200, 0, 0, 200);
它将画出一个有两条对角线的方框(别忘将窗口拉大以查看全图)。试着画一些其他图形。阅读文档并尝试使用setColor方法改变颜色。例如:
import java.awt.Graphics;
import java.awt.Color;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
g.setColor(Color.red);
g.fillRect(0, 0, 200, 200);
g.setColor(Color.black);
g.drawLine(0, 0, 200, 200);
g.drawLine(200, 0, 0, 200);
}
}
注意程序的第二行增添了import语句。程序运行的结果如下:
现在您可能在想:“他怎么知道要用Color.red而不是简单的red,他又是怎么知道要增添第二个import行的呢?”这是通过例子学来的。因为我刚向您展示了一个调用setColor方法的例子,所以您现在知道了要改变颜色就用Color.后接颜色的名字作为setColor方法的参数,并且要在程序开始处添加适当的import语句。如果您查阅setColor的文档,可以通过一个链接查询到Color类的信息,其中包括一个所有可用颜色名字的列表,还有关于创建新(无名)的颜色的技巧的说明。您阅读到这些信息,将它们记在脑子里,就知道如何用Java改变颜色了。这是作为程序员的关键:学习技巧并记住为写下一个程序使用。您或者通过例子(如本文中的)学习这些技巧,或者通过阅读说明文档,或者通过察看示例代码(如在demo路径下的那些)。如果您有一个喜欢发现、学习和记忆的大脑,那么您一定会爱上编程的!
本节中,您学习了如何编写线性、顺序执行的代码:从开始直到结束都由方法调用组成的代码快。(试试在画红色矩形之前画出直线——它会被矩形覆盖掉成为不可见的。代码行的顺序很重要。)顺序代码构成了所有计算机程序的基本核心。尝试一下所有不同的绘制方法,看看您有什么发现。
程序缺陷及调试
学习编程的过程中您会注意到自己总是会犯许多错误,或者想当然做出一些错误的假定,这都会使程序:1)无法通过编译,或者2)执行时得出奇怪的结果。程序的这些问题称为程序缺陷(我们常说的bug),而排除它们的过程称为调试。任何程序员约有一半的时间都花在调试程序上。
您有的是时间和机会制造自己的程序缺陷,但为了使我们对可能出现的各种错误更加熟悉一些,现在让我们人为制造一些程序缺陷。试着删除您的程序中某行结尾的分号,然后用javac编译。编译器会给出一条错误消息。这叫做编译错误。您必须排除所有的编译错误才能执行程序。试着将一个函数的名字写错,或者忽略一个“{”不写,或者删掉一行import语句等等,这些可以让您熟悉许多种编译错误消息。初次看到某种类型的编译错误时您可能很是烦恼,但是经过上面这样用故意造成的已知错误多次试验以后,您就会熟悉许多常见错误了。
程序缺陷还包括执行(或运行时)错误,发生于程序可以通过编译,但是在运行的时候不能给出预想的输出的情况。例如,下面代码将绘制一个带两条交叉对角线的红色矩形:
g.setColor(Color.red);
g.fillRect(0, 0, 200, 200);
g.setColor(Color.black);
g.drawLine(0, 0, 200, 200);
g.drawLine(200, 0, 0, 200);
但是下面的代码只能产生红色的矩形(两条直线被它覆盖了):
g.setColor(Color.black);
g.drawLine(0, 0, 200, 200);
g.drawLine(200, 0, 0, 200);
g.setColor(Color.red);
g.fillRect(0, 0, 200, 200);
两段代码几乎完全一样,但是执行后产生的结果却大不相同。如果您希望看到两条对角线,则第二段代码就包含了一个缺陷。
这里是另一个例子:
g.drawLine(0, 0, 200, 200);
g.drawRect(0, 0, 200, 200);
g.drawLine(200, 0, 0, 200);
上面的代码生成一个具有黑色轮廓线和两条对角线的方框。而下面这段代码只产生一条对角线:
g.drawLine(0, 0, 200, 200);
g.drawRect(0, 0, 200, 200);
g.drawLine(0, 200, 0, 200);
同样,如果您希望看到两条对角线,则第二段代码包含一个缺陷(请查看第二段代码找出错误)。这类错误因其隐蔽性可能需要花很多时间才能找到。
您将有充裕的时间练习查找自己程序中的缺陷。程序员平均要花大约一半的时间进行程序缺陷的排查。程序发生缺陷错误的时候不要灰心——它们是程序员编程生涯的一个正常的组成部分。
变量
所有的程序都使用变量临时存储各种数据。例如,当程序运行到某个阶段时请求用户输入一个数字,则您要用一个变量存储输入数据供以后使用。
变量必须在程序中被定义(或声明)后才能使用,您必须为每个变量确定一个具体类型。例如,您可能声明某变量为保存数字的类型,又声明另一个变量为保存人名的类型。(因为Java要求在使用变量前显式定义变量并声明变量值的类型,所以Java被称为是一个强类型的语言。有些语言则没有这些要求。一般说来,在创建大型程序时,强类型有助于减少程序错误。)
import java.awt.Graphics;
import java.awt.Color;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
int width = 200;
int height = 200;
g.drawRect(0, 0, width, height);
g.drawLine(0, 0, width, height);
g.drawLine(width, 0, 0, height);
}
}
这个程序中我们声明了两个名为width和height的变量。我们将其类型声明为int。一个int型的变量可以保存一个整数(如1、2、3等)。我们将两个变量都初始化为200。我们也完全可以这样写:
int width;
width = 200;
int height;
height = 200;
第一种形式只是输入起来稍快一些。
将变量赋予初值的过程称为初始化变量。一种常见的程序错误是忘记初始化变量。为重现此错误,试删除代码的初始化部分(“=200”)然后重新编译程序观察后果。您会看到编译器将发现这个问题。顺便指出,这是编译器的一个非常好的特性。它将为您节省许多时间。
Java支持两种变量:简单(初级)变量和类。
int是简单变量的类型。这种变量可以保存一个数字,此外别无他长。您只要声明一个int变量,设置它为某个值后使用即可。另一方面,类可以包含多个成员和方法,这些方法能简化类的使用。一个易于理解的类的好例子就是Rectangle类,让我们从它开始。
我们一直使用的那个程序有一个局限:他总是假定窗口大小是200乘200像素。为什么我们不问问窗口“您的尺寸有多大?”,然后据此调整我们的矩形和对角线的大小呢?如果您回头查看Graphics类的说明文档(java.awt.Graphics.html——那个列出了所有可用的绘图函数的文件),您会发现其中有一个叫做getClipBounds的函数。点击此函数名浏览它的完整说明。这个函数没有参数但是会返回一个Rectangle类型的值。返回的矩形包含了绘图区的宽度和高度。若在此文档页面中点击Rectangle就会被转到Rectangle类(java.awt.Graphics.html)的文档页面。查看页首的变量索引您会发现这个类包含四个名字分别为x、y、width和height的变量。因此我们将要做的就是用getClipBounds得到代表画板边界的矩形,然后从这个矩形中提取宽度和高度数据,将它们保存在前一个例子中创建的width和height变量中,如下所示:
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Rectangle;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
int width;
int height;
Rectangle r;
r = g.getClipBounds();
width = r.width - 1;
height = r.height - 1;
g.drawRect(0, 0, width, height);
g.drawLine(0, 0, width, height);
g.drawLine(width, 0, 0, height);
}
}
当运行上面程序的时候您会发现矩形和对角线恰好充满绘图区域。而且改变窗口大小时矩形和对角线还会自动重画适应新的窗口大小。这段代码引入了五个新概念,让我看一看:
1.首先,因为我们使用了Rectangle类,所以要在程序的第三行引进java.awt.Rectangle。
2.我们在本程序中声明了三个变量:两个(width和height)int型的,一个(r)Rectangle型的。
3.我们使用了getClipBounds函数获得绘图区域的大小。此函数没有参数所以我们也就不传入参数(使用“()”),但是它返回一个Rectangle。我们写下的代码“r= g.getClipBounds();”其意思是说:“请将返回的矩形赋值给变量r。”
4.变量r是Rectangle类型的,它其实包含四个变量:x、y、width和height(通过阅读Rectangle类的说明文档可以知道这些变量名)。要访问它们需使用“.”(点)操作符。因此表达式“r.width”的意思就是“从变量r中取出名为width的变量”。这个值被保存到我们的名为width的局部变量中。在此过程中我们减去了一个1。试试不做减法会是什么结果。再试试减去五会是什么结果。
5.最后,我们在绘图函数中使用了width和height。
学到这里常常提出的一个问题就是:“我们真有必要声明width和height变量吗?”答案是否定的。我们可以在绘图函数参数的位置直接输入r.width-1。创建变量只是为了使程序更容易阅读,因此这是一个应该养成的好习惯。
Java支持多种简单变量类型。三种最常见的类型是:
int——整型数值(1、2、3……)
float——十进制小数(如 3.14159)
char——字符值(a、b、c……)
可以用简单类型进行数学运算。Java能够识别+(加)、-(减)、*(乘)、/(除)和几种其他的运算。这里有一个在程序中使用这些运算符的例子。假设您要计算一个半径为3米的圆球的体积。可用下面的代码完成:
float diameter = 10;
float radius;
float volume;
radius = diameter / 2.0;
volume = 4.0 / 3.0 * 3.14159 * radius * radius *radius;
第一行运算的意义是:“将diameter变量的值除以2.0,结果保存在radius变量中。”可见“=”符号在这里的意义就是:“将右侧计算的结果保存到左侧的变量之中。”
如何使一个顺序代码块重复地执行
计算机尤其擅长的工作之一就是进行重复的计算或操作。在前面的几节中我们看到了如何编写“顺序代码块”,所以下面我们将讨论如何使一个顺序代码块重复地执行。
例如,我让您画出下面的图形:
不妨先画出所有的水平线,像这样:
绘制这些线的一种方法是编写一个顺序代码块:
import java.awt.Graphics;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
int y;
y = 10;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
y = y + 25;
g.drawLine(10, y, 210, y);
}
}
(对于一些新程序员来说,“y = y +25;”这条语句初看起来很奇怪。它的意思是说:“将变量y当前的值加上25,结果仍存回到y。”因此如果在该行执行之前y的值是10,则该行执行后y的值将立即变成35。)
看过以上代码的多数人会立刻注意到有两行代码被一遍遍重复了。在我们这个特例中,重复现象还不是很严重。但可以想像如果需要绘制包含上千个行和列的网格时,用这种方法编程将会是多么劳累。解决此问题的办法就是循环,如下所示:
import java.awt.Graphics;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
int y;
y = 10;
while (y <= 210)
{
g.drawLine(10, y, 210, y);
y = y + 25;
}
}
}
运行程序时您会看到它会绘制九条200像素长的水平线。
while语句是Java中的一种循环语句。该语句告诉Java按照如下方式工作:执行到while语句时,Java查看括号中的表达式后判断:“y是否小于等于210?”
如果答案是肯定的,Java将进入用花括号({})包围的代码块。循环发生在代码块的结尾处。当Java执行到结尾的花括号时就返回到前面的while语句处回答同样的问题。这种循环过程可能要进行许多次。
如果答案是否定的,Java将跳过用花括号包围的代码块继续执行。
因此您可以看到,程序开始运行时y的初值是10。10小于210,所以Java进入花括号代码块,绘制从(10,10)到(210,10)的直线,将y设为35,然后回溯到while语句。35小于210,所以Java进入花括号代码块,绘制从(10,35)到(210,35)的直线,将y设为60,然后回溯到while语句。此过程一直重复直到y终于超过了210,然后程序结束。
在程序中加入第二个循环即可完成网格的绘制,如下所示:
import java.awt.Graphics;
public class FirstApplet extendsjava.applet.Applet
{
public void paint(Graphics g)
{
int x, y;
y = 10;
while (y <= 210)
{
g.drawLine(10, y, 210, y);
y = y + 25;
}
x = 10;
while (x <= 210)
{
g.drawLine(x, 10, x, 210);
x = x + 25;
}
}
}
可见一个while语句包含三部分:
一个初始化步骤,将y设为10。
一个求值步骤,在while语句的括号中。
while语句的某处会有一个增量步骤,递增y的值。
Java支持另一种比while语句更为紧凑的方式完成同样的工作。这就是for语句。如果您有如下的while语句:
y = 10;
while (y <= 210)
{
g.drawLine(10, y, 210, y);
y = y + 25;
}
那么等价的for语句看起来就是这样子:
for (y = 10; y <= 210; y = y +25)
{
g.drawLine(10, y, 210, y);
}
可见for语句的全部工作是将初始化、求值和增量步骤精简到一个短行之中。它只是缩短了您编写代码的长度,仅此而已。
关于循环顺便提出下面两点值得注意的地方:
许多情况下将y初始化为210然后在循环中每次递减25同样是很容易的。求值部分的问题将变为:“y是否大于等于10?”您可以选择两种方法中的任何一种。多数人觉得用加法比用减法更舒服一些。但您可能有不同的感觉。
增量步骤十分重要。假如您无意间漏写了循环中“y=y+25;”这行,于是y的值将不会改变——它总是等于10。因此它永远不会超过210,循环也就会无限地进行下去(直到你关闭计算机或程序窗口时才停止)。这种情况称为无限循环,是一种常见的编程错误。