您的位置:寻梦网首页编程乐园Java天地Core Java>Java中文教程
Java 天地
Java中文教程

第一章Java 概 述

(转载:共六章)

§ 1.1 Java语言出现的背景、影响及应用前景。

一、背景

最近一年多来,在Internet上出现的特别吸引人的事件就是Java语言和用Java编写的浏览器HotJava。

1991年,SUN MicroSystem公司的Jame Gosling、Bill Joe等人,为在电视、控制烤面包箱等家用消费类电子产品上进行交互式操作而开发了一个名为Oak的软件(即一种橡树的名字),但当时并没有引起人们的注意,直到1994年下半年,Internet的迅猛发展,环球信息网WWW的快速增长,促进了Java语言研制的进展,使得它逐渐成为Int ernet上受欢迎的开发与编程语言,一些著名的计算机公司纷纷购买了Java语言的使用权,如MicroSoft、IBM、Netscape、Novell、Apple、DEC、SGI等r,因此,Java语言被美国的著名杂志PC Magazine评为1995年十大优秀科技产品,(计算机类就此一项入选),随之大量出现了用Java编写的软件产品,受到工业界的重视与好评,认为"Java是八十年代以来计算机界的一件大事",微软总裁比尔·盖茨在悄悄地观察了一段时间后,不无感慨地说:"Java是长时间以来最卓越的程序设计语言",并确定微软整个软件开发的战略从PC单机时代向着以网络为中心的计算时代转移,而购买Java则是他的重大战略决策的实施部署。

因此,Java的诞生必将对整个计算机产业发生深远的影响,对传统的计算模型提出了新的挑战。

SUN MicroSystem公司的总裁Scott McNealy认为Java为Internet和WWW开辟了一个崭新的时代。

环球信息网WWW的创始人Berners-Lee说:"计算机事业发展的下一个浪潮就是Java,并且将很快会发生的"。

看来,使用Java已成大势所趋!

MicroSoft和IBM两大公司都计划在Internet上销售用Java编写的软件。

Apple、HP、IBM、MicroSoft、Novell、SGI、SCO、Tandem等公司均计划将Java并入各自开发的操作系统,而负责开发并推广Java技术的SunSoft公司(这是SUN下属的一个子公司),将通过颁发许可证的办法来允许各家公司把Java虚拟机和Java的Applets类库嵌入他们开发的操作系统,这样各类开发人员就能更容易地选择多种平台来使用Java语言编程,不同的用户也就可以脱离Web浏览器来运行Java应用程序,这无疑是很受广大用户欢迎的,也为Java语言的应用开拓了极为广阔的前景。(当然,各类JavaOS之间的兼容性必须得到重视,好在JavaSoft已保证将监督这种兼容性)。

另外,由JavaSoft推出的完全用Java编写的Internet上新型浏览器HotJava,比去年alpha版更为实用,不仅能编制动态的应用软件,而且能编制完整的成套桌面应用软件,将来还会提供更多的能帮助编制动态应用软件的模块,显然,这也是为Java的应用提供了有力的例证。

今年6月7日,由SUN公司和台湾经济事务部信息发展局、台湾信息技术研究所等单位牵头,成立了一个"Java联盟",参加的有22个在台湾相当著名的计算机公司,并在台北建立一个"Java开发中心",在新竹建立一个"Java语言实验室",以掀起台湾开发与应用Java语言的热潮。

香港则在今年4月就举行了全岛的Java杯比赛,在计算机界掀起了学习Java的热潮(尤其是在大学生们中,出现了一批Java迷)。

有人预言:Java将是网络上的"世界语",今后所有的用其他语言编写的软件统统都要用Java语言来改写。

二、Java语言对软件开发技术的影响

工业界不少人预言:"Java语言的出现,将会引起一场软件革命",这是因为传统的软件往往都是与具体的实现环境有关,换了一个环境就需要作一番改动,耗时费力,而Java语言能在执行码(二进制码)上兼容,这样以前所开发的软件就能运行在不同的机器上,只要所用的机器能提供Java语言解释器即可。

Java语言将对未来软件的开发产生影响,可从如下几个方面考虑:

1. 软件的需求分析:可将用户的需求进行动态的、可视化描述,以提供设计者更加直观的要求。而用户的需求是各色各样的,不受地区、行业、部门、爱好的影响,都可以用Java语言描述清楚。

2. 软件的开发方法:由于Java语言的面向目标的特性,所以完全可以用O-O的技术与方法来开发,这是符合最新的软件开发规范要求的。

3. Java语言的动画效果远比 GUI技术更加逼真 ,尤其是利用 WW W提供的巨大动画资源空间 ,可以共享全世界的动态画面的资源。

4软件最终产品:用Java语言开发的软件可以具有可视化、可听化、可操作化的效交互、动画与动作",要它停就停,要它继续就继续,而这是在电影与电视播放过程中难以做到的。

5其它:使用Java语言对开发效益、开发价值都有比较明显的影响。

三、工业界对Java语言的评价

1996年5月29~31日,在美国旧金山召开了一个全世界Java语言开发者大会,(Java One Developer Confer-ence),出席会议的多达6500多人,来自工业界的超过一半,有人评价说:"这是近年来计算机界最光辉的一次盛会",一些工业界的老总们相当看好Java语言,认为它的使用将会引起一场软件革命。从软件的设计风格、设计方法、设计目标到设计过程,都会产生彻底的变革,"甚至会改变此星球的生活方式"。

在这次会上,Java的创始人之一James Gosling说:"Java不仅仅只是applets,它能做任何事情",Dta咨询公司的高级软件工程师Rich Kadel说:"Java不仅仅是一种程序设计语言,更是现代化软件再实现的基础;Java还是未来新型OS的核心;将会出现Java芯片;将构成各种应用软件的开发平台与实现环境,是人们必不可少的开发工具,……"。

由于各界都看好它,因此,各大公司都纷纷表示支持Java,Intel、Xerox公司声言将把Java嵌入到他们的产品中去。就连华尔街金融界也在投入资金人力用Java开发电子贸易、金融软件。

所以有人说:"现在第三方的开发商都团结在Java大旗周围了!",纷纷推出用Java开发的各种软件产品,以期尽快地占领市场。

四、Java语言的应用前景

Java语言有着广泛的应用前景,大体上可以从以下几个方面来考虑其应用:

1. 所有面向对象的应用开发,包括面向对象的事件描述、处理、综合等;

2. 计算过程的可视化、可操作化的软件的开发;

3. 动态画面的设计,包括图形图像的调用;

4. 交互操作的设计(选择交互、定向交互、控制流程等);

5. Internet的系统管理功能模块的设计,包括Web页面的动态设计、管理和交互操作设计等;

6. Intranet(企业内部网)上的软件开发(直接面向企业内部用户的软件);

7. 与各类数据库连接查询的SQL语句实现;

8. 其它应用类型的程序。

§ 1.2 Java的特点

Java是一个广泛使用的网络编程语言,它是一种新的计算概念。

首先,作为一种程序设计语言,它简单、面向对象、不依赖于机器的结构、具有可移植性、鲁棒性、安全性、并且提供了并发的机制、具有很高的性能。其次,它最大限度地利用了网络,Java的小应用程序(applet)可在网络上传输而不受CPU和环境的限制。另外,Java还提供了丰富的类库,使程序设计者可以很方便地建立自己的系统。

下面我们分别从这三个方面来讨论Java的特点,然后通过把Java与C,C++相比进一步指出它所具有的优点。

一、Java语言

Java语言有下面一些特点:简单、面向对象、分布式、解释执行、鲁棒、安全、体系结构中立、可移植、高性能、多线程以及动态性。

1.简单性

Java语言是一种面向对象的语言,它通过提供最基本的方法来完成指定的任务,只需理解一些基本的概念,就可以用它编写出适合于各种情况的应用程序。Java略去了运算符重载、多重继承等模糊的概念,并且通过实现自动垃圾收集大大简化了程序设计者的内存管理工作。另外,Java也适合于在小型机上运行,它的基本解释器及类的支持只有40KB左右,加上标准类库和线程的支持也只有215KB左右。库和线程的支持也只有215KB左右。

2.面向对象

Java语言的设计集中于对象及其接口,它提供了简单的类机制以及动态的接口模型。对象中封装了它的状态变量以及相应的方法,实现了模块化和信息隐藏;而类则提供了一类对象的原型,并且通过继承机制,子类可以使用父类所提供的方法,实现了代码的复用。

3.分布性

