第三章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的 运 行 系 统(runtime system)有 效 地 解 释。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 short try
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(字 符 或 字 ??reg;)。 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 字 符 ?reg; 下 边 给 出 的 都 是 字 符 ?reg; 的 例 子: "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里 创 建 数 组,你 可 使 用 两 种 基 本 方 法 ?reg; 一。 创 建 一 个 空 数 组: 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的 结 果 是 除 完 后剩 下 的浮点 数 部 分。 只 有 单 精 度 操 作 数 的浮点 表 达 式 按 照 单精 度 运 算 求 值, 产 生 单 精 度 结 果。 如 果浮点 表 达 式 中 含 有一 个 或 一 个 以 上 的 双 精 度 操 作 数, 则 按 双 精 度 运 算, 结 果是 双 精 度浮点 数。
数 组 运 算 符 数 组 运 算 符 形 式 如 下: <expression> [ <expression>] 可 给 出 数 组 中 某 个 元 素 的 值。 合 法 的 取 值 范 围 是 从0到 数组 的 长 度 减1。 取 值 范 围 的 检 查 只 在 运 行 时 刻 实 ?copy;。
?reg; 运 算 符 ?reg; 以String对 象 实 现。 运 算 符"+"完成 并 ?reg; 操 作, 如 果 必 要 则 自 动 把 操 作 数 转 换 为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语 言 和 解 释 器 限 制 使 用 强 制 和 转 换, 以防 止 出 错 导 致 系 统 崩 溃。 整 数 和浮点 数 ?reg; 间 可 以 来 回 强制 转 换, 但 整 数 不 能 强 制 转 换 成 数 组 或 对 象。 对 象 不 能 被强 制 为 基 本 类 型。
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的 类 包 含 变 量 和 函 数。 数 据 变 量 可 以 是 一 ?copy; 原始 的 类 型,如int,char等。 成 员 函 数 是 一 ?copy; 可 执 行 的 过 程。例 如,下 面 程 序 里: 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)。
成 员 函 数 成 员 函 数 是 一 ?copy; 可 被 其 它 类 或 自 己 类 调用 的 处 理 子 程 序。 一 个 特 殊 的 成 员 函 数 叫 构 造 函 数, 这 个函 数 名 称 一 般 与 本 类 名 程 相 同。 它 没 有 返 回 值。
构 造 函 数 和 成 员 函 数 当 你 在Java里 定 义 一 个 类 时,你 可 定义 一 个 或 多 个 可 选 的 构 造 函 数,当 创 建 本 类 的 一 个 对 象 时用 某 一 个 构 造 函 数 来 初 始 化 本 对 象。 用 前 面 的 程 序 例 子来 说 明,当ClassOne类 创 建 一 个 新 实 例 时, 所 有 成 员 函 数 和 变量 被 创 建(创 建 实 例)。 构 造 函 数 被 调 用。 ClassOne mc: mc = new ClassOne();
关 键 词new用 来 创 建 一 个 类 的 实 例,一 个 类 用new初 始 化 ?reg; 前 并 不 占 用 内 存,它 只 是 一 个 类 型 定 义, 当mc对 象 初 始 化 后,mc对象 里 的i变 量 等 于10。 你 可 以 通 过 对 象 名 来 引 用 变 量i。(有 时称 ?reg; 为 实 例 变 量) mc.i++;//mc实 例 变 量 加1 因 为mc有ClassOne类的 所 有 变 量 和 成 员 函 数, 我 们 可 以 使 用 同 样 的 语 法 来 调用 成 员 函 数 Add_i: Add_i(10); 现 在mc.i变 量 等 于21.
结 束 函 数 Java并 不 支 持 析 构 函 数(C++里 的 定 义),因 为java本身 提 ?copy; 对 象 无 用 时 自 动 清 除 的 功 能,同 时 它 也 提 ?copy; 了 一 个 自 动 拉 圾 箱 的 成 员 函 数, 在 清 除 对 象 时 被 调 用: 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 playing the 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操 作。 注 要 再 次 实 ?copy;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)组 成。