Java程序设计基础

3.1 Java编程概况

如今你能够复习一下Java语言的背景材料,它的基本结构象C/C++。但不论什么用面向过程语言编写过程序的人都能够了解Java语言的大部分结构.

3.1.1程序结构

Java语言的源程序代码由一个或多个编译单元(compilation unit)组成,每一个编译单元仅仅能包括下列内容(空格和凝视除外):*一个程序包语句(package statement )*入口语句(import statements) *类的声明(class declarations)*界面声明(interface declarations) 每一个Java的编译单元可包括多个类或界面,可是每一个编译单元最多仅仅能有一个类或者界面是公共的。

Java的源程序代码被编译?reg;后,便产生了Java字节代码。Java的字节代码由一?copy;不依赖于机器的指令组成,这?copy;指令能被Java的执行系统(runtimesystem)有效地解释。Java的执行系统工作起来如同一台虚拟机。

在当前的Java实现中。每一个编译单元就是一个以.java为后缀的文件。每一个编译单元有若干个类,编译后。每一个类生成一个.class文件。

.class文件是Java虚拟机可以识别的代码。

3.1.2 凝视

三种类型例如以下://凝视一行/*一行或多行凝视*//**文档凝视**/文档凝视一般放在一个变量或函数定义?reg;前,指示在不论什么自己主动生成文档系统中调入。

这?copy;凝视都是声明条目的描写叙述.。

3.1.3 标识符

变量,函数。类和对象的名称都是标识符,程序猿须要标识和使用的东西都须要标识符。在Java语言里,标识符以字符或_,$开头,后面能够包括数字。标识符是大写和小写有差别的,没有长度限制。

有效的标识符 myname ict_network Hello _sys_path $bill

样例:int a_number; char _onechar; float $bill;

关键词 abstract continue for new switch boolean default goto null synchronized break do if package this byte double implements private threadsafe byvalue else import protected throw case extends instanceof public transient catch false int return true char final interface shorttry class finally long static void const float native super while 其他保留词下面单词被保留使用:cast future generic inner operator outer rest var

3.1.4 数据类型

Java使用五种基本类型:integer(整数),floating(浮点数),point(指针),Boolean(布尔变量),Character or String(字符或字符串)。

integer整数下边给出的数据表示都是整数的样例:4,15,089,0xAD00整数长度数据类型表示 8 bits byte 16 bits short 32 bits int 64 bits long

floating 浮点数下边给出的数据表示都是浮点数的样例:6.37。3.7E15,3e8

浮点数长度数据类型表示 32 bits float 64 bits double

Boolean 布尔变量下边是布尔变量的两种可能取值:true false Character 字符下边给出的都是字符的样例: a \\t (tab) \\u?

???(unicode)

String字符串下边给出的都是字符串的样例:\"This is a string literal\" \"中国科学院计算所\"数组你能够定义随意类型的数组. char s[]; 这是字符型数组。 int [] array; 这是整型数组;你还能够定义数组的数组. int block[][]=new int [2][3]; 数组边界在执行时被检測,避免堆栈溢出和内存崩溃.

在Java里,数组实际上是一个对象,数组有一个成员变量:length。你能够用这个成员函数来查看随意数组的长度.

int a[][] = new int [10][3]。

a.length;      /* 10 */

a[0].length;   /* 3 */

创建数组在Java里创建数组,你可使用两种基本方法:

一。创建一个空数组:

int list[]=new int[50]; 或你能够用初始数值填充数组.