Java是面向网络的语言。通过它提供的类库可以处理TCP/IP协议,用户可以通过URL地址在网络上很方便地访问其它对象。

4.鲁棒性

Java在编译和运行程序时,都要对可能出现的问题进行检查,以消除错误的产生。它提供自动垃圾收集来进行内存管理,防止程序员在管理内存时容易产生的错误。通过集成的面向对象的例外处理机制,在编译时,Java提示出可能出现但未被处理的例外,帮助程序员正确地进行选择以防止系统的崩溃。另外,Java在编译时还可捕获类型声明中的许多常见错误,防止动态运行时不匹配问题的出现。

5.安全性

用于网络、分布环境下的Java必须要防止病毒的入侵。Java不支持指针,一切对内存的访问都必须通过对象的实例变量来实现,这样就防止程序员使用"特洛伊"木马等欺骗手段访问对象的私有成员,同时也避免了指针操作中容易产生的错误。

6.体系结构中立

Java解释器生成与体系结构无关的字节码指令,只要安装了Java运行时系统,Java程序就可在任意的处理器上运行。这些字节码指令对应于Java虚拟机中的表示,Java解释器得到字节码后,对它进行转换,使之能够在不同的平台运行。

7.可移植性

与平台无关的特性使Java程序可以方便地被移植到网络上的不同机器。同时,Java的类库中也实现了与不同平台的接口,使这些类库可以移植。另外,Java编译器是由Java语言实现的,Java运行时系统由标准C实现,这使得Java系统本身也具有可移植性。

8.解释执行

Java解释器直接对Java字节码进行解释执行。字节码本身携带了许多编译时信息,使得连接过程更加简单。

9.高性能

和其它解释执行的语言如BASIC、TCL不同,Java字节码的设计使之能很容易地直接转换成对应于特定CPU的机器码,从而得到较高的性能。

10.多线程

多线程机制使应用程序能够并行执行,而且同步机制保证了对共享数据的正确操作。通过使用多线程,程序设计者可以分别用不同的线程完成特定的行为,而不需要采用全局的事件循环机制,这样就很容易地实现网络上的实时交互行为。

11.动态性

Java的设计使它适合于一个不断发展的环境。在类库中可以自由地加入新的方法和实例变量而不会影响用户程序的执行。并且Java通过接口来支持多重继承,使之比严格的类继承具有更灵活的方式和扩展性。

二、Java Applet

Java语言的特性使它可以最大限度地利用网络。Applet是Java的小应用程序,它是动态、安全、跨平台的网络应用程序。Java Applet嵌入HTML语言,通过主页发布到Internet。网络用户访问服务器的Applet时,这些Applet从网络上进行传输,然后在支持Java的浏览器中运行。由于Java语言的安全机制,用户一旦载入Applet,就可以放心地来生成多媒体的用户界面或完成复杂的计算而不必担心病毒的入侵。虽然Applet可以和图像、声音、动画等一样从网络上下载,但它并不同于这些多媒体的文件格式,它可以接收用户的输入,动态地进行改变,而不仅仅是动画的显示和声音的播放。

三、丰富的类库

Java提供了大量的类以满足网络化、多线程、面向对象系统的需要。

1.语言包提供的支持包括字符串处理、多线程处理、例外处理、数学函数处理等,可以用它简单地实现Java程序的运行平台。

2.实用程序包提供的支持包括哈希表、堆栈、可变数组、时间和日期等。

3.输入输出包用统一的"流"模型来实现所有格式的I/O,包括文件系统、网络、输入

4.低级网络包用于实现Socket编程。

5.抽象图形用户接口包实现了不同平台的计算机的图形用户接口部件,包括窗口、菜单、滚动条、对话框等,使得Java可以移植到不同平台的机器。

6.网络包支持Internet的TCP/IP协议,提供了与In-ternet的接口。它支持URL连接,WWW的即时访问,并且简化了用户/服务器模型的程序设计。

四、Java和C、C++

对于变量声明、参数传递、操作符、流控制等,Java使用了和C、C++相同的传统,使得熟悉C、C++的程序员能很方便地进行编程。同时,Java为了实现其简单、鲁棒、安全等特性,也摒弃了C和C++中许多不合理的内容。

1.全局变量

Java程序中,不能在所有类之外定义全局变量,只能通过在一个类中定义公用、静态的变量来实现一个全局变量。例如:

Class GlobalVar{

public static global_var;

}

在类GlobalVar中定义变量global_var为public static,使得其它类可以访问和修改该变量。

Java对全局变量进行了更好的封装。而在C和C++中,依赖于不加封装的全局变量常常造成系统的崩溃。

2.Goto

Java不支持C、C++中的goto语句,而是通过例外处理语句try,Catch,final等来代替C、C++中用goto来处理遇到错误时跳转的情况,使程序更可读且更结构化。

3.指针

指针是C、C++中最灵活,也是最容易产生错误的数据类型。由指针所进行的内存地址操作常会造成不可预知的错误,同时通过指针对某个内存地址进行显式类型转换后,可以访问一个C++中的私有成员,从而破坏安全性,造成系统的崩溃。而Java对指针进行完全的控制,程序员不能直接进行任何指针操作,例如把整数转化为指针,或者通过指针释放某一内存地址等。同时,数组作为类在Java中实现,良好地解决了数组访问越界这一C、C++中不作检查的错误。

4.内存管理

在C中,程序员通过库函数malloc()和free()来分配和释放内存,C++中则通过运算符new和delete来分配和释放内存。再次释放已释放的内存块或未被分配的内存块,会造成系统的崩溃;同样,忘记释放不再使用的内存块也会逐渐耗尽系统资源。而在Java中,所有的数据结构都是对象,通过运算符new为它们分配内存堆。通过new得到对象的处理权,而实际分配给对象的内存可能随程序运行而改变,Java对此自动地进行管理并且进行垃圾收集,有效防止了由于程序员的误操作而导致的错误,并且更好地利用了系统资源。

5.数据类型的支持

在C、C++中,对于不同的平台,编译器对于简单数据类型如int,float等分别分配不同长度的字节数,例如:int在IBM PC中为16位,在VAX-11中为32位,这导致了代码的不可移植性,但在Java中,对于这些数据类型总是分配固定长度的位数,如对int型,它总占32位,这就保证了Java的平台无关性。

6.类型转换

在C、C++中,可以通过指针进行任意的类型转换,常常带来不安全性,而Java中,运行时系统对对象的处理要进行类型相容性检查,以防止不安全的转换。

7.头文件

C、C++中用头文件来声明类的原型以及全局变量、库函数等,在大的系统中,维护这些头文件是很困难的。而Java不支持头文件,类成员的类型和访问权限都封装在一个类中,运行时系统对访问进行控制,防止对私有成员的操作。同时,Java中用import语句来与其它类进行通讯,以便使用它们的方法。

8.结构和联合

C、C++中的结构和联合中所有成员均为公有,这就带来了安全性问题。Java中不包含结构和联合,所有的内容都封装在类中。

9.预处理

C、C++中用宏定义来实现的代码给程序的可读性带来了困难。在Java中,不支持宏,它通过关键字final来声明一个常量,以实现宏定义中广泛使用的常量定义。

§1.3.简单的Java程序

下面我们先介绍两个简单的Java程序,并对其进行分析。

例1.1.

public class HelloWorldApp {//an application

 public static void main (String args[ ]){

 System.out.println("Hello World!");

}

}

本程序的作用是输出下面一行信息:

 Hello World!

程序中,首先用保留字class来声明一个新的类,其类名为HelloWorldApp,它是一个公共类(public)。整个类定义由大括号{}括起来。在该类中定义了一个main()方法,其中public表示访问权限,指明所有的类都可以使用这一方法;static指明该方法是一个类方法,它可以通过类名直接调用;void则指明main()方法不返回任何值。对于一个应用程序来说,main()方法是必需的,而且必须按照如上的格式来定义。Jave解释器在没有生成任何实例的情况下,以main()作为入口来执行程序。Jave程序中可以定义多个类,每个类中可以定义多个方法,但是最多只能有一个公共类,main()方法也只能有一个,作为程序的入口。main()方法定义中,括号()中的Stringargs[]是传递给main()方法的参数,参数名为args,它是类String的一个实例,参数可以为0个或多个,每个参数用"类名参数名"来指定,多个参数间用逗号分隔。在main()方法的实现(大括号中),只有一条语句:

 System.out.println ("Hello World!");

它用来实现字符串的输出,这条语句实现与C语言中的printf语句和C++中cout<<语句相同的功能。另外,//后的内容为注释。

现在我们可以运行该程序。首先把它放到一个名为HelloWorldApp.java的文件中,这里,文件名应和类名相同,因为Java解释器要求公共类必须放在与其同名的文件中。然后对它进行编译:

 C:\>javac HelloWorldApp.java

编译的结果是生成字节码文件HelloWorldApp.class。最后用java解释器来运行该字节码文件:

C:\>java HelloWorldApp

结果在屏幕上显示Hello World!

我们再来看下面的一个例子:

例1.2

import java.awr.*;

import java.applet.*;

public class HelloWorldApplet extends Applet {//an applet

public void paint(Graphics g){

g.drawString ("Hello World!",20,20);

}

}

这是一个简单的Applet(小应用程序)。程序中,首先用import语句输入java.awr和java.applet下所有的包,使得该程序可能使用这些包中所定义的类,它类似于C中的#include语句。然后声明一个公共类HelloWorldApplet,用extends指明它是Applet的子类。在类中,我们重写父类Applet的paint()方法,其中参数g为Graphics类,它表明当前作画的上下文。在paint()方法中,调用g的方法drawString(),在坐标(20,20)处输出字符串""Hello World!",其中坐标是用象素点来表示的。

这个程序中没有实现main()方法,这是Applet与应用程序Application(如例1)的区别之一。为了运行该程序,首先我们也要把它放在文件HelloWorldApplet.java中,然后对它进行编译:

C:\>javac HelloWorldApplet.java

得到字节码文件HelloWorldApplet.class。由于Applet中没有main()方法作为Java解释器的入口,我们必须编写HTML文件,把该Applet嵌入其中,然后用appletviewer来运行,或在支持Java的浏览器上运行。它的<HTML>文件如下

<HTML>

<HEAD>

<TITLE>An Applet </TITLE>

</HEAD>

<BODY>

<applet code="HelloWorldApplet.class" width=200 height=40>

</applet>

</BODY>

</HTML>

其中用<applet>标记来启动HelloWorldApplet,code指明字节码所在的文件,width和height指明applet所占的大小,我们把这个HTML文件存入Example.html,然后运行:

C:\>appleviewer Example.html

这时屏幕上弹出一个窗口,其中显示Hello World!,显示结果如图:

从上述例子中可以看出,Java程序是由类构成的,对于一个应用程序来说,必须有一个类中定义main()方法,而对applet来说,它必须作为Applet的一个子类。在类的定义中,应包含类变量的声明和类中方法的实现。Java在基本数据类型、运算符、表达式、控制语句等方面与C、C++基本上是相同的,但它同时也增加了一些新的内容,在以后的各章中,我们会详细介绍。本节中,只是使大家对Java程序有一个初步的了解。

第二章 数据类型

§ 2.1 数据类型

数据类型指明了变量或表达式的状态和行为。Java的数据类型如下所示:

Java不支持C、C++中的指针类型、结构体类型和共用体类型。

本章我们主要介绍简单类型。

§2.2 常量与变量

一、常量

Java中的常量值是用文字串表示的,它区分为不同的类型,如整型常量123,实型常量1.23,字符常量‘a’,布尔常量true、false以及字符串常量"This is a constant string."。

与C、C++不同,Java中不能通过#define命令把一个标识符定义为常量,而是用关键字final来实现,如final double PI=3.14159(有关final的用法见[6.2.3])。

二、变量

变量是Java程序中的基本存储单元,它的定义包括变量名、变量类型和作用域几个部分。

①变量名是一个合法的标识符,它是字母、数字、下划线或美元符"$"的序列,Java对变量名区分大小写,变量名不能以数字开头,而且不能为保留字。合法的变量名如:myName、value-1、dollar$等。非法的变量名如:2mail、room#、class(保留字)等,变量名应具有一定的含义,以增加程序的可读性。

②变量类型可以为上面所说的任意一种数据类型。

③变量的作用域指明可访问该变量的一段代码。声明一个变量的同时也就指明了变量的作用域。按作用域来分,变量可以有下面几种:局部变量、类变量、方法参数、例外处理参数。局部变量在方法或方法的一块代码中声明,它的作用域为它所在的代码块(整个方法或方法中的某块代码)。

类变量在类中声明,而不是在类的某个方法中声明,它的作用域是整个类。

方法参数传递给方法,它的作用域就是这个方法。

例外处理参数传递给例外处理代码,它的作用域就是例外处理部分。

在一个确定的域中,变量名应该是唯一的。通常,一个域用大括号{}来划定。

有关类变量、参数传递以及例外处理将分别在[6.7.1]、[6.2.4]和第八章中讲述。

④变量的声明格式为:

type identifier[=value][,identifier[=value]… ];

例如: int a, b, c;

 double d1, d2=0.0;

其中,多个变量间用逗号隔开,d2=0.0对实型变量d2赋初值0.0,只有局部变量和类变量是可以这样赋初值的,而方法参数和例外处理参数的变量值是由调用者给出的。

§2.3 整型数据

一、整型常量:

与C,C++相同,Java的整常数有三种形式:

① 十进制整数,如123,-456,0

② 八进制整数,以0开头,如0123表示十进制数83,-011表示十进制数-9。

③ 十六进制整数,以0x或0X开头,如0x123表示十进制数291,-0X12表示十进制数-18。

整型常量在机器中占32位,具有int型的值,对于long型值,则要在数字后加L或l,如123L表示一个长整数,它在机器中占64位。

二、整型变量:

整型变量的类型有byte、short、int、long四种。下表列出各类型所在内存的位数和其表示范围。

int类型是最常使用的一种整数类型。它所表示的数据范围64位处理器。但对于大型计算,常会遇到很大的整数,超出int类所表示的范围,这时要使用long类型。

由于不同的机器对于多字节数据的存储方式不同,可能是?低字节向高字节存储,也可能是从高字节向低字节存储,这样,在分析网络协议或文件格?时,为了解决不同机器上的字节存储顺序问题,用byte类型来表示数据是合适的。而通常?况下,由于其表示的数据范围很小,容易造成溢出,应避免使用。

short类型则很少使用,它限制数据的存储为先高字节,后低?节,这样在某些机器中会出错。

三 、整型变量的定义,如:

byteb;//指定变量b为byte型

shorts;//指定变量s为short型

inti;//指定变量i为int型

longl;//指定变量l为long型

§ 2.4 浮点型(实型)数据

一、实型常量

与C,C++相同,Java的实常数有两种表示形式:

①十进制数形式,由数字和小数点组成,且必须有小数点,如0.123,.123,123.,123.0

②科学计数法形式。如:123e3或123E3,其中e或E之前必须有数,且e或E后面的指数必须为整数。

实常数在机器中占64位,具有double型的值。对于float型的值,?要在数字后加f或F,如12.3F,它在机器中占32位,且表示精度较低。

二、实型变量

实型变量的类型有float和double两种,下表列出这两种类型所?内存的位数和其表示范围。

数据类型所占位数数的范围

float 32 3.4e-038~3.4e+038

double 64 1.7e-308~1.7e+308

双精度类型double比单精度类型float具有更高的精度和更大表示范围,常常使用。

三、实型变量定义,如

floatf;//指定变量f为float型

doubled;//指定变量d为double型

[注]与C、C++不同,Java中没有无符号型整数,而且明确规定了?型和浮点型数据所占的内存字节数,这样就保证了安全性、鲁棒性和平台无关性。

§2.5字符型数据

一、字符常量

字符常量是用单引号括起来的一个字符,如‘a’,‘A’。?外,与C、C++相同,Java也提供转义字符,以反斜杠(\)开头,将其后的字符转变为另外的含义,下?列出了Java中的转义字符。

与C、C++不同,Java中的字符型数据是16位无符号型数据,它表?Unicode集,而不仅仅是ASCII集,例如\u0061表示ISO拉丁码的‘a’。

转义字符描述

\ddd1到3位8进制数据所表示的字符(ddd)

\uxxxx1到4位16进制数所表示的字符(xxxx)

\'单引号字符

\\反斜杠字符

\r回车

\n换行

\f走纸换页

\t横向跳格

\b退格

二、字符型变量

字符型变量的类型为char,它在机器中占16位,其范围为0~655

35。字符型变量的定义如:

charc='a';//指定变量c为char型,且赋初值为'a'

与C、C++不同,Java中的字符型数据不能用作整数,因为Java不供无符号整数类型。但是同样可以把它当作整数数据来操作。

例如:

int three=3;

char one='1';