String names[] = { \"Chenji\",\"Yuan\",\"Chun\",\"Yang\" };

相 当 于 下 面 功 能:

String names[];
names = new String[4];
names[0]=new String(\"Chenji\");
names[1]=new String(\"Yuan\");
names[2]=new String(\"Chun\");
names[3]=new String(\"Yang\");

在编译时你不能象下例那样创建静态数组。

int name[50];
//将产生一个编译错误你也不能用new操作去填充一个没定义大小的数组。
int name[];
for (int i=0;i<9;i++)
{ name[i] = i; }

3.1.5 表达式

Java语言的表达式和C语言很类似。运算符运算符(operator)优先级从高究竟排列例如以下:. [ ] () ++ -- ! ~ instanceof * / % + - <> >>>  <= >\\ == ! = & ^ && || ? :

= op = , 整数运算符在整数运算时,假设操作数是long类型,则运算结果是long类型。否则为int类型,绝不会是byte。short或char型。这样。假设变量i被声明为short或byte,i+1的结果会是int。假设结果超过该类型的取值范围。则按该类型的最大值取模。单目整数运算符是:运算符操作-单目非~位补码++加1--减1++运算符用于表示直接加1操作。增量操作也能够用加运算符和赋值操作间接完毕。

++lvalue(左值?copy;表示lvalue+=1,++lvalue也表示lvalue =lvalue +1 (仅仅要lvalue没有副作用)。

--运算符用于表示减1操作。

++和--运算符既能够作为前缀运算符,也能够做为后缀运算符。

双目整数运算符是:运算符操作**+加-减*乘/除%取模&位与|位或^位异或<>右移(带符号)>>>添零右移整数除法按零舍入。

除法和取模遵守下面等式:(a/b)*b+(a%b)==a整数算术运算的异常是因为除零或按零取模造成的。

它将引发一个算术异常。下溢产生零,上溢导致越界。

比如:加1超过整数最大值。取模后。变成最小值。一个op=赋值运算符。和上表中的各双目整数运算符联用。构成一个表达式。整数关系运算符,<=。>=,==和!=产生boolean类型的数据。

布尔运算符布尔(boolean)变量或表达式的组合运算能够产生新的boolean值。

单目运算符!是布尔非。双目运算符&,|和^是逻辑AND,OR和XOR运算符,它们强制两个操作数求布尔值。为避免右側操作数冗余求值,用户能够使用短路求值运算符&&和||。

用户能够使用==和!=,赋值运算符也能够用&=、|=、^=。三元条件操作符?:和C语言中的一样。

浮点运算符浮点运算符能够使用常规运算符的组合:如单目运算符++、--,双目运算符+、-、*和/,以及赋值运算符+=,-=。*=,和/=。此外,还有取模运算:%和%=也能够作用于浮点数,比如:a%b和a-((int)(a/b)*b)的语义同样。这表示a%b的结果是除完后剩下的浮点数部分。

仅仅有单精度操作数的浮点表达式依照单精度运算求值,产生单精度结果。

假设浮点表达式中含有一个或一个以上的双精度操作数,则按双精度运算,结果是双精度浮点数。

数组运算符数组运算符形式例如以下:[]可给出数组中某个元素的值。合法的取值范围是从0到数组的长度减1。取值范围的检查仅仅在执行时刻实。

运算符以String对象实现。运算符\"+\"完毕并操作,假设必要则自己主动把操作数转换为String型。

假设操作数是一个对象,它可定义一个方法toString()返回该对象的String方式,比如 float a = 1.0  print (\"The value of a is\"+ a +\"\\n\"); +运算符用到?reg;上的样例 String s=\"a=\"+ a; +=运算符也能够用于String。

注意。左边(下例中的s1)仅求值一次。

s1+=a;//s1=s1+a//若a非String型,自己主动转换为String型。

对象运算符双目运算符instanceof測试某个对象是否是指定类或其子类的实例。比如:if(myObject instanceof MyClass) { MyClass anothermyObject=( MyClass) myObject; … } 是判定myObject是否是MyClass的实例或是其子类的实例。强制和转换Java语言和解释器限制使用强制和转换。以防止出错导致系统崩溃。

整数和浮点数之间能够来回

强制转换,但整数不能强制转换成数组或对象。对象不能被强制为基本类型。

3.1.6 Java流控制

以下几个控制结构是从C语言借鉴的。

分支结构

if/else分支结构 if (Boolean) { statemanets; } else { statements; }

switch分支结构 switch(expr1) { case expr2: statements; break; case expr3: statements; break; default: statements; break; }

循环结构for循环结构 for (init expr1;test expr2;increment expr3) { statements; }

While循环结构While(Boolean) { statements; }

Do循环结构 do { statements; } while (Boolean);

一般顺序控制break [label] continue [label] reutrn expr; label:statement;

for循环样例以下是一个程序样例。画几条线,分别用红,绿,蓝颜色。这段程序可能是Java函数的一部分: int count; for (count=1;count<=12;count++) { switch (count % 3) } case 0: setColor(Color.red); break; case 1: setColor(Color.blue); break; case 2: setColor(Color.green); break; } g.drawLine(10,count*10,80,count*10); }

3.2 Java变量和函数的实例

Java的类包括变量和函数。

数据变量能够是一些原始的类型,如int,char等。

成员函数是一些可运行的过程。比如,以下程序里:public class ClassOne { int i; public ClassOne() { i=10; } public void Add_i(int j) { i=i+j; } } ClassOne包括一个变量i和两个成员函数,ClassOne(int first)和Add_i(int j)。

成 员 函 数 成 员 函 数 是 一 些 可 被 其 它 类 或 自 己 类 调 用 的 处 理 子 程 序。 一 个 特 殊 的 成 员 函 数 叫 构 造 函 数, 这 个 函 数 名 称 一 般 与 本 类 名 程 相 同。

它 没 有 返 回 值。 构 造 函 数 和 成 员 函 数 当 你 在Java里 定 义 一 个 类 时,你 可 定 义 一 个 或 多 个 可 选 的 构 造 函 数,当 创 建 本 类 的 一 个 对 象 时 用 某 一 个 构 造 函 数 来 初 始 化 本 对 象。 用 前 面 的 程 序 例 子 来 说 明,当ClassOne类 创 建 一 个 新 实 例 时, 所 有 成 员 函 数 和 变 量 被 创 建(创 建 实 例)。 构 造 函 数 被 调 用。

ClassOne mc: mc = new ClassOne();

关 键 词new用 来 创 建 一 个 类 的 实 例,一 个 类 用new初 始 化 前 并 不 占 用 内 存,它 仅仅 是 一 个 类 型 定 义, 当mc对 象 初 始 化 后,mc对 象 里 的i变 量 等 于10。 你 可 以 通 过 对 象 名 来 引 用 变 量i。

(有 时 称 为 实 例 变 量) mc.i++;//mc实 例 变 量 加1 因 为mc有ClassOne类 的 所 有 变 量 和 成 员 函 数, 我 们 可 以 使 用 同 样 的 语 法 来 调 用 成 员 函 数 Add_i: Add_i(10); 现 在mc.i变 量 等 于21.

结 束 函 数 Java并 不 支 持 析 构 函 数(C++里 的 定 义),因 为java本 身 提供 对 象 无 用 时 自 动 清 除 的 功 能,同 时 它 也 提 供了 一 个 自 动 拉 圾 箱 的 成 员 函 数, 在 清 除 对 象 时 被 调 用: Protected void finalize() { close(); }

3.3 对 象 有 效 范 围 和 废 物 自 动 回 收

对 象 有 一 定 的 生 命 期 并 在 它 的 生 命 期 间 使 用 资 源,当 一 个 对 象 不 再 被 使 用 时,它 应 释 放 内 存, 避 免 内 存 溢 出。

在Java里,收 集 和 释 放 内 存 是 一 个 叫 自 动 废 品 回 收 站 的 线 程 的 责 任。 这 个 线 程 监 视 对 象 有 效 范 围 并 给 一 个 走 出 有 效 范 围 的 对 象 作 上 标 识。

例 如: String s;//没 有 分 配 内 存 s = new String(\"oldstring\");//分 配 内 存 s =\"newstring\";//重 新 分 配 内 存(创 建 新 对 象) 我 们 将 在 以 后 訪 问String类 时 将 更 加 明 白 它 的 工 作 过 程,但 它 的 快 速 工 作 过 程 是 这 样 的: 1.创 建 一 个 新 的String类 对 象 并 填 充 以\"oldstring\" 2.创 建 另 一 个String对 象 并 填 充 以\"newstring\" 注 意 我 们 创 建 了 两 个 对 象。

Stirng 对 象 \"oldstring\" Stirng 对 象 \"newstring\" 在 第 三 条 语 句 里,第 一 个 包 括\"oldstring\"的 叫 做s的 对 象 已 走 出 了 有 效 范 围,没 有 任 何 方 法 可 以 再 訪 问 他,我 们 现 在 有 一 个 新 的 对 象 也 叫s,包 含\"newstring\"。 在 下 一 个 废 品 回 收 线 程,前 一 个 对 象 将 被 标 识 并 清 除。

3.4 子 类

子 类 是 利 用 存 在 的 对 象 创 建 一 个 新 对 象 的 机 制,比 如,如 果 你 有 一 个Horse类,你 可 以 创 建 一 个 Zebra子 类,Zebra是Horse的 一 种。

class Zebra extends Horse { int number_OF_stripes: } 关 键 词extends来 定 义 对 象 有 的 子 类.Zebra是Horse的 子 类。Horse类 里 的 所 有 特 征 都 将 拷 贝 到 Zebra类 里,而Zebra类 里 可 以 定 义 自 己 的 成 员 函 数 和 实 例 变 量。Zebra称 为Horse的 派 生 类 或 继 承。 另 外,你 也 许 还 想 覆 盖 基 类 的 成 员 函 数。 用ClassOne说 明,下 面 是 一 个 派 生 类 覆 盖Add_i功 能 的 例 子.

import ClassOne; public class NewClass extends ClassOne { public void

Add_i(int j) { i=i+(j/2); } }

当NewClass类 的 实 例 创 建 时,变 量i初 始 化 值 为10,但 调 用Add_i产 生 不 同 的 结 果。 NewClass mnc; mnc=new NewClass(); mnc.Add_i(10); 訪 问 控 制 Java里 当 你 创 建 一 个 新 类 时,你 可 以 标 明 变 量 和 成 员 函 数 的 訪 问 层 次。

public public void AnyOneCanAccess(){} public实 例 变 量 和 成 员 函 数 可 以 任 意 其 它 类 调 用。

protected protected void OnlySubClasses(){} protected实 例 变 量 和 成 员 函 数 仅仅 能 被 其 子 类 调 用.

private private String CreditCardNumber; private实 例 变 量 和 成 员 函 数 仅仅 能 在 本 类 里 调 用.

friendly void MyPackageMethod(){} 缺 省 的,如 果 没 有 定 义 任 何 防 火 控 制,实 例 变 量 或 函 数 缺 省 定 义 成friendly,意 味 着 可 以 被 本 包 里 的 任 意 对 象 防 问,但 其 它 包 里 的 对 象 不 可 防 问。 静 态 成 员 函 数 和 变 量 有 ?

copy; 时 候,你 创 建 一 个 类,希 望 这 个 类 的 所 有 实 例 都 公 用 一 个 变 量。 也 就 是 说,所 有 这 个 类 的 对 象 都 仅仅 有 实 例 变 量 的 同 一 个 拷 贝。 这 种 方 法 的 关 键 词 是static, 例 如: class Block {  static int number=50; }

所 有 从Block类 创 建 的 对 象 的number变 量 值 都 是 相 同 的。 无 任 在 哪 个 对 象 里 改 变 了number的 值, 所 有 对 象 的number都 跟 着 改 变。 同 样 的,你 可 以 定 义static成 员 函 数,但 这 个 成 员 函 数 不 能 訪 问 非static函 数 和 变 量。 class Block { static int number = 50; int localvalue; static void add_local(){ localvalue++;//没 有 运 行 } static void add_static() { number++;//运 行 } }

3.5 this和super

訪 问 一 个 类 的 实 例 变 量 时,this关 键 词 是 指 向 这 个 类 本 身 的 指 针,在 前 面ClassOne例 子 中,我 们 可 以 增 加 构 造 函 数 如 下:

public class ClassOne { int i; public ClassOne() { i = 10; }

public ClassOne (int value) this.i = value; }

public void Add_i(int j) { i = i + j; } }

这 里,this指 向ClassOne类 的 指 针。

如 果 在 一 个 子 类 里 覆 盖 了 父 类 的 某 个 成 员 函 数,但 又 想 调 用 父 类 的 成 员 函 数,你 可 以 用super 关 键 词 指 向 父 类 的 成 员 函 数。

import ClassOne; public class NewClass extends ClassOne { public void Add_i (int j) { i = i+(j/2); super.Add_i (j); } }

下 面 程 序 里,i变 量 被 构 造 函 数 设 成10,然 后15, 最 后 被 父 类(ClassOne)设 成25。 NewClass mnc; mnc = new NewClass(); mnc.Add_i(10);

3.6 类 的 类 型

至 今 为 止,我 用 在 类 前 面 仅仅 用 了 一 个public关 键 词,其 实 它 有 下 面4种 选 择:abstract 一 个abstract类 必 须 至 少 有 一 个 虚 拟 函 数,一 个abstract类 不 能 直 接 创 建 对 象,必 须 继 承 子 类 后 才 能。

final 一 个final类 声 明 了 子 类 链 的 结 尾,用final声 明 的 类 不 能 再 派 生 子 类。 public public类 能 被 其 它 的 类 訪 问。

在 其 它 包 里,如 果 想 使用 这 个 类 必 须 先import, 则 它 仅仅 能 在 它 定 义 的package里 使 用。 synchronicable 这 个 类 标 识 表 示 所 有 ?copy; 类 的 成 员 函 数 都 是 同 步 的。

3.7 抽 象 类

面 向 对 象 的 一 个 最 大 优 点 就 是 能 够 定 义 怎 样 使 用 这 个 类 而 不 必 真 正 定 义 好 成 员 函 数。 如 果 程 序 由 不 同 的 用 户 实 现 时 是 非常 有 用 的, 这 不 需 用 户 使 用 相 同 的 成 员 函 数 名。

在java里Graphics类 里 一 个abstract类 的 例 子 如 下: public abstract class Graphics { public abstract void drawLine(int x1,int y1,int x2, int y2); public abstract void drawOval(int x,int y,int width, int height); public abstract void drawRect(int x,int y,int width,int height); ... }

在Graphics类 里 声 明 了 几 个 成 员 函 数,但 成 员 函 数 的 实 际 代 码 是 在 另 外 一 ?copy; 地 方 实 现 的。

public class MyClass extends Graphics { public void drawLine (int x1,int y1,int x2,int y2) {  } }

当 一 个 类 包 含 一 个abstract成 员 函 数,这 个 类 必 须 定 义 为abstract类。

然 而 并 不 是abstract类 的 所 有 的 成 员 函 数 都 是abstract的。Abstract类 不 能 有 私 有 成 员 函 数(它 们 不 能 被 实 现),也 不 能 有 静 态 成 员 函 数。

3.8 接 口

当 你 确 定 多 个 类 的 操 作 方 式 都 非常 相 象 时。abstract成 员 函 数 是 非常 有 用 的。

但 如 果 你 需 要 使 用 这 ?copy;abstract成 员 函 数。 必 须 创 建 一 个 新 类, 这 样 有 时 非常 繁 琐。 接 口 提 ?

copy; 了 一 种 抽 象 成 员 函 数 的 有 利 方 法。 一 个 接 口 包 含 了 在 另 一 个 地 方 实 现 的 成 员 函 数 的 收 集。

成 员 函 数 在 接 口 里 定 义 为public和 abstract。 接 口 里 的 实 例 变 量 是public,static和final。

接 口 和 抽 象 的 主 要 区 别 是 一 个 接 口 提 ?copy; 了 封 装 成 员 函 数 协 议 的 方 法 而 不 必 强 迫 用 户 继 承 类。 例 子: public interface AudiClip { //Start playing the clip. void play(); //Play the clip in a loop. void loop(); //Stop playingthe clip void stop(); }

想 使 用Audio Clip接 口 的 类 使 用implenents关 键 词 来 提 ?copy; 成 员 函 数 的 程 序 代 码。

class MyClass implements AudioClip { void play(){  } void loop  } void stop  } }

优 点 一 个 接 口 类 可 以 被 任 意 多 的 类 实 现, 每 个 类 可 以 共 享 程 序 接 口 而 不 必 关 心 其 它 类 是 怎 样 实 现 的。 class MyOtherClass implements AudioClip { void stop(){  } ... } 内 部 成 员 函 数 Java还 提 ?copy; 了 调 用C和C++函 数 的 方 法。

用native关 键 词 来 定 义C和C++的 函 数。 public class Date { int now; public Date() { now = time (); } private native int time (); static { System.loadLibrary(\"time\"); } } 一 ?

copy;Java代 码 写 好 后,就 需 要 以 下 步 骤 执 行: 1.用javah来 创 建 头 文 件(.h) 2.用javah来 创 建stub文 件 3.用C和C++写native成 员 函 数 的 代 码 4.编 译stub文 件 和.C文 件 成 一 个 动 态 可 加 载 库 5.用java运 行java程 序 或appletviewer运 行applet 注 意:Native成 员 函 数 超 出 了 类 的 范 围。

3.9 包(Packages)

包(Package)由 一 组 类(class)和 界 面(interface)组 成。 它 是 管 理 大 型 名 字 空 间, 避 免 名 字 冲 突 的 工 具。 每 一 个 类 和 界 面 的 名 字 都 包 含 在 某 个 包 中。 按 照 一 般 的 习 惯, 它 的 名 字 是 由\".\" 号 分 隔 的 单 词 构 成, 第 一 个 单 词 通 常 是 开 发 这 个 包 的 组 织 的 名 称。

定 义 一 个 编 译 单 元 的 包 编 译 单 元 的 包 由package语 句 定 义。 如 果 使 用package语 句, 编 译 单 元 的 第 一 行 必 须 无 空 格。 也 无 注 释。 其 格 式 如 下: package packageName; 若 编 译 单 元 无package语 句。 则 该 单 元 被 置 于 一 个 缺 省 的 无 名 的 包 中。

使 用 其 它 包 中 的 类 和 界 面 在Java语 言 里 提 ?copy; 一 个 包 可 以 使 用 另 一 个 包 中 类 和 界 面 的 定 义 和 实 现 的 机 制。

用import关 键 词 来 标 明 来 自 其 它 包 中 的 类。 一 个 编 译 单 元 可 以 自 动 把 指 定 的 类 和 界 面 输 入 到 它 自 己 的 包 中。 在 一 个 包 中 的 代 码 可 以 有 两 种 方 式 来 定 义 来 自 其 它 包 中 的 类 和 界 面: * 在 每 个 引 用 的 类 和 界 面 前 面 给 出 它 们 所 在 的 包 的 名 字; //前 缀 包 名 法 acme. project.FooBar obj=new acme. project. FooBar( ); * 使 用import语 句, 引 入 一 个 类 或 一 个 界 面。 或 包 含 它 们 的 包。 引 入 的 类 和 界 面 的 名 字 在 当 前 的 名 字 空 间 可 用。

引 入 一 个 包 时, 则 该 包 所 有 的 公 有 类 和 界 面 均 可 用。

其 形 式 如 下: // 从 acme.project 引 入 所 有 类 import acme.project.*; 这 个 语 句 表 示acme.project中 所 有 的 公 有 类 被 引 入 当 前 包。 以 下 语 句 从acme. project包 中 进 入 一 个 类Employec_List。

//从 acme. project而 引 入 Employee_List import acme.project.Employee_list; Employee_List obj = new Employee_List( ); 在 使 用 一 个 外 部 类 或 界 面 时, 必 须 要 声 明 该 类 或 界 面 所 在 的 包, 否 则 会 产 生 编 译 错 误。 import(引 用) 类 包(class package)用import关 键 词 调 入,指 定package名 字 如 路 径 和 类 名,用*匹 配 符 可 以 调 入 多 于 一 个 类 名。

import java.Date; import java.awt.*;

如 果java源 文 件 不 包 含package,它 放 在 缺 省 的 无 名package。 这 与 源 文 件 同 目 录。 类 可 以 这 样 引 入: import MyClass。

Java系 统 包: Java语 言 提 ?

copy; 了 一 个 包 含 窗 口 工 具 箱, 实 用 程 序, 一 般I/O,工 具 和 网 络 功 能 的 包。

java.applet 这 个 包 包 含 量 了 一 ?copy; 设 计applet的 类,用 一 个 类Applet和 三 个 接 口. AppletContext;AppletStub;和AudioClip.

java.awt 另 一 个 窗 口 工 具 箱 包.awt,包 含 了 一 ?copy; 产 生 装 饰 物 和GUI成 员 的 类。

这 个package包 括:

Button,Checkbox,Choice,Component,Graphics,Menu,Pane1,TextArea和 TextField。

java.io I/O package包 含 文 件 输 入/输 出 类,FileInput Stream和File OutputStream.

java.lang 这 个 包 包 含Java语 言 类,包 含:对 象,线 程,异 常 出 口,系 统,整 数,原 点,数 学,字 符 等。

java.net 这 个 类 支 持TCP/IP网 络 协 议, 并 包 含Socket类,URL和URL相 联 系 的 类。

java.util 这 个 类 包 含 一 ?

copy; 程 序 的 同 步 类,它 包 含Date,Dictionary类 等。

3.10 异 常

当 在Java程 序 中 发 生 一 个 错 误 时, 例 如: 一 个 变 元 的 值 非 法, 代 码 会 发 现 这 个 错 误。 并 引 发 一 个 异 常(exception)。 在 缺 省 的 情 况 下, 异 常 会 输 出 一 个 错 误 消 息, 然 后 中 止 线 程 的 执 行。 但 是, 程 序 自 己 可 以 定 义 异 常 处 理 段(exception handler)来 截 获(catch)异 常, 并 从 错 误 中 恢 复。 有 一 ?copy; 异 常 是 由Java解 释 器 在 运 行 时 刻 引 发 的。

实 际 上, 任 何 类 都 可 以 定 义 属 于 自 己 的 异 常, 并 使 用throw语 句 引 发 它 们。 一 个throw(引 发?copy; 语 句 是 由throw关 键 字 和 一 个 对 象 构 成。 按 常 规, 该 对 象 应 该 是Exception 类 的 实 例 或 其 子 类 的 实 例。throw语 句 会 引 起 执 行 转 向 相 应 的 异 常 处 理 段。

当 一 个throw语 句 执 行 时。 它 下 面 的 所 有 代 码 不 再 执 行 了, 它 所 在 的 方 法 也 不 再 返 回 值。 下 面 的 例 子 将 演 示 如 何 创 建 一 个Exception的 子 类, 然 后 引 发 一 个 异 常。 class MyException extends Exception { } class MyClass { void oops() { if ( /* 不 出 现 错 误 */) { … } else { /* 出 错 */ } else { /* 出 错 */ throw new MyException( ); } } } 为 了 定 义 一 个 异 常 处 理 段, 程 序 必 须 用try语 句 把 可 能 产 生 异 常 的 代 码 成 组。 在try语 句 后 面 跟 上 一 个 或 多 个catch(截 获?

copy; 语 句, 每 个 异 常 对 应 一 个catch语 句。 每 个catch语 句 中 包 含 着 异 常 处 理 段。 例 如: try { p.a=10; } catch ( NullPointerException e) { println(\"p was null\"); } catch ( Exception e) { println (\"other errors occured\"); } catch ( Object obj) { println(\"Who threw that object?\"); } catch语 句 和 一 个 方 法 定 义 类 似, 仅仅 不 过 该 方 法 仅仅 有 一 个 參 数。 且 无 返 回 类 型。 參 数 可 以 是 一 个 类 或 一 个 界 面。

当 一 个 异 常 发 生 时, 嵌 套 的try/catch语 句 会 寻 找 出 与 该 异 常 类 相 匹 配 的 參 数。 如 果 一 个 參 数 和 指 定 异 常 匹 配 则: * 该 參 数 和 指 定 的 异 常 是 同 一 个 类, 或 * 该 參 数 是 指 定 异 常 的 子 类, 或 * 如 果 參 数 是 一 个 界 面。 指 定 异 常 类 实 现 了 这 个 界 面。 第 一 个 參 数 和 异 常 匹 配 的try/catch语 句, 则 与 其 匹 配 的catch语 句 执 行。 在catch语 句 执 行 完 后, 程 序 的 执 行 被 恢 复。

但 已 不 可 能 恢 复 到 异 常 发 生 处 再 次 执 行。 例 如: print ( \"now\"); try { print (\"is\"); throw new MyException( ); print (\"a\"); } catch (MyException e) { print (\"the \"); } print (\"time\\n\"); 打 印 为\"now is the time\"。 正 如 这 个 例 子 所 示, 异 常 应 该 主 要 用 于 错 误 处 理, 若 用 于 其 它 方 面 会 使 代 码 晦 涩 难 ?reg;。

异 常 处 理 段 是 可 以 嵌 套 的, 允 许 异 常 处 理 可 以 发 生 在 多 个 地 方。 嵌 套 异 常 处 理 通 常 用 于 当 第 一 个 处 理 程 序 无 法 完 全 从 错 误 中 恢 复 过 来 的 时 候。 而 不 得 不 执 行 一 ?copy; 清 除 代 码。 为 了 把 异 常 处 理 控 制 传 递 给 更 高 层 的 处 理 段, 可 以 再 一 次 对 截 获 对 象 实 ?copy;throw操 作。 注 要 再 次 实 throw异 常 的 方 法。throw语 句 执 行 完 后。 会 终 止 执 行。 try { f. open ( ); } catch(Exception e) { f. close( ); throw e; } 定 局 语 句 finally(定 局?

copy; 语 句 是 用 于 保 证 无 论 在 异 常 是 否 发 生 的 情 况 下, 某 ?copy; 代 码 被 执 行。 下 例 说 明finally语 句 的 用 法: try { //做 某 ?copy; 动 作; } finally { //此 后 清 除; } 和 以 下 代 码 类 似 try { //做 某 ?copy; 动 作 } catch (Object e) { //此 后 清 除。 throw e; } } //此 后 清 除; 即 使try块 中 包 含return。break。continue,throw语 句,finally语 句 也 会 被 执 行。 例 如: 下 面 的 代 码\"finally\" 总 是 被 输 出。 而\"aftertry\" 仅 在a!=10时 被 输 出。 try { if (a==10) { return ; } } finally { print (\"finally\\n\"); } print (\"after try \\n\"); 运 行 时 刻 异 常 本 节 列 出 的 清 单 是Java解 释 器 引 发 的 各 种 异 常。 当 运 行 时 刻 发 现 各 种 错 误。 由 解 释 器 引 发 异 常。

ArithmeticException 如 果 程 序 试 图 除0。 或 用0取 模, 会 产 生ArithmeticException(算 术 异 常?

copy;。 其 它 算 术 操 作 不 会 产 生 异 常。

有 关Java如 何 处 理 其 它 算 术 错 误 的 信 息, 见\" 整 数 运 算 符\" 和\"浮点 运 算 符\" 两 节。

例 如: 下 面 的 代 码 将 会 引 发ArithmeticException异 常: class Arith { public static void main (String args [ ] ) { int j = 0; j = j/j; } } NullPointerException 当 程 序 试 图 訪 问 一 个 空 对 象 中 的 变 量 或 方 法。 或 一 个 空 数 组 中 的 元 素 时 则 引 发 NullPointerException(空 指 针 异 常?copy;。

例 如, 訪 问 长 度 为0的 数 组a[0]。

有 以 下 类 声 明, 运 行 时 会 引 发NullPointerException异 常: class Null { public static void main(String args [ ]) { String o = null; int a [ ] = null; o.length( ); a[0] = 0; } } 有 趣 的 是。 如 果 我 们 引 发 一 个 空 对 象, 也 会 产 一NullPointerException异 常。 IncompatibleClassChangeException 当 一 个 类 的 定 义 被 改 变。 而 引 用 该 类 的 其 它 类 没 有 被 重 新 编 译 时。 会 产 生 这 一 异 常。

有 四 种 类 更 改 会 导 致 运 行 时 刻 引 发IncompatibleClassChangException异 常。 * 一 个 类 中 的 变 量 声 明 由static变 成 非static, 而 其 它 訪 问 该 类 这 一 变 量 的 类 没 有 被 重 新 编 译。

* 一 个 类 中 的 变 量 声 明 由 非static变 成static, 而 其 它 訪 问 该 类 这 一 变 量 的 类 没 有 被 重 新 编 译。 * 类 中 声 明 的 某 个 域 被 删 除, 而 其 它 訪 问 该 域 的 类 没 有 被 重 新 编 译。

* 类 中 声 明 的 某 个 方 法 被 删 除, 而 其 它 訪 问 该 方 法 的 类 没 有 被 重 新 编 译。

ClassCastException 如 果 试 图 把 对 象o强 制 成Class C, 而o既 不 是Class C的 实 例。 也 不 是Class C子 类 的 实 例, 这 时 便 会 产 生ClassCastException。 class ClassCast { public static void main (String args [ ] ) { Object o = new Object( ); String s = (string) o; s.length( ); } } } NagativeArraySizeException 如 果 一 个 数 组 的 长 度 是 负 数, 则 会 引 发NagativeArraySizeException(数 组 负 下 标?copy; 异 常。 例 如 下 面 类 定 义 的 代 码 在 运 行 时 引 发 这 一 异 常: class NegArray { public static void main(String args [ ]) { int a [ ] = new int [-1]; a[0] = 0; } }

OutOfMemoryException 当 系 统 无 法 再 向 应 用 程 序 提 ?copy; 内 存 时, 会 引 发OutOfMemoryException(内 存 溢 出?copy; 异 常。 这 种 异 常 仅仅 能 出 现 在 创 建 新 对 象 的 时 候, 即new被 调 用 的 时 候。 例 如, 下 面 一 段 代 码 在 运 行 时 刻 会 引 发OutOfMemoryException异 常: class Link { int a [ ] = new int [1000000]; Link l; } Class OutOfMem

{ public static void main(String args [ ]) { public static void main(String args [ ]) { Link root = new link( ); Link cur = root; while (true) { cur.l = new Link( ); cur = cur.l; } } } NoClassDefFoundException 如 果 一 个 类 被 引 用。 但 在 运 行 时 刻, 系 统 没 有 找 到 被 引 用 的 类。 这 时 会 引 发 NoClassDefFoundException(未 找 到 类 定 义?copy; 异 常。 例 如,NoClass

的 声 明 如 下: class NoClass { public static void main(String args [ ]) { C c = new C ( ); } } 当NoClass运 行 时, 如 果 解 释 器 找 不 到C类, 则 会 产 生NoClassDefFoundException。 注 意, 在NoClass被 编 译 时C类 一 定 要 存 在。

IncompatibleType Exception 如 果 试 图 为 一 界 面 作 实 例, 则 会 引 发IncompatibleTypeException(类 型 不 兼 容?copy; 异 常。 例 如。 下 面 的 代 码 会 引 发 一 个IncompatibleTypeException。

Interface I { } class IncompType { public static void main(String args [ ]) { I r = (I) new (\"I\"); } } ArrayIndexOutOfBoundsException 试 图 訪 问 数 组 中 的 一 个 非 法 元 素 时。 会 引 发ArrayIndexOutOfBoundsException(数 组 索 引 越 界?copy; 异 常。

例 如: Class ArrayOut { public static void main(String args [ ]) { int a [ ]=new int[0]; a[0]=0; } } public static void main(String args [ ]) { int a [ ]=new int[0]; a[0]=0; } } UnsatisfiedLinkException 如 果 一 个 方 法 被 声 明 为 本 机, 但 该 方 法 在 运 行 时 刻 却 不 能 连 接 到 一 个 例 程 体 上 去 时, 会 产 生 UnsatisfiedLinkException(无 法 连 接?copy; 异 常。

例 如: Class NoLink { static native void foo( ); public static void main(String args [ ]) { foo( ); } } InternalException InternalException(内 部?copy; 异 常 是 不 能 被 引 发 的。 仅仅 有 在 运 行 失 败 作 一 致 性 检 查 时。 才 会 引 发 这 个 异 常。

本 章 小 结

1. Java语 言 的 基 本 结 构 象C/C++。 2. Java语 言 的 源 程 序 代 码 由 一 个 或 多 个 编 译 单 元(compilation unit)组 成。