char four=(char)(three+one);//four='4'

上例中,在计算加法时,字符型变量one被转化为整数,进行相?,

最后把结果又转化为字符型。

三、字符串常量

与C、C++相同,Java的字符串常量是用双引号("")括起来的一?字符,如"This is a string.\n"。但不同的是,Java中的字符串常量是作为String类的一个对象来处理?,而不是一个数据。有关类String,我们将在第七章讲述。

§2.6布尔型数据

布尔型数据只有两个值,true和false,且它们不对应于任何整值。在流控制中常用到它。

布尔型变量的定义如:

boolean b=true; //定义b为布尔型变量,且初值为true

§ 2.7举例

例 2.1.下例中用到了前面提到的数据类型,并通过屏幕显示们的值。

public class SimpleTypes{

public static void main( String args[] ){

byte b=0x55;

short s=0x55ff;

int i=1000000;

long l=0xfffL;

char c='c';

float f=0.23F;

double d=0.7E-3;

boolean bool=true;

System.out.println("b = "+b);

System.out.println("s = "+s);

System.out.println("i = "+i);

System.out.println("l = "+l);

System.out.println("c = "+c);

System.out.println("f = "+f);

System.out.println("d = "+d);

System.out.println("bool = "+bool);

}

}

编译并运行该程序,输出结果为:

C:\>java SimpleTypes

b = 85

s = 22015

i = 1000000

l = 4095

c = c

f = 0.23

d = 0.0007

bool = true

§ 2.8 各类数值型数据间的混合运算

一、自动类型转换

整型、实型、字符型数据可以混合运算。运算中,不同类?的数据先转化为同一类型,然后进行运算。转换从低级到高级,如下图:

转换规则为:

①(byte或short)opint→int

②(byte或short或int)oplong→long

③(byte或short或int或long)opfloat→float

④(byte或short或int或long或float)opdouble→double

⑤charopint→int

其中,箭头左边表示参与运算的数据类型,op为运算符(如加减、乘、除等),右边表示转换成的进行运算的数据类型。

例2.2

public class Promotion{

public static void main( String args[ ] ){

byte b=10;

char c='a';

int i=90;

long l=555L;

float f=3.5f;

double d=1.234;

float f1=f*b;

// float * byte -> float

int i1=c+i;

// char + int -> int

long l1=l+i1;

// long + int ->ling

double d1=f1/i1-d;

// float / int ->float, float - double -> double}

}

二、强制类型转换

高级数据要转换成低级数据,需用到强制类型转换,如:

int i;

byte b=(byte)i; //把 int型 变 量 i强 制 转 换 为 byte型

这种使用可能会导致溢出或精度的下降,最好不要使用。

第三章 运算符和表达式

运算符指明对操作数所进行的运算。按操作数的数目来分+-),二元运算符(如+、>)和三元运算符(如?:),它们分别对应于一于一元运算符来说,可以有前缀表达式(如++i)和后缀表达式(如

采用中缀表达式(如a+b)。按照运算符功能来分,基本的运算符?下面几类:

1.算术运算符(+,-,*,/,%,++,--)

2.关系运算符(>,<,>=,<=,==,!=)

3.布尔逻辑运算符(!,&&,||)

4.位运算符(>>,<<,>>>,&,|,^,~)

5.赋值运算符(=,及其扩展赋值运算符如+=)

6.条件运算符(?:)

7.其它(包括分量运算符·,下标运算符[],实例运算符instanceof,内存分配运算符new,强制类型转换运算符(类型),方法调用运算符()等)

本章中我们主要讲述前6类运算符。

§ 3.1算术运算符

算术运算符作用于整型或浮点型数据,完成算术运算。

一、二元算术运算符,如下表所示

运算符用法描述+op1+op2加-op1-op2减*op1*op2乘/op1/op2除%op1%op2取模(求余)

Java对加运算符进行了扩展,使它能够进行字符串的连接,如"abc"+"de",得到串"abcde"。我们将在第七章中讲解。

与C、C++不同,对取模运算符%来说,其操作数可以为浮点数, ? 37.2%10=7.2。

二、一元算术运算符,如下表所示:

运算符用法描述++op正值--op负值++ ++op,op++加1-- --op,op-- 减1

i++与 ++i的区别

i++在使用i之后,使i的值加1,因此执行完i++后,整个表达式的?为i,而i的值变为i+1。

++i在使用i之前,使i的值加1,因此执行完++i后,整个表达式和i的值均为i+1。

对i--与--i同样。

例3.1.下面的例子说明了算术运算符的使用

public class ArithmaticOp{public static void main( String args[] ){int a=5+4; //a=9int b=a*2; //b=18int c=b/4; //c=4int d=b-c; //d=14int e=-d; //e=-14int f=e%4; //f=-2double g=18.4;double h=g%4; //h=2.4int i=3;int j=i++; //i=4,j=3int k=++i; //i=5,k=5System.out.println("a = "+a);System.out.println("b = "+b);System.out.println("c = "+c);System.out.println("d = "+d);System.out.println("e = "+e);System.out.println("f = "+f);System.out.println("g = "+g);System.out.println("h = "+h);System.out.println("i = "+i);System.out.println("j = "+j);System.out.println("k = "+k);}}其结果为:C:\>java ArithmaticOpa = 9b = 18c = 4d = 14e = -14f = -2g = 18.4h = 2.4i = 5j = 3k = 5

§ 3.2关系运算符

关系运算符用来比较两个值,返回布尔类型的值true或false?关系运算符都是二元运算符,如下表所示:

运算符用法返回true的情况>op1>op2op1大于op2>+op1>=op2op1大于或等于op2<op1<op2op1小于op2<=op1<=op2op1小于或等于op2==op1==op2op1与op2相等!=op1!=op2op1与op2不等

Java中,任何数据类型的数据(包括基本类型和组合类型)都?以通过==或!=来比较是否相等(这与C、C++不同)。

关系运算的结果返回true或false,而不是C、C++中的1或0。

关系运算符常与布尔逻辑运算符一起使用,作为流控制语?的判断条件。如

if( a>b && b==c)

§ 3.3布尔逻辑运算符

布尔逻辑运算符进行布尔逻辑运算,如下表所示:

op1 op2 op1&&op2 op1||op2 !op1false false false false truefalse true false true truetrue false false true falsetrue true true true false}@@@·&&、‖ 为二元运算符,实现逻辑与、逻辑或。·! 为一元运算符,实现逻辑非。·对于布尔逻辑运算,先求出运算符左边的表达式的值,对或运算如果为true,则整个表达式的结果为true,不必对运算符右边的表达式再进行运算;同样,对与运算,如果左边表达式的值为false,则不必对右边的表达式求值,整个表达式的结果为false。下面的例子说明了关系运算符和布尔逻辑运算符的使用。@@@[public class RelationAndConditionOp{public static void main( String args[] ){int a=25,b=3;boolean d=a<b; //d=falseSystem.out.println("a<b = "+d);int e=3;if(e!=0 && a/e>5)System.out.println("a/e = "+a/e);int f=0;if(f!=0 && a/f>5)System.out.println("a/f = "+a/f);elseSystem.out.println("f = "+f);}}其运行结果为:C:\>java RelationAndConditionOpa<b = falsea/e = 8f = 0

注意:上例中,第二个if语句在运行时不会发生除0溢出的错,因为e!=0为false,所以就不需要对a/e进行运算。

§3.4位运算符

位运算符用来对二进制位进行操作,Java中提供了如下表所的位运算符:

位运算符中,除~以外,其余均为二元运算符。

操作数只能为整型和字符型数据。

3.4.1 补码

Java使用补码来表示二进制数,在补码表示中,最高位为符号?,正数的符号位为0,负数为1。补码的规定如下:

对正数来说,最高位为0,其余各位代表数值本身(以二进制?示),如+42的补码为00101010。

对负数而言,把该数绝对值的补码按位取反,然后对整个数1,即得该数的补码。如-42的补码为11010110 (00101010 按 位取反 11010101 +1 11010110 )

用补码来表示数,0的补码是唯一的,都为00000000。(而在原码,反码表示中,+0和-0的表示是不唯一的,可参见相应的书籍)。而且可以用111111表示-1的补(这也是补码与原码和反码的区别)。

3.4.2 按位取反运算符 ~

~ 是一元运算法,对数据的每个二进制位取反,即把1变为0,把0变为1。

例如: 0010101

1101010

注意,~运算符与-运算符不同,~21≠-21。

3.4.3 按位与运算符 &

参与运算的两个值,如果两个相应位都为1,则该位的结果为1例如:

0010101

1101010

注意,~运算符与-运算符不同,~21≠-21。

3.4.3 按位与运算符 &

参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0。即:

0& 0 = 0,0 &1 = 0,1 & 0 = 0,1 & 1 = 1

第四章 流控制

与C、C++相同,Java程序通过流控制来执行程序流,完成一定?个语句组成的。语句可以是单一的一条语句(如c=a+b;),也可以复合语句。

下面我们分别来介绍Java中的流控制语句,包括

1.分支语句:if-else,break,switch,return.

2.循环语句:while,do-while,for,continue.

3.例外处理语句:try-catch-finally,throw

最后我们简单介绍一下注释语句。

§4.1分支语句<

分支语句提供了一种控制机制,使得程序的执行可以跳过?些语句不执行,而转去执行特定的语句。

4.1.1 条件语句if-else.

if-else语句根据判定条件的真假来执行两种操作中的一种,?的格式为:

if(boolean-expression)statement1;[elsestatement2;]

1.布尔表达式boolean-expression是任意一个返回布尔型数据的达式(这比C、C++的限制要严格)。

2.每个单一的语句后都必须有分号。

3.语句statement1,statement2可以为复合语句,这时要用大括号{}?起。建议对单一的语句也用大括号括起,这样程序的可读性强,而且有利于程序的扩充(可以在其中填加新的语句)。{}外面不加分号。

4.else子句是任选的。

5.若布尔表达式的值为true,则程序执行statement1,否则执行statement2。

6.if-else语句的一种特殊形式为:

if(expression1){statement1}elseif(expression2){statement2}……}elseif(expressionM){statementM}else{statementN}@@@[else子句不能单独作为语句使用,它必须和if配对使用。else总是与离它最近的if配对。可以通过使用大括号{}来改变配对关系。7.举例:例4.1比较两个数的大小,并按从小到大的次序输出。@@@[public class CompareTwo{public static void main( String args[] ){double d1=23.4;double d2=35.1;if(d2>=d1)System.out.println(d2+" >= "+d1);elseSystem.out.println(d1+" >= "+d2);}}运行结果为:C:\>java CompareTwo

35.1 >= 23.4

例 4.2 判断某一年是否为闰年。

闰年的条件是符合下面二者之一:①能被4整除,但不能被100整除;②能被4整除,又能被100整除。

public class LeapYear{public static void main( String args[] ){int year=1989; //method 1if( (year%4==0 && year%100!=0) || (year%400==0) )System.out.println(year+" is a leap year.");elseSystem.out.println(year+" is not a leap year.");year=2000; //method 2boolean leap;if( year%4!=0 )leap=false;else if( year%100!=0 )leap=true;else if( year%400!=0 )leap=false;elseleap=true;if( leap==true )System.out.println(year+" is a leap year.");elseSystem.out.println(year+" is not a leap year.");year=2050; //method3if( year%4==0){if( year%100==0 ){if( year%400==0)leap=true;elseleap=false;}elseleap=false;}elseleap=false;if( leap==true )System.out.println(year+" is a leap year.");elseSystem.out.println(year+" is not a leap year.");}}运行结果为C:\>java LeapYear1989 is not a leap year.2000 is a leap year.2050 is not a leap year.

该例中,方法1用一个逻辑表达式包含了所有的闰年条件,方?2使用了if-else语句的特殊形式,方法3则通过使用大括号{}对if-else进行匹配来实现闰年的?断。大家可以根据程序来对比这三种方法,体会其中的联系和区别,在不同的场合选用适?的方法。

4.1.2 多分支语句switch

switch语句根据表达式的值来执行多个操作中的一个,它的般格式如下:

switch (expression){case value1 : statement1;break;case value2 : statement2;break;…………case valueN : statemendN;break;[default : defaultStatement; ]}

1.表达式expression可以返回任一简单类型的值(如整型、实?、字符型),多分支语句把表达式返回的值与每个case子句中的值相比。如果匹配成功,则?行该case子句后的语句序列。

2.case子句中的值valueI必须是常量,而且所有case子句中的值是不同的。

3.default子句是任选的。当表达式的值与任一case子句中的?都不匹配时,程序执行default后面的语句。如果表达式的值与任一case子句中的值都不?配且没有default子句,则程序不作任何操作,而是直接跳出switch语句。

4.break语句用来在执行完一个case分支后,使程序跳出switch语?,即终止switch语句的执行。因为case子句只是起到一个标号的作用,用来查找匹配的入口?从此处开始执行,对后面的case子句不再进行匹配,而是直接执行其后的语句序列,因此该在每个case分支后,要用break来终止后面的case分支语句的执行。

在一些特殊情况下,多个不同的case值要执行一组相同的操,这时可以不用break。

5.case分支中包括多个执行语句时,可以不用大括号{}括起。

6.switch语句的功能可以用if-else来实现,但在某些情况下,使switch语句更简炼,可读性强,而且程序的执行效率提高。

7.举例:

例4.3.根据考试成绩的等级打印出百分制分数段。

public class GradeLevel{public static void main( String args[] ){System.out.println("\n** first situation **");char grade='C'; //normal useswitch( grade ){case 'A' : System.out.println(grade+" is 85~100");break;case 'B' : System.out.println(grade+" is 70~84");break;case 'C' : System.out.println(grade+" is 60~69");break;case 'D' : System.out.println(grade+" is <60");break;default : System.out.println("input error");}System.out.println("\n** second situation **");grade='A'; ∥creat error without break statementswitch( grade ){case 'A' : System.out.println(grade+" is 85~100");case 'B' : System.out.println(grade+" is 70~84");case 'C' : System.out.println(grade+" is 60~69");case 'D' : System.out.println(grade+" is <60");default : System.out.println("input error");}System.out.println("\n** third situation **");grade='B'; ∥several case with same operationswitch( grade ){case 'A' :case 'B' :case 'C' : System.out.println(grade+" is >=60");break;case 'D' : System.out.println(grade+" is <60");break;default : System.out.println("input error");}}}运行结果为C:\>java GradeLevel**** first situation ****C is 60~69**** second situation ****A is 85~100A is 70~84A is 60~69A is <60input error**** third situation ****B is >=60

从该例中我们可以看到break语句的作用。

4.1.3 break语句

1.在switch语中,break语句用来终止switch语句的执行。使程序switch语句后的第一个语句开始执行。

2.在Java中,可以为每个代码块加一个括号,一个代码块通常用大括号{}括起来的一段代码。加标号的格式如下:

BlockLabel: { codeBlock }

break语句的第二种使用情况就是跳出它所指定的块,并从紧?该块的第一条语句处执行。其格式为:

break BlockLabel;例如:a:{…… //标记代码块ab: {…… //标记代码块bc: {…… //标记代码块cbreak b;…… //will not be executed}…… //will not be executed}…… //will not be executed}…… /execute from here}

3.与 C、C++不同,Java中没有goto语句来实现任意的跳转,因为goto语句破坏程序的可读性,而且影响编译的优化。但是从上例可以看出,Java用break来实现goto语句所特有的一些优点。如果break后所指定的标号不是一个代码块的标号,而是一个?句,则这时break完全实现goto的功能。不过应该避免这种方式的使用。

4.1.4返回语句 return

return语句从当前方法中退出,返回到调用该方法的语句处,句继续程序的执行。(有关方法的内容,我们将在第六章详细讲)是一个方法)。返回语句有两种格式:

1.return expression

返回一个值给调用该方法的语句,返回值的数据类型必须?方法声明中的返回值类型一致。可以使用强制类型转换来使类型一致。

2.return

当方法说明中用void声明返回类型为空时,应使用这种格式,?不返回任何值。

return语句通常用在一个方法体的最后,以退出该方法并返一个值。Java中,单独的return语句用在一个方法体的中间时,会产生编译错误,因为这时?有一些语句执行不到。但可以通过把return语句嵌入某些语句(如if-else)来使程序在未执?完方法中的所有语句时退出,例如:

int method (int num) {∥ return num; ∥will cause compile time errorif (num>0)return num;…… ∥ may or may not be executed∥depending on the value of num

§ 4.2循环语句

循环语句的作用是反复执行一段代码,直到满足终止循环?条件为止,一个循环一般应包括四部分内容:

1.初始化部分(initialization):用来设置循环的一些初始条件,?计数器清零等。

2.循环体部分(body):这是反复循环的一段代码,可以是单一?一条语句,也可以是复合语句。

3.迭代部分(iteration):这是在当前循环结束,下一次循环开始?执行的语句,常常用来使计数器加1或减1。

4.终止部分(termination):通常是一个布尔表达式,每一次循环要对该表达式求值,以验证是否满足循环终止条件。

Java中提供的循环语句有:while语句,do-while语句和for语句,下分别介绍。

4.2.1 while语句

while语句实现"当型"循环,它的一般格式为;

[initialization]while (termination){body;[iteration;]}

1.当布尔表达式(termination)的值为true时,循环执行大括号中语句。并且初始化部分和迭代部分是任选的。

2.while语句首先计算终止条件,当条件满足时,才去执行循环?中的语句。这是"当型"循环的特点。

4.2.2 do-while语句

do-while 语句实现"直到型"循环,它的一般格式为:[initialization]do {body;[iteration;]} while (termination);

1.do-while语句首先执行循环体,然后计算终止条件,若结果为true,则循环执行大括号中的语句,直到布尔表达式的结果为false。

2.与while语句不同的是,do-while语句的循环体至少执行一次,?是"直到型"循环的特点。

4.2.3 for语句

for语句也用来实现"当型"循环,它的一般格式为:

for (initialization; termination; iteration){

body;

}

1.for语句执行时,首先执行初始化操作,然后判断终止条件?否满足,如果满足,则执行循环体中的语句,最后执行迭代部分。完成一次循环后,重新判断?止条件。

2.可以在for语句的初始化部分声明一个变量,它的作用域为?个for语句。

3.for语句通常用来执行循环次数确定的情况(如对数组元素?行操作),也可以根据循环结束条件执行循环次数不确定的情况。

4.在初始化部分和迭代部分可以使用逗号语句,来进行多个?作。逗号语句是用逗号分隔的语句序列。例如:

for(i=0, j=10; i<j; i++, j--){……}

5.初始化、终止以及迭代部分都可以为空语句(但分号不能?),三者均为空的时候,相当于一个无限循环。

4.2.4 continue语句

1.continue语句用来结束本次循环,跳过循环体中下面尚未执的语句,接着进行终止条件的判断,以决定是否继续循环。对于for语句,在进行终止条件?判断前,还要先执行迭代语句。它的格式为:

continue;

2.也可以用continue跳转到括号指明的外层循环中,这时的格为

continue outerLable;

例如:

outer: for( int i=0; i<10; i++ ){ ∥外层循环for( int j=0; j<20; j++ ){ ∥内层循环if( j>i ){……continue outer;}……}……}

该例中,当满足j>i的条件时,程序执行完相应的语句后跳转?外层循环,执行外层循环的迭代语句i++;然后开始下一次循环。

4.2.5举例

例4.4下例分别用while、do-while和for语句实现累计求和。

public class Sum{public static void main( String args[] ){System.out.println("\n** while statement **");int n=10,sum=0; ∥initializationwhile( n>0 ){ ∥terminationsum+=n; ∥bodyn--; ∥iteration}System.out.println("sum is "+sum);System.out.println("\n** do_while statement **");n=0; ∥initializationsum=0;do{sum+=n; ∥bodyn++; ∥iteration}while( n<=10 ); ∥terminationSystem.out.println("sum is "+sum);System.out.println("\n** for statement **");sum=0;for( int i=1; i<=10; i++){∥initialization,termination,iterationsum+=i;}System.out.println("sum is "+sum);}}运行结果为:C:\>java Sum** while statement **sum is 55** do_while statement **sum is 55** for statement **sum is 55可以从中来比较这三种循环语句,从而在不同的场合选择合适的语句。例4.5 求100~200间的所有素数public class PrimeNumber{public static void main( String args[] ){System.out.println(" ** prime numbers between 100 and 200 **");int n=0;outer:for(int i=101;i<200;i+=2={ ∥outer loopint k=15; ∥select for convinence for(int j=2;j<=k;j++={ ∥inner lop

if( i%j==0 )continue outer;}System.out.print(" "+i);n++; ∥output a new lineif( n<10 = ∥after 10 numberscontinue;System.out.println();n=0;=System.out.println();==运行结果为:C:\>java PrimeNumber** prime numbers between 100 and 200 **101 103 107 109 113 127 131 137 139 149151 157 163 167 173 179 181 191 193 197199

该例通过一个嵌套的for语句来实现。

§ 4.3 例外处理语句

例外处理语句包括try、catch、finally以及throw语句。与C、C++相比,例外处理语句是Java所特有的。我们将在第八章作专门的介绍。

§ 4.4 注释语

Java中可以采用三种注释方式:

1 ∥ 用于单行注释。

注释从∥开始,终止于行尾。

2 /* … */ 用于多行注释。

注释从/*开始,到*/结束,且这种注释不能互相嵌套。

3 /** … */ 是Java所特有的doc注释。

它以/**开始,到*/结束。这种注释主要是为支持JDK工具javadoc而采用的。javadoc能识别注释中用标记@标识的一些特殊变量,并把doc注释加入它所生成的HTML文件。对javadoc的详细讲述可参见附录。

第五章 数组

数组是有序数据的集合,数组中的每个元素具有相同的数?数组名和下标来唯一地确定数组中的元素。数组有一维数组?绍。

§5.1一维数组

一、一维数组的定义

一维数组的一、一维数组的定义

一维数组的定义方式为:

type arrayName[];

其中类型(type)可以为Java中任意的数据类型,包括简单类型组合类型(见2.1),数组名arrayName为一个合法的标识符,[]指明该变量是一个数组类型变?。例如:

int intArray[];

声明了一个整型数组,数组中的每个元素为整型数据。与C?C++不同,Java在数组的定义中并不为数组元素分配内存,因此[]中不用指出数组中元素?个数,即数组长度,而且对于如上定义的一个数组是不能访问它的任何元素的。我们必须?它分配内存空间,这时要用到运算符new,其格式如下:

arrayName = new type[arraySize];

其中,arraySize指明数组的长度。如:

intArray= new int[3];

为一个整型数组分配3个int型整数所占据的内存空间。

通常,这两部分可以合在一起,格式如下:

type arrayName = new type [arraySize];

例如 :

int intArray= new int[3];

二、一维数组元素的引用

定义了一个数组,并用运算符new为它分配了内存空间后,就以引用数组中的每一个元素了。数组元素的引用方式为:

arrayName[index]

其中:index为数组下标,它可以为整型常数或表达式。如a[3],b[i](i为整型),c[6*I]等。下标从0开始,一直到数组的长度减1。对于上面例子中的in-tArray数来说,它有3个元素,分别为:

intArray[0],intArray[1],intArray[2]。注意:没有intArray[3]。

另外,与C、C++中不同,Java对数组元素要进行越界检查以保?安全性。同时,对于每个数组都有一个属性length指明它的长度,例如:intArray.length指明数?intArray的长度。

例5.1public class ArrayTest{public static void main( String args[] ){int i;int a[]=new int[5];for( i=0; i<5; i++ )a[i]=i;for( i=a.length-1; i>=0; i-- )System.out.println("a["+i+"] = "+a[i]);}}运行结果如下:C:\>java ArrayTesta[4] = 4a[3] = 3a[2] = 2a[1] = 1a[0] = 0

该程序对数组中的每个元素赋值,然后按逆序输出。

三、一维数组的初始化

对数组元素可以按照上述的例子进行赋值。也可以在定义?组的同时进行初始化。例如:

inta[]={1,2,3,4,5};

用逗号(,)分隔数组的各个元素,系统自动为数组分配一定?空间。

与C中不同,这时Java不要求数组为静态(static)。

四、一维数组程序举例:

例5.2 Fibonacci数列

Fibonacci数列的定义为:

F1 = F2 = 1, Fn = Fn-1 + Fn-2 (n>=3)

public class Fibonacci{

public static void main( String args[] ){

int i;

int f[]=new int[10];

f[0]=f[1]=1;

for( i=2; i<10; i++ )

f[i]=f[i-1]+f[i-2];

for( i=1; i<=10; i++ )

System.out.println("F["+i+"]= "+f[i-1]);

}

}

运行结果为:

C:\>java Fibonacci

F[1]=1

F[2]=1

F[3]=2

F[4]=3

F[5]=5

F[6]=8

F[7]=13

F[8]=21

F[9]=34

F[10]=55

例5.3冒泡法排序(从小到大)

冒泡法排序对相邻的两个元素进行比较,并把小的元素交?到前面。

public class BubbleSort{

public static void main( String args[] ){

int i,j;

int intArray[]={30,1,-9,70,25};

int l=intArray.length;

for( i=0; i<l-1; i++)

for( j=i+1; j<l; j++ )

if( intArray[i]>intArray[j] ){

int t=intArray[i];

intArray[i]=intArray[j];

intArray[j]=t;

}

for( i=0; i<l; i++ )

System.out.println(intArray[i]+" ");

}

}

运行结果为:

C:\>java BubbleSort

-9

1

25

30

70]@@@

§ 5.2多维数组

与C、C++一样,Java中多维数组被看作数组的数组。例如二维?组为一个特殊的一维数组,其每个元素又是一个一维数组。下面我们主要以二维数为例来进行说明,高维的情况是类似的。

一、二维数组的定义

二维数组的定义方式为:

type arrayName[][];

例如:

int intArray[][];

与一维数组一样,这时对数组元素也没有分配内存空间,同要使用运算符new来分配内存,然后才可以访问每个元素。

对高维数组来说,分配内存空间有下面几种方法:

1直接为每一维分配空间,如:

int a[][] =new int[2][3];

2从最高维开始,分别为每一维分配空间,如:

int a[][] = new int[2][];

a[0] = new int[3];

a[1] = new int[3];

完成1中相同的功能。这一点与C、C++是不同的,在C、C++中?须一次指明每一维的长度。

二、二维数组元素的引用

对二维数组中每个元素,引用方式为:arrayName[index1][index2]

其中index1、index2为下标,可为整型常数或表达式,如a[2][3]等?同样,每一维的下标都从0开始。

三、二维数组的初始化

有两种方式:

1直接对每个元素进行赋值。

2在定义数组的同时进行初始化。

如:inta[][]={{2,3},{1,5},{3,4}};

定义了一个3×2的数组,并对每个元素赋值。

四、二维数组举例:

例5.4矩阵相乘

两个矩阵Am×n、Bn×l相乘得到Cm×l,每个元素Cij=aik*bk (i=1..m,n=1..n)

public class MatrixMultiply{

public static void main( String args[] ){

int i,j,k;

int a[][]=new int[2][3];

int b[][]={ {1,5,2,8},{5,9,10,-3},{2,7,-5,-18} };

int c[][]=new int[2][4];

for( i=0; i<2; i++=

for( j=0; j<3; j++)

a[i][j]=(i+1)*(j+2);

for( i=0; i<2; i++={

for( j=0; j<4; j++){

{ c[i][j]=0;

for( k=0; k<3; k++ =

c[i][j]+=a[i][k]*b[k][j];

}

}

System.out.println("\n*** Matrix A ***");for( i=0; i<2; i++ ){for( j=0; j<3; j++ )System.out.print(a[i][j]+" ");System.out.println();}System.out.println("\n*** Matrix B ***");for( i=0; i<3; i++ ){for( j=0; j<4; j++ )System.out.print(b[i][j]+" ");System.out.println();}System.out.println("\n*** Matrix C ***");for( i=0; i<2; i++ ){for( j=0; j<4; j++ )System.out.print(c[i][j]+" ");System.out.println();}}}其结果为:C:\>java MatrixMultiplyfor( j=0; j<4; j++ )System.out.print(c[i][j]+" ");System.out.println();}}}其结果为:C:\>java MatrixMultiply*** Matrix A ***2 3 44 6 8*** Matrix B ***1 5 2 85 9 10 -32 7 -5 -18*** Matrix C ***25 65 14 -6550 130 28 -130 

第 六 章  对 象、类、包 和 接 口

在前面几章中,我们对Java的简单数据类型、数组、运算符作了详细的介绍。从现在开始,我们要深入到面向对象的编程地方。本章中,我们首先讲述面向对象程序设计的基本概念及点,然后讨论Java中的类、对象、包和接口,最后进行小结,给出一个完整的Java文件的格?

§ 6.1 面向对象的程序设计

面向过程的程序设计方法从解决问题的每一个步骤入手,?适合于解决比较小的简单问题。C语言采用面向过程的程序设计模型,但是由于C本身几?没有支持代码重用的语言结构,并且缺乏统一的接口,使得当程序的规模达到一定程度时,程序员很难控制其复杂性

面向对象的程序设计方法则按照现实世界的特点来管理复杂的事物,把它们抽象为对象,具有自己的状态和行为,通过对消息的反应来完成一定的任?。

6.1.1对象、类和消息

一个对象就是变量和相关的方法的集合,其中变量表明对象的状态,方法表明对象所具有的行为,下图表示了一个对象的特征:

从图中可以看出,一个对象的变量构成这个对象的核心,包在它外面的方法使这个对象和其它对象分离开来。例如:我们可以把汽车抽象为一个象,用变量来表示它当前的状态,如速度、油量、型号、所处的位置等,它的行为则可以有?速、刹车、换挡等。我们操纵汽车时,不用去考虑汽车内部各个零件如何运作的细节,?只需根据汽车可能的行为使用相应的方法即可。实际上,面向对象的程序设计实现了对象的封装,使我们不必关心对象的行为是如何实现的这样一些细节。通过对对象的?装,实现了模块化和信息隐藏,有利于程序的可移植性和安全性,同时也利于对复杂对象的?理。

对象之间必须要进行交互来实现复杂的行为。例如,要使?车加速,必须发给它一个消息,告诉它进行何种动作(这里是加速)以及实现这种动作所?的参数(这里是需要达到的速度等)。下图表示了对象A与对象B间的消息传递过程。

从图中可以看出,一个消息包含三个方面的内容:

●  消息的接收者

●  接收对象应采用的方法

●  方法所需要的参数。

同时,接收消息的对象在执行相应的方法后,可能会给发送息的对象返回一些信息(如上例中,汽车的仪表上会出现已经达到的速度等)。

由于任何一个对象的所有行为都可以用方法来描述,通过?息机制就可以完全实现对象之间的交互,同时,处于不同处理过程甚至不同主机的对象间?可以通过消息实现交互。

上面所说的对象是一个具体的事物,例如每辆汽车都是一?不同的对象。但是多个对象常常具有一些共性,如所有的汽车都有轮子、方向盘、常具一些共性,如所有的汽车都有轮子、方向盘、刹车装置等。于是我们抽象出一类对象?共性,这就是类。类中定义一类对象共有的变量和方法。把一个类实例化即生成该类的?个对象。比如我们可以定义一个汽车类来描述所有汽车的共性。通过类的定义人们可?实现代码的复用。我们不用去描述每一个对象(如某辆汽车),而是通过创建类(如汽车类)?一个实例来创建该类的一个对象,这大大减化了软件的设计。

6.1.2 继承

通过对象、类,我们实现了封装,通过子类我们可以实现继。

对于上例来说,公共汽车、出租车、货车等都是汽车,但它是不同的汽车,除了具有汽车的共性外,它们还具有自己的特点(如不同的操作方法,不?的用途等)。这时我们可以把它们作为汽车的子类来实现,它们继承父类(汽车)的所有状?和行为,同时增加自己的状态和行为。通过父类和子类,我们实现了类的的层次,可以从最?般的类开始,逐步特殊化,定义一系列的子类。同时,通过继承也实现了代码的复用,使序的复杂性线性地增长,而不是呈几何级数增长。

在C++中支持多重继承,即一个类可以继承多个父类,这使得象的实现变得非常复杂且不可预料(设想多个父类拥有某些相同的变量和方法)。Java?只支持单一继承,大大降低了复杂度。在Java中通过接口可以实现多重继承,但接口的概念?简单,使用更方便,而且不仅仅限于继承,它使多个不相关的类可以具有相同的方法。

6.1.3 多态

Java通过方法重写和方法重载来实现多态。

通过方法重写,一个类中可以有多个具有相同名字的方法,?传递给它们的不同个数和类型的参数来决定使用哪种方法,这就是多态。例如,对于一和行为,同时增加自己的状?作图的类,它有一个draw()方法用来画图或输出文字,我们可以传递给它一个字符串一个矩形、一个圆形,甚至还可以再指定作图的初始位置、图形的颜色等,对于每一种现,只需实现一个新的draw()方法即可,而不需要新起一个名字,这样大大简化了方法?实现和调用,程序员和用户都不需要记住很多的方法名,只需要传入相应的参数即可。

通过方法重载,子类可以重新实现父类的某些方法,使其具自己的特征。例如对于汽车类的加速方法,其子类(如赛车)中可能增加了一些新的部?来改善提高加速性能,这时可以在赛车类中重载父类的加速方法。重载隐藏了父类的方?,使子类拥有自己具体实现,更进一步表明了与父类相比,子类所具有的特殊性。

本节中,我们对面向对象程序设计的一些基本内容作了讲?,下面我们就分别讲述Java是如何实现这些内容的。

§ 6.2

类是组成Java程序的基本要素。它封装了一类对象的状态?方法,是这一类对象的原型。在前几章的例子中,我们已经定义了一些简单的类,如Helloo rldApp类。

public class HelloWorldApp{

public static void main( String args[ ]){

System.out.println("Hello World !");

}

}

可以看出,一个类的实现包含两部分的内容:classDeclaration {classBody}

下面我们分别对每一部分详细讲述。

6.2.1 类声明

一个最简单的类声明如下:

class className {……}例如:class Point{……}

同时,在类声明中还可以包含类的父类,类所实现的接口以修饰符public、abstract或final。我们将分别在后面的几节中介绍。

6.2.2 类体

类体中定义了该类所有的变量和该类所支持的方法。通常?量在方法前定义(并不一定要求),如下所示:

class className {memberVariableDeclarationsmethodDeclarations}

下例定义了一个Point类,并且声明了它的两个变量x、y坐标,?时实现init()方法对x、y赋初值。

例 6.1

class Ponit {int x,y;void init(int ix, int iy){x=ix;y=iy;}}

类中所定义的变量和方法都是类的成员。对类的成员可以?定访问权限,来限定其它对象对它的访问,访问权限所以有以下几种:private,protected,public,friendly。我们将在§6.6中详细讨论。

同时,对类的成员来说,又可以分为实例成员和类成员两种我们在§6.8中详细讨论。

6.2.3 成员变量

最简单的成员变量的声明为:

type variableName;

如在例6.1中所声明的变量,int x,y;

成员变量的类型可以是Java中的任意数据类型包括简单类?、数组、类和接口。在一个类中,成员变量应该是唯一的,但是成员变量的名字可以和类?某个方法的名字相同,例如:

class Point{int x,y;int x(){return x;}}

其中,方法x()和变量x具有相同的名字。

类的成员变量和在方法中所声明的局部变量是不同的,成?变量的作用域是整个类,而局部变量的作用域只是方法内部。

对一个成员变量,我们还可以限定它的访问权限(见§6.6),?static限定它为类变量(见§6.7),或者用以下的修饰符限定:

final:用来声明一个常量,如:

class FinalVar{final int CONSTANT = 50;……}

例中声明了常量CONSTANT,并赋值为50。对于用final限定的常,在程序中不能改变它的值。通常常量名用大写字母。

6.2.6 构造方法

构造方法是一种特殊的方法。Java中的每个类都有构造方法,用来初始化该类的一个新的对象。构造方法具有和类名相同的名称,而且不返回任何据类型,在构造方法的实现中,也可以进行方法重写。

  例6.5  class point {

int x,y;

point (){

    x=0;

y=0;

}   

point (int x, int y){

    this.x=x;

    this.y=y;

            }   

}

上例中,我们对类Point实现了两个构造方法,方法名均为Point,与类名相同。而且我们使用了方法重写,根据不同的参数分别对点的x、y坐标赋与不同的?回忆在例6.2中,我们曾用init()方法对点的x、y坐标进行初始?。二者完成相同的功能,那么用构造方法的好处在哪里呢?

当用运算符new为一个对象分配内存时,要调用对象的构造方法,而当创建一个对象时,必须用new为它分配内存。因此用构造方法进行初始化避免了在生成对象后每次都要调用对象的初始化方法。如果没有实现类的构造方法,则Java运行

另外,构造方法只能由new运算符调用。我们将在§6.3中进行详细介绍。对构造方法同

6.2.7 finalize()方法

在对对象进行垃圾收集前,Java运行时系统回自动调用对象的finalize()方法来释放系统资

 protected void finalize() throws throwable

 finalize()方法在类java.lang.Object中实现。如果要在一个所定义的类中实现该方法以释放该类所占用的资源(即要重载父类的finalize()方法),则在对该类所使用的资源进行翻译后,一般要调用父类的finalize()方法以清除对象使用的所有资源,包括?于继承关系而获得的资源

 ……      // clean up code for this class

 super. finalize();    }

将在§6.4中讲述,对类java.lang.Ob-ject,我们也将在§6.4中讲述。

来进行交互(消息传递即激活指定的某个对象的方法以改变其状态或让它产生一定的行为),最终完成复杂的任务

我们分别讲述:

对象的生成包括声明、实例化和初始化三方面的内容。通?的格式为:

1. type objectName; 声明了一个类型为type的对象。其中type是组合类型(包括类和接口)。对象的声明并不为对象分配内存空间。

对象的构造方法,返回对该对象的一个引用(即该对象所在的内存地址)。用new可以为一?类实例化多个不同的对象。这些对象分别占用不同的内存空间,因此改变其中一个对象的状态不会影响其它对象

3.生成对象的最后一步是执行构造方法,进行初始化。由于对构造方法可以进行重写,所以通过给出不同个数或类型的参数会分别调用不同的构造方 ?以例6.5中所定义的类Point为例,我们生成类Point的对象:

  Point p1 = new Point();

  Point p2 = new Point(5,10);

 这里,我们为类Point生成了两个对象p1、p2,它们分别调用不同的构造方法,p1调用缺省的构造方法(即没有参数),p2则调用带参数的构造方法。p1、p2分

虽然new运算符返回对一个对象的引用,但与C、C++中的指针不同,对象的引用是指向一个中间的数据结构,它存储有关数据类型的信息以及当前对象所在的堆的地址,而对于对象所在的实际的内存地址是不可操作的,这就保证了安全性

6.3.2 对象的使用

对象的使用包括引用对象的成员变量和方法,通过运算符·可以实现对变量的访问和方法的调用,变量和方法可以通过设定一定的访问权限(见§6.6)

我们先定义一个类Point,它在例6.5的定义中添加了一些内容?

例6.6  

class Point{

int x,y;

String name = "a point";

Point(){

x = 0;

y = 0;

}

Point( int x, int y, String name ){

this.x = x;

this.y = y;

this.name = name;

}

int getX(){

return x;

}

int getY(){

return y;

}

void move( int newX, int newY ){

x = newX;

y = newY;

}

Point newPoint( String name ){

Point newP = new Point( -x, -y, name );

return newP;

}

boolean equal( int x, int y ){

if( this.x==x && this.y==y )

return true;

else

return false;

}

void print(){

System.out.println(name+" :  x = "+x+"  y = "+y);

}

}

public class UsingObject{

public static void main( String args[] ){

Point p = new Point();

p.print();         //call method of an object

p.move( 50, 50 );

System.out.println("** after moving **");

System.out.println("Get x and y directly");

System.out.println("x = "+p.x+"  y = "+p.y);    //access variables of an object

System.out.println("or Get x and y by calling method");

System.out.println("x = "+p.getY()+"  y = "+p.getY());

if( p.equal(50,50) )

System.out.println("I like this point!!!! ");

else

System.out.println("I hate it!!!!! ");

p.newPoint( "a new point" ).print();

new Point( 10, 15, "another new point" ).print();

}

}

运行结果为:    C:\java UsingObject   

 a point :  x = 0  y = 0   

 **** after moving *****    Get x and y directly    x = 50  y = 50   

or Get x and y by calling method    x = 50  y = 50   

I like this point!!!!    a new point :  x = -50  y = -50   

 another new point :  x = 10  y = 15

1.引用对象的变量

要访问对象的某个变量,其格式为:

objectReference.variable

其中objectReference是对象的一个引用,它可以是一个已生成的对象,也可以是能够生成对

例如:我们用Point p=new Point();生成了类Point的对象p后,可以用p.x,p.y来访问该点的x、y坐

p.x=10;      p.y=20;

或者用new生成对象的引用,然后直接访问,如:

tx=new point().x;

2.调用对象的方法要调用对象的某个方法,其格式为:

,但是通过方法调用的方式来实现能更好地体现面向对象的特点,建议在可能的情况下尽

?

型的值,我们可以合法地使用这个值,如:例6.6中类Point的方法equal返回布尔值,我们可以用它来作为判断条件分别执行

if (p.equal (20,30)){          ……  //statements when equal    }else {          ……  //statements when unequal    }

另外,类Point的方法newPoint返回该点关于原点的对称点,返回?也是一个Point类型,我们可以访问它的变量或调用它的方法,如:

px=p.newPoint().x          或    px = p.newPoint(). getX();

(未完待续)