2006 年 12 月 SUN 公 司 发 布 JDK6.0 目 前 主 流 的 JDK 是 Sun 公 司 发 布 的 JDK, 除 了 Sun 之 外, 还 有 很 多 公 司 和 组 织 都 开 发 了 自 己 的 JDK, 例 如 IBM 公 司 开 发 的 JDK,BEA 公 司 的 Jr



Similar documents
《C语言基础入门》课程教学大纲

说 明 为 了 反 映 教 运 行 的 基 本 状 态, 为 校 和 院 制 定 相 关 政 策 和 进 行 教 建 设 与 改 革 提 供 据 依 据, 校 从 程 资 源 ( 开 类 别 开 量 规 模 ) 教 师 结 构 程 考 核 等 维 度, 对 2015 年 春 季 期 教 运 行 基

何 秋 琳 张 立 春 视 觉 学 习 研 究 进 展 视 觉 注 意 视 觉 感 知

评 委 : 李 炎 斌 - 个 人 技 术 标 资 信 标 初 步 审 查 明 细 表 序 号 投 标 单 位 投 标 函 未 按 招 标 文 件 规 定 填 写 漏 填 或 内 容 填 写 错 误 的 ; 不 同 投 标 人 的 投 标 文 件 由 同 一 台 电 脑 或 同 一 家 投 标 单

I

,,,,, :,, (.,, );, (, : ), (.., ;. &., ;.. &.., ;, ;, ),,,,,,, ( ) ( ),,,,.,,,,,, : ;, ;,.,,,,, (., : - ),,,, ( ),,,, (, : ),, :,

Microsoft Word - 第7章 图表反转形态.doc

<433A5C446F63756D656E E E67735C41646D696E F725CD7C0C3E65CC2DBCEC4CFB5CDB3CAB9D3C3D6B8C4CFA3A8BCF2BBAFA3A95CCAB9D3C3D6B8C4CF31302D31392E646F63>

( ) 信 号 与 系 统 Ⅰ 学 科 基 础 必 修 课 教 周 2016 年 06 月 13 日 (08:00-09:35) ( )

修改版-操作手册.doc

评 委 : 徐 岩 宇 - 个 人 技 术 标 资 信 标 初 步 审 查 明 细 表 序 号 投 标 单 位 投 标 函 未 按 招 标 文 件 规 定 填 写 漏 填 或 内 容 填 写 错 误 的 ; 不 同 投 标 人 的 投 标 文 件 由 同 一 台 电 脑 或 同 一 家 投 标 单

龚 亚 夫 在 重 新 思 考 基 础 教 育 英 语 教 学 的 理 念 一 文 中 援 引 的 观 点 认 为 当 跳 出 本 族 语 主 义 的 思 维 定 式 后 需 要 重 新 思 考 许 多 相 连 带 的 问 题 比 如 许 多 发 音 的 细 微 区 别 并 不 影 响 理 解 和

深圳市新亚电子制程股份有限公司

18 上 报 该 学 期 新 生 数 据 至 阳 光 平 台 第 一 学 期 第 四 周 至 第 六 周 19 督 促 学 习 中 心 提 交 新 增 专 业 申 请 第 一 学 期 第 四 周 至 第 八 周 20 编 制 全 国 网 络 统 考 十 二 月 批 次 考 前 模 拟 题 第 一 学

HSK( 一 级 ) 考 查 考 生 的 日 常 汉 语 应 用 能 力, 它 对 应 于 国 际 汉 语 能 力 标 准 一 级 欧 洲 语 言 共 同 参 考 框 架 (CEF) A1 级 通 过 HSK( 一 级 ) 的 考 生 可 以 理 解 并 使 用 一 些 非 常 简 单 的 汉 语


一 公 共 卫 生 硕 士 专 业 学 位 论 文 的 概 述 学 位 论 文 是 对 研 究 生 进 行 科 学 研 究 或 承 担 专 门 技 术 工 作 的 全 面 训 练, 是 培 养 研 究 生 创 新 能 力, 综 合 运 用 所 学 知 识 发 现 问 题, 分 析 问 题 和 解 决

Microsoft Word - 文件汇编.doc

国债回购交易业务指引

ETF、分级基金规模、份额变化统计

第2章 数据类型、常量与变量

2 熟 悉 Visual Basic 的 集 成 开 发 环 境 3 了 解 可 视 化 面 向 对 象 编 程 事 件 驱 动 交 互 式 开 发 等 基 本 概 念 4 了 解 Visual Basic 的 特 点 环 境 要 求 与 安 装 方 法 1 Visual Basic 开 发 应 用

珠江钢琴股东大会

Microsoft Word - 第3章.doc

马 克 思 主 义 公 正 观 的 基 本 向 度 及 方 法 论 原 则!! # #

金 不 少 于 800 万 元, 净 资 产 不 少 于 960 万 元 ; (3) 近 五 年 独 立 承 担 过 单 项 合 同 额 不 少 于 1000 万 元 的 智 能 化 工 程 ( 设 计 或 施 工 或 设 计 施 工 一 体 ) 不 少 于 2 项 ; (4) 近 三 年 每 年

抗 战 时 期 国 民 政 府 的 银 行 监 理 体 制 探 析 % # % % % ) % % # # + #, ) +, % % % % % % % %

2006年顺德区高中阶段学校招生录取分数线

 编号:

登录、注册功能的测试用例设计.doc


<4D F736F F D D323630D6D0B9FAD3A6B6D4C6F8BAF2B1E4BBAFB5C4D5FEB2DFD3EBD0D0B6AF C4EAB6C8B1A8B8E6>

目 录 一 系 统 访 问... 1 二 门 户 首 页 申 报 用 户 审 核 用 户... 2 三 系 统 登 录 用 户 名 密 码 登 录 新 用 户 注 册 用 户 登 录 已 注 册 用

目 录 关 于 图 标... 3 登 陆 主 界 面... 3 工 单 管 理... 5 工 单 列 表... 5 搜 索 工 单... 5 工 单 详 情... 6 创 建 工 单... 9 设 备 管 理 巡 检 计 划 查 询 详 情 销 售 管

<4D F736F F D20B9D8D3DAB0BABBAAA3A8C9CFBAA3A3A9D7D4B6AFBBAFB9A4B3CCB9C9B7DDD3D0CFDEB9ABCBBE C4EAC4EAB6C8B9C9B6ABB4F3BBE1B7A8C2C9D2E2BCFBCAE92E646F6378>

2014年中央财经大学研究生招生录取工作简报


采 取 行 动 的 机 会 90% 开 拓 成 功 的 道 路 2

世华财讯模拟操作手册

中 国 软 科 学 年 第 期!!!

证券代码: 证券简称:长城电脑 公告编号:

0 年 上 半 年 评 价 与 考 核 细 则 序 号 部 门 要 素 值 考 核 内 容 考 核 方 式 考 核 标 准 考 核 ( 扣 原 因 ) 考 评 得 3 安 全 生 产 目 30 无 同 等 责 任 以 上 道 路 交 通 亡 人 事 故 无 轻 伤 责 任 事 故 无 重 大 质 量

中 中 中 中 部 中 岗 位 条 件 历 其 它 历 史 师 地 理 师 生 物 师 体 与 健 康 师 从 事 中 历 史 工 从 事 中 地 理 工 从 事 中 生 物 工 从 事 中 体 与 健 康 工 2. 课 程 与 论 ( 历 史 ); 2. 科 ( 历 史 )

3 月 30 日 在 中 国 证 券 报 上 海 证 券 报 证 券 时 报 证 券 日 报 和 上 海 证 券 交 易 所 网 站 上 发 出 召 开 本 次 股 东 大 会 公 告, 该 公 告 中 载 明 了 召 开 股 东 大 会 的 日 期 网 络 投 票 的 方 式 时 间 以 及 审

教师上报成绩流程图

伊 犁 师 范 学 院 611 语 言 学 概 论 全 套 考 研 资 料 <2016 年 最 新 考 研 资 料 > 2-2 语 言 学 纲 要 笔 记, 由 考 取 本 校 本 专 业 高 分 研 究 生 总 结 而 来, 重 点 突 出, 借 助 此 笔 记 可 以 大 大 提 高 复 习 效

<433A5C C6B73625C B746F705CB9FABCCAD6D0D2BDD2A9D7A8D2B5B8DFBCB6BCBCCAF5D6B0B3C6C6C0C9F3C9EAC7EBD6B8C4CFA3A CDA8D3C3B0E6A3A92E646F63>

课程类 别

名 称 生 命 科 学 学 院 环 境 科 学 1 生 物 学 仅 接 收 院 内 调 剂, 初 试 分 数 满 足 我 院 生 物 学 复 试 最 低 分 数 线 生 命 科 学 学 院 生 态 学 5 生 态 学 或 生 物 学 生 命 科 学 学 院

3 复 试 如 何 准 备 4 复 试 成 绩 计 算 5 复 试 比 例 6 复 试 类 型 7 怎 么 样 面 对 各 种 复 试 04 05

电信系教学大纲的基本规范

全国建筑市场注册执业人员不良行为记录认定标准(试行).doc

一 从 分 封 制 到 郡 县 制 一 从 打 虎 亭 汉 墓 说 起

年 8 月 11 日, 公 司 召 开 2015 年 第 五 次 临 时 股 东 大 会, 审 议 通 过 了 关 于 公 司 <2015 年 股 票 期 权 激 励 计 划 ( 草 案 )> 及 其 摘 要 的 议 案 关 于 提 请 股 东 大 会 授 权 董 事 会 办 理 公

Microsoft Word - 资料分析练习题09.doc

导 数 和 微 分 的 概 念 导 数 的 几 何 意 义 和 物 理 意 义 函 数 的 可 导 性 与 连 续 性 之 间 的 关 系 平 面 曲 线 的 切 线 和 法 线 导 数 和 微 分 的 四 则 运 算 基 本 初 等 函 数 的 导 数 复 合 函 数 反 函 数 隐 函 数 以

2016 年 荔 湾 区 财 政 核 定 支 出 汇 总 表 表 二 单 位 名 称 : 广 州 文 化 公 园 基 本 支 出 项 目 支 出 科 目 编 码 预 算 科 目 名 称 一 般 公 共 预 算 5, , , , ,

全国教师资格认定管理信息系统

Template BR_Rec_2005.dot

现 场 会 议 时 间 为 :2016 年 5 月 19 日 网 络 投 票 时 间 为 :2016 年 5 月 18 日 年 5 月 19 日 其 中 通 过 深 圳 证 券 交 易 所 交 易 系 统 进 行 网 络 投 票 的 时 间 为 2016 年 5 月 19 日 9:30-

上海证券交易所会议纪要

一、资质申请

附 件 : 上 海 市 建 筑 施 工 企 业 施 工 现 场 项 目 管 理 机 构 关 键 岗 位 人 员 配 备 指 南 二 一 四 年 九 月 十 一 日 2

云信Linux SSH认证代理用户手册

21 业 余 制 -- 高 起 专 (12 级 ) 75 元 / 学 分 网 络 学 院 学 生 沪 教 委 财 (2005)49 号 江 西 化 校 工 科 22 业 余 制 -- 高 起 专 (12 级 ) 70 元 / 学 分 网 络 学 院 学 生 沪 教 委 财 (2005)49 号 吉

新, 各 地 各 部 门 ( 单 位 ) 各 文 化 事 业 单 位 要 高 度 重 视, 切 实 加 强 领 导, 精 心 组 织 实 施 要 根 据 事 业 单 位 岗 位 设 置 管 理 的 规 定 和 要 求, 在 深 入 调 查 研 究 广 泛 听 取 意 见 的 基 础 上, 研 究 提

<4D F736F F D20B3D6B2D6CFDEB6EEB1EDB8F1D7EED6D52E646F63>

黄 金 原 油 总 持 仓 增 长, 同 比 增 幅 分 别 为 4.2% 和 4.1% 而 铜 白 银 以 及 玉 米 则 出 现 减 持, 减 持 同 比 减 少 分 别 为 9.4%,9.4% 以 及 6.5% 大 豆, 豆 粕 结 束 连 续 4 周 总 持 仓 量 增 长, 出 现 小 幅

¹ º ¹ º 农 业 流 动 人 口 是 指 户 口 性 质 为 农 业 户 口 在 流 入 地 城 市 工 作 生 活 居 住 一 个 月 及 以 上 的 流 动 人 口 非 农 流 动 人 口 是 指 户 口 性 质 为 非 农 户 口 在 流 入 地 城 市 工 作 生 活 居 住 一 个

随着执业中医师资格考试制度的不断完善,本着为我校中医学专业认证服务的目的,本文通过对我校中医类毕业生参加2012年和2013年的中医执业医师考试成绩及通过率、掌握率进行分析,并与全国的平均水平进行差异比较分析,以此了解我校执业中医师考试的现状,进而反映我校中医类课程总体教学水平,发现考核知识模块教学中存在的不足,反馈给相关学院和教学管理部门,以此提高教学和管理水平。

上海证券交易所会议纪要

收 入 支 出 项 目 2016 年 预 算 项 目 2016 年 预 算 预 算 01 表 单 位 : 万 元 ( 保 留 两 位 小 数 ) 一 公 共 财 政 预 算 拨 款 一 人 员 经 费 一 般 财 力 人 员 支 出 成 品

4 进 入 交 互 区 设 置 的 组 件 管 理, 在 组 件 管 理 中, 教 师 可 以 选 择 课 程 空 间 中 的 所 有 组 件, 并 通 过 点 击 启 用 或 不 启 用 选 定 组 件 在 课 程 空 间 中 的 显 示 5 进 入 工 作 室 管 理 的 工 作 室 首 页,

上证指数

01

抗 日 战 争 研 究 年 第 期


自 服 务 按 钮 无 法 访 问 新 系 统 的 自 服 务 页 面 因 此 建 议 用 户 从 信 网 中 心 ( 主 页, 右 下 角 位 置 的 常 用 下 载, 或 校 园 网 用 户 自 服 务 ( 首 页

关于修订《沪市股票上网发行资金申购

光明乳业股份有限公司


学 年 第 二 学 期 集 中 考 试 安 排 (18 周 ) 考 试 日 期 :6 月 27 日 星 期 一 8:10-9:50 第 二 公 共 教 学 楼 A 区 A 高 等 数 学 ( 理 二 2) 复 材 材 料 科 学 与 工 程

超 级 玛 丽 JAVA 小 游 戏 测 试 报 告 1. 导 言 1.1 编 写 目 的 该 文 档 的 目 的 是 描 述 超 级 玛 丽 JAVA 小 游 戏 的 系 统 测 试 的 总 结 报 告, 其 主 要 内 容 包 括 : 系 统 环 境 的 介 绍 功 能 的 实 现 的 测 试

一 开 放 性 的 政 策 与 法 规 二 两 岸 共 同 的 文 化 传 承 三 两 岸 高 校 各 自 具 有 专 业 优 势 远 见 杂 志 年 月 日

第 六 章 债 券 股 票 价 值 评 估 1 考 点 一 : 债 券 价 值 的 影 响 因 素 2

第二讲 数列

( 此 页 无 正 文, 为 广 东 东 方 精 工 科 技 股 份 有 限 公 司 关 于 提 供 资 料 真 实 准 确 和 完 整 的 承 诺 函 之 签 署 页 ) 广 东 东 方 精 工 科 技 股 份 有 限 公 司 法 定 代 表 人 : 唐 灼 林 2016 年 7 月 28 日

正 规 培 训 达 规 定 标 准 学 时 数, 并 取 得 结 业 证 书 二 级 可 编 程 师 ( 具 备 以 下 条 件 之 一 者 ) (1) 连 续 从 事 本 职 业 工 作 13 年 以 上 (2) 取 得 本 职 业 三 级 职 业 资 格 证 书 后, 连 续 从 事 本 职 业

工 程 勘 察 资 质 标 准 根 据 建 设 工 程 勘 察 设 计 管 理 条 例 和 建 设 工 程 勘 察 设 计 资 质 管 理 规 定, 制 定 本 标 准 一 总 则 ( 一 ) 本 标 准 包 括 工 程 勘 察 相 应 专 业 类 型 主 要 专 业 技 术 人 员 配 备 技 术

Microsoft Word - 中节能_工业项目节能评估审查导则Draft.doc

<443A5C6D B5C30312EB9A4D7F7CEC4B5B55C30322EBACFCDACCEC4B5B55C C30342EC8CBC9E7CCFC5C31332ECFEEC4BFC5E0D1B55C E30385C322EB2D9D7F7CAD6B2E12E646F63>

<4D F736F F D20B6C0C1A2B6ADCAC2D0ECCCFABEFDCFC8C9FABCB0CCE1C3FBC8CBC9F9C3F72E646F63>

目 录 第 一 章 博 星 卓 越 电 子 商 务 营 销 策 划 实 践 平 台 硬 件 使 用 介 绍... 3 第 二 章 博 星 卓 越 电 子 商 务 营 销 策 划 实 践 平 台 管 理 员 端 功 能 使 用 介 绍 系 统 管 理 员 登 陆 班

年 第 期 % %! & % % % % % % &

全国艺术科学规划项目

定 位 和 描 述 : 程 序 设 计 / 办 公 软 件 高 级 应 用 级 考 核 内 容 包 括 计 算 机 语 言 与 基 础 程 序 设 计 能 力, 要 求 参 试 者 掌 握 一 门 计 算 机 语 言, 可 选 类 别 有 高 级 语 言 程 序 设 计 类 数 据 库 编 程 类

第 一 部 分 MagiCAD for Revit 安 装 流 程

<4D F736F F D C4EAB9A4B3CCCBB6CABFCAFDD1A7D7A8D2B5BFCEBFBCCAD4B4F3B8D9D3EBD2AAC7F3>

2. 本 次 修 改 后, 投 资 者 申 购 新 股 的 持 有 市 值 要 求 市 值 计 算 规 则 及 证 券 账 户 使 用 的 相 关 规 定 是 否 发 生 了 变 化? 答 : 未 发 生 变 化 投 资 者 申 购 新 股 的 持 有 市 值 是 指, 以 投 资 者 为 单 位


Transcription:

1 Java 入 门 Java 是 一 门 很 优 秀 的 编 程 语 言, 具 有 面 向 对 象 与 平 台 无 关 安 全 稳 定 和 多 线 程 等 特 点, 是 目 前 软 件 设 计 中 极 为 健 壮 的 编 程 语 言 Java 不 仅 可 以 用 来 开 发 大 型 的 应 用 程 序, 而 且 特 别 适 合 于 Internet 的 应 用 开 发 Java 确 实 具 备 了 一 次 编 写, 处 处 运 行 的 特 点,Java 已 成 为 网 络 时 代 最 重 要 的 编 程 语 言 之 一 1.1 Java 的 诞 生 在 1990 年,Sun 公 司 成 立 了 一 个 由 James Gosling 领 导 的 软 件 设 计 团 队, 他 们 合 作 的 项 目 称 为 绿 色 计 划 他 们 认 为 计 算 机 技 术 发 展 的 一 个 趋 势 是 数 字 家 电 之 间 的 通 讯 James 开 始 负 责 为 设 备 和 用 户 之 间 的 交 流 创 建 一 种 能 够 实 现 网 络 交 互 的 语 言 随 着 大 量 的 时 间 和 金 钱 投 入 到 绿 色 计 划, 他 们 创 建 了 一 种 语 言 这 种 语 言 一 开 始 被 叫 做 Oak, 这 个 名 字 得 自 于 Gosling 想 名 字 时 看 到 了 窗 外 的 一 棵 橡 树, 后 来 被 改 为 了 Java Java 的 快 速 发 展 得 利 于 Internet 和 Web 的 出 现, 到 了 2000 年,Java 已 经 成 为 世 界 上 最 流 行 的 电 脑 语 言 绿 色 小 组 当 初 设 计 Java 是 为 了 面 向 数 字 家 庭, 支 持 各 种 家 电 设 备 他 们 没 有 想 到 的 是,Java 支 持 的 计 算 模 式, 实 际 上 就 是 互 联 网 的 模 式 Java 的 重 要 历 史 事 件 : 时 间 事 件 1995 年 5 月 23 日 Java 语 言 诞 生 1996 年 1 月 第 一 个 JDK-JDK1.0 诞 生 1996 年 4 月 10 个 最 重 要 的 操 作 系 统 供 应 商 申 明 将 在 其 产 品 中 嵌 入 JAVA 技 术 1997 年 2 月 18 日 JDK1.1 发 布 1998 年 12 月 8 日 JAVA2 企 业 平 台 J2EE 发 布 1999 年 6 月 SUM 公 司 发 布 Java 的 三 个 版 本 : 标 准 版 (J2SE) 企 业 版 (J2EE) 和 微 型 版 (J2ME) 2004 年 9 月 30 日 J2SE1.5 发 布, 成 为 Java 语 言 发 展 史 上 的 又 一 里 程 碑 为 了 表 示 该 版 本 的 重 要 性,J2SE1.5 更 名 为 Java SE 5.0 第 1 页

2006 年 12 月 SUN 公 司 发 布 JDK6.0 目 前 主 流 的 JDK 是 Sun 公 司 发 布 的 JDK, 除 了 Sun 之 外, 还 有 很 多 公 司 和 组 织 都 开 发 了 自 己 的 JDK, 例 如 IBM 公 司 开 发 的 JDK,BEA 公 司 的 Jrocket, 还 有 GNU 组 织 开 发 的 JDK 等 等 印 度 尼 西 亚 有 一 个 重 要 的 盛 产 咖 啡 的 岛 屿, 中 文 名 叫 爪 哇, 开 发 人 员 为 这 种 新 的 语 言 起 名 为 Java, 其 寓 意 是 为 世 人 端 上 一 杯 香 浓 的 热 咖 啡 现 在 就 让 我 们 来 一 起 品 尝 吧 1.2 Java 编 程 语 言 是 什 么 Java 的 内 容 很 丰 富, 实 现 的 功 能 也 很 多, 我 们 从 以 下 几 个 角 度 来 描 述 它 一 种 计 算 机 编 程 语 言 一 种 软 件 开 发 平 台 一 种 软 件 运 行 平 台 一 种 软 件 部 署 环 境 句 法 与 C++ 相 似, 语 义 与 Small Talk 相 似 用 来 开 发 applets, 又 用 来 开 发 applications 1 Java 是 一 种 计 算 机 编 程 语 言 语 言 我 们 说 的 普 通 话 英 语 都 是 语 言, 语 言 是 一 种 交 流 的 工 具, 语 言 具 有 创 造 性 和 结 构 性, 并 且 代 表 一 定 的 意 义 比 如 我 说 下 课 了, 大 家 都 明 白 什 么 意 思, 证 明 这 个 语 句 的 意 思 表 达 清 楚 了, 正 规 的 语 言 在 交 流 上 是 不 能 有 歧 义 的 计 算 机 编 程 计 算 机 编 程 就 是 : 把 程 序 员 的 要 求 和 设 想, 按 照 能 够 让 计 算 机 看 得 懂 的 规 则 和 约 定, 编 写 出 来 的 过 程, 就 是 编 程 编 程 的 结 果 就 是 一 些 计 算 机 能 够 看 懂 并 能 够 执 行 和 处 理 的 东 西, 我 们 把 它 叫 做 软 件 或 者 程 序 事 实 上, 程 序 就 是 我 们 对 计 算 机 发 出 的 命 令 集 ( 指 令 集 ) Java 是 一 种 计 算 机 编 程 语 言 首 先,Java 是 一 种 语 言, 也 就 是 Java 是 用 来 交 流 的, 那 么 用 来 谁 和 谁 交 流 呢? 很 明 显 就 是 程 序 员 和 计 算 机 交 流, 换 句 话 说 把 我 们 的 要 求 和 设 想 用 Java 语 言 表 达 出 来, 那 么 计 算 机 能 看 懂, 就 能 够 按 照 我 们 要 求 运 行, 而 这 个 过 程 就 是 我 们 所 说 的 使 用 Java 编 程, 所 以 我 们 讲 Java 是 一 种 计 算 机 编 程 语 言 为 了 让 计 算 机 看 懂,Java 会 有 一 系 列 的 规 则 和 约 定, 这 些 就 是 Java 的 语 法 2 Java 是 一 种 软 件 开 发 平 台 什 么 是 软 件 开 发 可 以 简 单 地 理 解 为 : 编 程 的 结 果 是 软 件 或 者 程 序, 而 编 程 的 过 程 就 是 软 件 开 发 软 件 开 发 的 基 本 步 骤 包 括 : 需 求 分 析 概 要 设 计 详 细 设 计 编 码 测 试 维 护 等 阶 段 需 求 分 析 : 这 里 指 的 需 求 不 仅 仅 是 用 户 需 求, 应 该 是 开 发 中 遇 到 的 所 有 的 需 求 比 如, 你 首 第 2 页

先 要 知 道 做 这 个 项 目 是 为 了 解 决 什 么 问 题 ; 测 试 案 例 中 应 该 输 入 什 么 数 据 为 了 清 楚 地 知 道 这 些 需 求, 你 经 常 要 和 客 户 项 目 经 理 以 及 项 目 伙 伴 调 查 研 究, 这 就 是 需 求 分 析 概 要 设 计 详 细 设 计 : 根 据 软 件 系 统 需 求 完 成 对 系 统 的 设 计, 确 定 强 壮 的 系 统 架 构, 设 计 模 块 层 次 用 户 界 面 和 数 据 库 表 结 构 编 码 : 开 发 代 码, 完 成 设 计 的 具 体 实 现 测 试 : 利 用 测 试 工 具 按 照 测 试 方 案 和 业 务 流 程 对 产 品 进 行 功 能 和 性 能 测 试, 对 测 试 方 案 可 能 出 现 的 问 题 进 行 分 析 和 评 估, 并 修 改 代 码 维 护 : 根 据 用 户 需 求 的 变 化 或 硬 件 环 境 的 变 化, 对 应 用 程 序 进 行 部 分 或 全 部 的 修 改 用 以 下 的 流 程 图 来 表 达 这 个 过 程 : 需 求 分 析 概 要 设 计 软 件 设 计 和 实 现 软 件 测 试 详 细 设 计 编 单 码 元 测 试 代 码 测 试 交 付 维 护 功 能 测 试 验 收 测 试 什 么 是 开 发 平 台 在 软 件 开 发 的 过 程 中, 我 们 需 要 很 多 的 工 具 来 辅 助 我 们 的 工 作, 不 可 能 什 么 都 从 头 自 己 做 我 们 把 编 程 的 环 境 和 相 应 的 辅 助 工 具 统 称 为 开 发 环 境, 开 发 平 台 就 是 用 来 提 供 这 个 开 发 环 境 的 车 床 工 人 需 要 一 个 车 床 才 能 工 作 一 样 Java 是 一 种 开 发 平 台 Java 不 单 纯 是 一 个 编 程 的 语 言, 它 自 身 提 供 了 一 系 列 开 发 Java 所 需 要 的 环 境 和 工 具, 来 进 行 编 译 解 释 文 档 生 成 打 包 等, 比 如 :javac.exe java.exe 等 等, 这 些 我 们 后 面 会 讲 到, 所 以 我 们 讲 Java 是 一 个 开 发 平 台 3 Java 是 一 种 软 件 运 行 平 台 什 么 是 软 件 的 运 行 平 台 如 同 人 类 需 要 阳 光 空 气 水 和 食 物 才 能 正 常 存 活 一 样, 软 件 最 终 要 能 够 运 行, 也 需 要 一 系 列 的 外 部 环 境, 来 为 软 件 的 运 行 提 供 支 持, 而 提 供 这 些 支 持 的 就 是 运 行 平 台 Java 是 一 种 软 件 运 行 平 台 第 3 页

Java 本 身 提 供 Java 软 件 所 需 要 的 运 行 环 境,Java 应 用 可 运 行 在 安 装 了 JRE(Java Runtime Environment) 的 机 器 上, 所 以 我 们 说 Java 是 一 个 运 行 平 台 JRE:Java Runtime Environment,Java 运 行 环 境 4 Java 是 一 种 软 件 部 署 环 境 什 么 是 软 件 的 部 署 简 单 地 讲, 部 署 就 是 安 装, 就 是 把 软 件 放 置 到 相 应 的 地 方, 并 且 进 行 相 应 的 配 置 ( 一 般 称 作 部 署 描 述 ) 让 软 件 能 够 正 常 运 行 起 来 Java 是 一 种 软 件 部 署 环 境 Java 本 身 是 一 个 开 发 的 平 台, 开 发 后 的 Java 程 序 也 是 运 行 在 Java 平 台 上 的 也 就 是 说, 开 发 后 的 Java 程 序 也 是 部 署 在 Java 平 台 上 的, 这 个 尤 其 在 后 面 学 习 JEE(Java 的 企 业 版 ) 的 时 候, 体 现 更 为 明 显 1.3 Java 能 干 什 么 Java 能 做 的 事 情 很 多, 涉 及 到 编 程 领 域 的 各 个 方 面 桌 面 级 应 用 : 尤 其 是 需 要 跨 平 台 的 桌 面 级 应 用 程 序 桌 面 级 应 用 : 简 单 的 说 就 是 主 要 功 能 都 在 我 们 本 机 上 运 行 的 程 序, 比 如 word excel 等 运 行 在 本 机 上 的 应 用 就 属 于 桌 面 应 用 企 业 级 应 用 企 业 级 应 用 : 简 单 的 说 就 是 大 规 模 的 应 用, 一 般 使 用 人 数 较 多, 数 据 量 较 大, 对 系 统 的 稳 定 性 安 全 性 可 扩 展 性 和 可 装 配 性 等 都 有 比 较 高 的 要 求 举 例 说 明 一 下 : 组 件 化 : 企 业 级 应 用 通 常 比 较 复 杂, 组 件 化 能 够 更 好 对 业 务 进 行 建 模, 提 高 系 统 的 扩 展 性 和 维 护 性, 做 到 组 件 复 用 分 布 式 : 企 业 组 织 机 构 复 杂, 同 一 地 有 多 个 分 部, 或 者 跨 省, 甚 至 跨 国, COABA, RMI, Web Services 是 JavaEE 中 支 持 的 分 布 式 访 问 技 术, 还 有 分 布 式 的 连 接, 如 系 统 需 要 接 入 多 个 数 据 源, 可 以 用 JNDI 来 透 明 实 现 事 务 管 理 : 为 了 保 证 数 据 的 安 全 操 作 安 全 访 问, 事 务 是 不 可 缺 少 的, 事 实 上 只 要 操 作 数 据 库, 就 离 不 开 事 务 管 理 消 息 管 理 : 通 过 消 息 来 实 现 异 步 触 发 从 而 降 低 系 统 耦 合 性, 提 高 系 统 吞 吐 量 一 个 电 子 商 务 网 站 也 可 以 使 用 消 息 来 进 行 异 步 发 邮 件, 但 在 企 业 级 应 用 当 中, 根 据 实 际 需 求 还 可 以 演 变 成 更 多 复 杂 的 应 用,JEE 提 供 JMS 实 现 消 息 管 理 安 全 性 : 企 业 级 应 用 的 数 据 都 更 为 敏 感 ( 比 如 公 司 的 销 售 数 据 财 务 数 据 ), 需 要 为 此 提 供 严 格 的 安 全 性 保 护, 企 业 级 组 织 的 复 杂 性 接 入 访 问 的 多 样 性 增 加 了 安 全 策 略 实 施 的 难 度, JAAS 为 此 提 供 了 一 整 套 的 安 全 策 略, 方 便 企 业 级 应 用 以 安 全 一 致 便 捷 的 方 式 实 现 安 全 机 第 4 页

制 目 前 企 业 级 应 用 是 Java 应 用 最 广 泛 的 一 个 领 域, 几 乎 一 枝 独 秀 包 括 各 种 行 业 应 用 企 业 信 息 化 电 子 政 务 等, 包 括 办 公 自 动 化 OA, 人 力 资 源 HR, 客 户 关 系 管 理 CRM, 企 业 资 源 计 划 ERP 供 应 链 管 理 SCM 企 业 设 备 管 理 系 统 EAM 产 品 生 命 周 期 管 理 PLM 面 向 服 务 体 系 架 构 SOA 商 业 智 能 BI 项 目 管 理 PM 营 销 管 理 流 程 管 理 WorkFlow 财 务 管 理 等 等 几 乎 所 有 你 能 想 到 的 应 用 嵌 入 式 设 备 及 消 费 类 电 子 设 备 包 括 无 线 手 持 设 备 智 能 卡 通 信 终 端 医 疗 设 备 信 息 家 电 ( 如 数 字 机 顶 盒 电 冰 箱 ) 汽 车 导 航 系 统 等 都 是 近 年 以 来 热 门 的 Java 应 用 领 域, 尤 其 是 手 机 上 的 Java 应 用 程 序 和 Java 游 戏, 更 是 普 及 嵌 入 式 装 置 答 题 上 区 分 为 两 种 : 一 种 是 运 算 功 能 有 限 电 力 供 应 也 有 限 的 嵌 入 式 装 置, 例 如 : PDA 手 机 ; 另 外 一 种 则 是 运 算 能 力 相 对 较 佳 并 且 电 力 供 应 上 相 对 比 较 充 足 的 嵌 入 式 装 置, 比 如 : 冷 气 机 电 冰 箱 电 视 机 顶 盒 除 了 上 面 提 到 的,Java 还 有 很 多 功 能 : 如 进 行 数 学 运 算 显 示 图 形 界 面 进 行 网 络 操 作 进 行 数 据 库 操 作 进 行 文 件 的 操 作 等 等 1.4 Java 有 什 么 Java 体 系 比 较 庞 杂, 功 能 繁 多, 这 也 导 致 很 多 人 在 自 学 Java 的 时 候 总 是 感 觉 无 法 建 立 全 面 的 知 识 体 系, 无 法 从 整 体 上 把 握 Java 的 原 因 在 这 里 我 们 先 简 单 了 解 一 下 Java 的 版 本 Java 分 成 三 种 版 本, 分 别 是 : Java 标 准 版 (JSE) Java 微 缩 版 (JME) 和 Java 企 业 版 (JEE) 每 一 种 版 本 都 有 自 己 的 功 能 和 应 用 方 向 Java 标 准 版 : JSE(Java Standard Edition) JSE 是 Sun 公 司 针 对 桌 面 开 发 以 及 低 端 商 务 计 算 解 决 方 案 而 开 发 的 版 本, 例 如 : 我 们 平 常 熟 悉 的 Application 桌 面 应 用 程 序 这 个 版 本 是 个 基 础, 它 也 是 我 们 平 常 开 发 和 使 用 最 多 的 技 术,Java 的 主 要 的 技 术 将 在 这 个 版 本 中 体 现 本 书 主 要 讲 的 就 是 JSE Java 微 缩 版 :JME(Java Micro Edition) JME 是 对 标 准 版 JSE 进 行 功 能 缩 减 后 的 版 本, 于 1999 年 6 月 由 Sun Microsystems 第 一 次 推 向 Java 团 体 它 是 一 项 能 更 好 满 足 Java 开 发 人 员 不 同 需 求 的 广 泛 倡 议 的 一 部 分 Sun Microsystems 将 JME 定 义 为 一 种 以 广 泛 的 消 费 性 产 品 为 目 标 的 高 度 优 化 的 Java 运 行 时 环 境, 应 用 范 围 包 括 掌 上 电 脑 移 动 电 话 可 视 电 话 数 字 机 顶 盒 和 汽 车 导 航 系 统 及 其 他 无 线 设 备 等 JME 是 致 力 于 消 费 产 品 和 嵌 入 式 设 备 的 开 发 人 员 的 最 佳 选 择 尽 管 早 期 人 们 对 它 看 好 而 且 Java 开 发 人 员 团 体 中 的 热 衷 人 士 也 不 少, 然 而 JME 最 近 才 开 始 从 其 影 响 更 大 的 同 属 产 品 JEE 和 第 5 页

JSE 的 阴 影 中 走 出 其 不 成 熟 期 JME 在 开 发 面 向 内 存 有 限 的 移 动 终 端 ( 例 如 掌 上 电 脑 移 动 电 话 ) 的 应 用 时, 显 得 尤 其 实 用 因 为 它 是 建 立 在 操 作 系 统 之 上 的, 使 得 应 用 的 开 发 无 须 考 虑 太 多 特 殊 的 硬 件 配 置 类 型 或 操 作 系 统 因 此, 开 发 商 也 无 须 为 不 同 的 终 端 建 立 特 殊 的 应 用, 制 造 商 也 只 需 要 简 单 地 使 它 们 的 操 作 平 台 可 以 支 持 JME 便 可 Java 企 业 版 :JEE(Java Enterprise Edition) JEE 是 一 种 利 用 Java 平 台 来 简 化 企 业 解 决 方 案 的 开 发 部 署 和 管 理 相 关 的 复 杂 问 题 的 体 系 结 构 JEE 技 术 的 基 础 就 是 核 心 Java 平 台 或 Java 平 台 的 标 准 版,JEE 不 仅 巩 固 了 标 准 版 中 的 许 多 优 点, 例 如 一 次 编 写 处 处 运 行 的 特 性 方 便 存 取 数 据 库 的 JDBC API CORBA 技 术 以 及 能 够 在 Internet 应 用 中 保 护 数 据 的 安 全 模 式 等 等, 同 时 还 提 供 了 对 EJB(Enterprise Java Beans) Java Servlets API JSP(Java Server Pages) 以 及 XML 技 术 的 全 面 支 持 其 最 终 目 的 就 是 成 为 一 个 能 够 使 企 业 开 发 者 大 幅 缩 短 投 放 市 场 时 间 的 体 系 结 构 JEE 体 系 结 构 提 供 中 间 层 集 成 框 架 来 满 足 无 需 太 多 费 用 而 又 需 要 高 可 用 性 高 可 靠 性 以 及 可 扩 展 性 的 应 用 的 需 求 通 过 提 供 统 一 的 开 发 平 台,JEE 降 低 了 开 发 多 层 应 用 的 费 用 和 复 杂 性, 同 时 提 供 对 现 有 应 用 程 序 集 成 强 有 力 支 持, 完 全 支 持 Enterprise Java Beans, 有 良 好 的 向 导 支 持 打 包 和 部 署 应 用, 添 加 了 目 录 支 持, 增 强 了 安 全 机 制, 提 高 了 性 能 JEE 是 对 标 准 版 进 行 功 能 扩 展, 提 供 一 系 列 功 能, 用 来 解 决 进 行 企 业 应 用 开 发 中 所 面 临 的 复 杂 的 问 题 具 体 的 我 们 会 放 到 后 面 JEE 的 课 程 去 讲 三 个 版 本 之 间 的 关 系 : JEE 几 乎 完 全 包 含 JSE 的 功 能, 然 后 在 JSE 的 基 础 上 添 加 了 很 多 新 的 功 能 JME 主 要 是 JSE 的 部 分 功 能 子 集, 然 后 再 加 上 一 部 分 额 外 添 加 的 功 能 如 下 图 所 示 : JEE JSE JME Java 的 API 类 库 之 中 有 一 组 所 谓 的 核 心 类 (CoreClass, 即 java.*), 在 核 心 类 之 外 还 有 所 谓 的 扩 充 类 (Extended Class, 即 javax.*) 根 据 对 这 两 种 类 的 支 持 程 度, 进 而 区 分 出 几 种 不 同 的 Java 版 本 我 们 必 须 以 Java Standard Edition(JSE) 作 为 基 准, 这 个 版 本 做 了 所 有 Java 标 准 规 格 之 中 所 定 义 的 核 心 类, 也 支 持 所 有 的 Java 基 本 类 JSE 定 位 在 客 户 端 程 序 的 应 用 上 第 6 页

从 JSE 往 外 延 伸, 其 外 面 为 Java Enterprise Edition(JEE), 此 版 本 除 了 支 持 所 有 的 标 准 核 心 类 外, 而 且 还 增 加 了 许 多 支 持 企 业 内 部 使 用 的 扩 充 类, 支 持 Servlet/ JSP 的 javax.servlet.* 类 支 持 Enterprise Java Bean 的 javax.ejb.* 类 当 然,JEE 必 定 支 持 所 有 的 Java 基 本 类 JEE 定 位 在 服 务 器 端 (server-side) 程 序 的 应 用 上 从 JSE 向 内 看, 是 Java Micro Edition(JME), 它 所 支 持 的 只 有 核 心 类 的 子 集 合, 在 JME CLDC 的 规 格 之 中, 只 支 持 java.lang.* java.io.* 以 及 java.util.* 这 些 类 此 版 本 也 增 加 了 一 些 支 持 微 小 装 置 的 扩 充 类, 如 javax.microedition.io.* 类 然 而, 此 版 本 并 不 支 持 所 有 的 Java 基 本 类, 就 标 准 的 JMECLDC, 也 就 是 能 在 PalmOS 上 执 行 的 KVM(KVirtualMachine) 来 说, 它 就 不 支 持 属 于 浮 点 数 (float double) 的 Java 基 本 类 JME 定 位 在 嵌 入 式 系 统 的 应 用 上 最 里 层, 还 有 一 个 Java 的 Smart Card 版 本, 原 本 在 Java 的 文 件 之 中 并 没 有 这 样 定 义, 但 是 将 它 画 在 JME 内 部 是 很 合 理 的 因 为 SmartCard 版 本 只 支 持 java.lang.* 这 个 核 心 类, 比 起 JME 所 支 持 的 核 心 类 更 少, 但 它 也 有 属 于 自 己 的 扩 充 类, 如 javacard.* javacardx.* 这 些 类 SmartCard 版 本 只 支 持 Boolean 与 Byte 这 两 种 Java 基 本 类, 此 版 本 定 位 在 SmartCard 的 应 用 上 1.5 Java 的 特 点 简 单 地 说,Java 具 有 如 下 特 点 : 简 单 的 面 向 对 象 的 平 台 无 关 的 多 线 程 的 安 全 的 高 效 的 健 壮 的 动 态 的 等 特 点 简 单 的 简 单 是 指 Java 既 易 学 又 好 用 不 要 将 简 单 误 解 为 这 门 编 程 语 言 很 干 瘪 你 可 能 很 赞 同 这 样 的 观 点 : 英 语 要 比 阿 拉 伯 语 言 容 易 学 但 这 并 不 意 味 着 英 语 就 不 能 表 达 丰 富 的 内 容 和 深 刻 的 思 想, 许 多 荣 获 诺 贝 尔 文 学 奖 的 作 品 都 是 用 英 文 写 的 如 果 你 学 习 过 C++, 你 会 感 觉 Java 很 眼 熟, 因 为 Java 中 许 多 基 本 语 句 的 语 法 和 C++ 一 样, 像 常 用 的 循 环 语 句 控 制 语 句 等 和 C++ 几 乎 一 样, 但 不 要 误 解 为 Java 是 C++ 的 增 强 版,Java 和 C++ 是 两 种 完 全 不 同 的 编 程 语 言, 它 们 各 有 各 的 优 势, 将 会 长 期 并 存 下 去,Java 和 C++ 已 成 为 软 件 开 发 者 应 当 掌 握 的 编 程 语 言 如 果 从 语 言 的 简 单 性 方 面 看,Java 要 比 C++ 简 单,C++ 中 有 许 多 容 易 混 淆 的 概 念, 或 者 被 Java 弃 之 不 用 了, 或 者 以 一 种 更 清 楚 更 容 易 理 解 的 方 式 实 现, 例 如,Java 不 再 有 指 针 的 概 念 面 向 对 象 的 面 向 对 象 是 指 以 对 象 为 基 本 粒 度, 其 下 包 含 属 性 和 方 法 对 象 的 说 明 用 属 性 表 达, 而 通 过 使 用 方 法 来 操 作 这 个 对 象 面 向 对 象 技 术 使 得 应 用 程 序 的 开 发 变 得 简 单 易 用, 节 省 代 码 基 于 对 象 的 编 程 更 符 合 人 的 思 维 模 式, 使 人 们 更 容 易 编 写 程 序 Java 是 一 种 面 向 对 象 的 语 言, 也 继 承 了 面 向 对 象 的 诸 多 好 处, 如 代 码 扩 展 代 码 复 用 等 我 们 将 在 以 后 的 章 节 中 详 细 地 讨 论 类 对 象 等 概 念 平 台 无 关 的 与 平 台 无 关 是 Java 最 大 的 优 势 其 他 语 言 编 写 的 程 序 面 临 的 一 个 主 要 问 题 是 : 操 作 系 统 的 变 化, 处 理 器 升 级 以 及 核 心 系 统 资 源 的 变 化, 都 可 能 导 致 程 序 出 现 错 误 或 无 法 运 行 而 用 Java 写 的 程 序 不 用 修 改 就 可 在 不 同 的 软 硬 件 平 台 上 运 行 这 样 就 能 实 现 同 样 的 程 序 既 可 以 在 第 7 页

Windows 下 运 行, 到 了 Unix 或 者 Linux 环 境 不 用 修 改 就 直 接 可 以 运 行 了 Java 主 要 靠 Java 虚 拟 机 (JVM) 实 现 平 台 无 关 性 平 台 无 关 性 就 是 一 次 编 写, 到 处 运 行 :Write Once, Run Anywhere 多 线 程 的 Java 实 现 了 内 置 对 多 线 程 的 支 持 多 线 程 允 许 同 时 完 成 多 个 任 务 实 际 上 多 线 程 使 人 产 生 多 个 任 务 在 同 时 执 行 的 错 觉, 因 为, 目 前 的 计 算 机 的 处 理 器 在 同 一 时 刻 只 能 执 行 一 个 线 程, 但 处 理 器 可 以 在 不 同 的 线 程 之 间 快 速 地 切 换, 由 于 处 理 器 速 度 非 常 快, 远 远 超 过 了 人 接 收 信 息 的 速 度, 所 以 给 人 的 感 觉 好 像 多 个 任 务 在 同 时 执 行 C++ 没 有 内 置 的 多 线 程 机 制, 因 此 必 须 调 用 操 作 系 统 的 多 线 程 功 能 来 进 行 多 线 程 程 序 的 设 计 安 全 的 安 全 性 可 以 分 为 四 个 层 面, 即 编 译 类 装 载 字 节 码 校 验 沙 箱 机 制 高 效 的 高 级 语 言 程 序 必 须 转 换 为 机 器 语 言 程 序 才 能 执 行, 但 不 同 的 计 算 机 系 统 所 使 用 的 机 器 语 言 不 同 Java 为 了 实 现 一 次 编 译, 随 处 运 行 的 目 标,Java 的 源 程 序 在 编 译 时, 并 不 直 接 编 译 成 特 定 的 机 器 语 言 程 序, 而 是 编 译 成 与 系 统 无 关 的 字 节 码, 由 Java 虚 拟 机 (JVM ) 来 执 行 当 JVM 解 释 执 行 Java 程 序 时,Java 实 时 编 译 器 (Just-In-Time,JIT) 会 将 字 节 码 译 成 目 标 平 台 对 应 的 机 器 语 言 的 指 令 代 码 早 先 的 许 多 尝 试 解 决 跨 平 台 的 方 案 对 性 能 要 求 都 很 高 其 他 解 释 执 行 的 语 言 系 统, 如 BASIC PERL 都 有 无 法 克 服 的 性 能 缺 陷 然 而,Java 却 可 以 在 非 常 低 档 的 CPU 上 顺 畅 运 行, 这 是 因 为 Java 字 节 码 是 经 过 精 心 设 计 的, 能 够 直 接 使 用 JIT 编 译 技 术 将 字 节 码 转 换 成 高 性 能 的 本 机 代 码 事 实 上,Java 的 运 行 速 度 随 着 JIT 编 译 器 技 术 的 发 展 已 接 近 于 C++ 健 壮 的 Java 是 健 壮 的 语 言 为 了 更 好 地 理 解 Java 的 健 壮 性, 先 讨 论 一 下 在 传 统 编 程 环 境 下 程 序 设 计 失 败 的 主 要 原 因 : 内 存 管 理 错 误 和 误 操 作 引 起 的 异 常 或 运 行 时 异 常 在 传 统 的 编 程 环 境 下, 内 存 管 理 是 一 项 困 难 乏 味 的 工 作 例 如, 在 C 或 C++ 中, 必 须 手 工 分 配 释 放 所 有 的 动 态 内 存 如 果 忘 记 释 放 原 来 分 配 的 内 存, 或 是 释 放 了 其 他 程 序 正 在 使 用 的 内 存 时, 就 会 出 错 在 传 统 的 编 程 环 境 下, 异 常 情 况 可 能 经 常 由 被 零 除 Null 指 针 操 作 文 件 未 找 到 等 原 因 引 起, 必 须 用 既 繁 琐 又 难 理 解 的 一 大 堆 指 令 来 进 行 管 理 对 此,Java 通 过 自 行 管 理 内 存 分 配 和 释 放, 从 根 本 上 消 除 了 有 关 内 存 的 问 题 Java 提 供 垃 圾 收 集 器, 可 自 动 收 集 闲 置 对 象 占 用 的 内 存 通 过 提 供 面 向 对 象 的 异 常 处 理 机 制 来 解 决 异 常 处 理 的 问 题 通 过 类 型 检 查 Null 指 针 检 测 数 组 边 界 检 测 等 方 法, 在 开 发 早 期 发 现 程 序 错 误 动 态 的 Java 语 言 具 有 动 态 特 性 Java 动 态 特 性 是 其 面 向 对 象 设 计 方 法 的 扩 展, 允 许 程 序 动 态 地 装 入 运 行 过 程 中 所 需 的 类, 这 是 C++ 进 行 面 向 对 象 程 序 设 计 所 无 法 实 现 的 C++ 程 序 设 计 过 程 中, 每 当 在 类 中 增 加 一 个 实 例 变 量 或 一 种 成 员 函 数 后, 引 用 该 类 的 所 有 子 类 都 必 须 重 新 编 译, 否 则 将 导 致 程 序 崩 溃 第 8 页

1.6 构 建 Java 开 发 环 境 我 们 先 来 学 习 构 建 Java 开 发 环 境, 让 大 家 对 Java 有 更 实 际 的 了 解 下 面 以 JDK6.0 在 Windows XP 上 的 安 装 配 置 为 例 来 讲 述 : 1.6.1 第 一 步 : 下 载 JDK 从 SUN 网 站 下 载 JDK6 或 以 上 版 本, 地 址 是 http://java.sun.com/javaee/ downloads/index.jsp, 这 里 以 jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep _2008.exe 版 为 例, 如 下 图 : 1.6.2 第 二 步 : 安 装 JDK (1) 双 击 jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep_2008.exe 文 件, 出 现 如 下 安 装 界 面 : 第 9 页

(2) 然 后 出 现 下 面 的 界 面 (3) 点 击 接 受 按 钮, 然 后 出 现 下 列 界 面 (4) 点 击 界 面 上 的 更 改 按 钮, 可 以 设 置 需 要 安 装 到 的 路 径, 然 后 点 击 下 一 步, 会 进 行 JDK 的 安 装, 请 耐 心 等 待 第 10 页

(5) 直 到 出 现 JRE 的 安 装, 如 下 图 : (6) 可 以 选 择 更 改, 然 后 在 弹 出 的 界 面 选 择 安 装 JRE 的 路 径, 然 后 点 击 确 定 也 可 以 不 更 改 安 装 路 径, 点 击 下 一 步, 出 现 下 面 的 界 面 这 里 介 绍 了 Java 语 言 开 发 的 一 个 Office 软 件, 和 微 软 的 Office 各 有 千 秋, 因 为 是 Java 开 发 的, 大 家 可 以 支 持 一 下, 最 主 要 的 它 是 免 费 的 第 11 页

(7) 直 到 出 现 如 下 界 面, 表 示 安 装 完 成 : (8) 不 想 查 看 产 品 注 册 信 息 的 话, 就 直 接 点 击 完 成 按 钮, 安 装 JDK 就 完 成 了 第 12 页

(9) 安 装 完 成 过 后,JDK 文 件 夹 如 下 图 : C:\Program Files\Java\jdk1.6.0_10: 是 JDK 的 安 装 路 径 bin: 是 binary 的 简 写, 存 放 的 是 Java 的 各 种 可 执 行 文 件, 常 用 的 命 令 有 编 译 器 javac.exe 解 释 器 java.exe 现 的 include: 需 要 引 入 的 一 些 头 文 件, 主 要 是 c 和 c++ 的,JDK 本 身 是 通 过 C 和 C++ 实 jre:java 运 行 环 境 lib: 是 library 的 简 写,JDK 所 需 要 的 一 些 资 源 文 件 和 资 源 包 C:\Program Files\Sun\JavaDB :JDK6 新 加 入 的 Apache 的 Derby 数 据 库, 支 持 JDBC4.0 的 规 范 1.6.3 第 三 步 : 配 置 环 境 变 量 安 装 完 成 后, 还 要 进 行 Java 环 境 的 配 置, 才 能 正 常 使 用, 步 骤 如 下 : (1) 在 我 的 电 脑 点 击 右 键 选 择 属 性, 如 下 图 所 示 : 第 13 页

(2) 在 弹 出 界 面 上 : 选 择 高 级 环 境 变 量, 如 下 图 所 示 : (3) 弹 出 如 下 界 面, 我 们 的 设 置 就 在 这 个 界 面 上 : 第 14 页

(4) 点 击 环 境 变 量 界 面 的 系 统 变 量 栏 的 新 建 按 钮, 弹 出 界 面 如 下 图 : 在 上 面 填 写 变 量 名 为 : JAVA_HOME, 变 量 值 为 : C:\Program Files\Java\jdk1.6.0_10, 如 下 图 所 示 : 点 击 确 定 按 钮 第 15 页

(5) 再 次 点 击 环 境 变 量 界 面 的 系 统 变 量 栏 的 新 建 按 钮 在 弹 出 的 窗 口 中 填 写 变 量 名 为 : classpath, 变 量 值 为 :.;, 注 意 是 点 和 分 号, 如 下 图 所 示 : 点 击 确 定 按 钮 (6) 如 下 图 所 示 : 在 系 统 变 量 里 面 找 到 Path 这 一 项, 然 后 双 击 它, 在 弹 出 的 界 面 上, 在 变 量 值 开 头 添 加 如 下 语 句 %JAVA_HOME%\bin;, 注 意 不 要 忘 了 后 面 的 分 号, 如 下 图 所 示 : 然 后 点 击 编 辑 系 统 变 量 界 面 的 确 定 按 钮 第 16 页

(7) 点 击 环 境 变 量 界 面 的 确 定 按 钮 (8) 点 击 系 统 属 性 界 面 的 确 定 按 钮 Java 开 发 环 境 的 设 置 就 完 成 了 那 么 为 何 要 设 置 这 些 环 境 变 量 呢? JAVA_HOME: 配 置 到 JDK 安 装 路 径 注 意 : 变 量 名 必 须 书 写 正 确, 全 部 大 写, 中 间 用 下 划 线 有 以 下 好 处 : 为 了 方 便 引 用 比 如,JDK 安 装 在 C:\Program Files\Java\jdk1.6.0_10 目 录 里, 则 设 置 JAVA_HOME 为 该 目 录 路 径, 那 么 以 后 要 使 用 这 个 路 径 的 时 候, 只 需 输 入 %JAVA_HOME% 即 可, 避 免 每 次 引 用 都 输 入 很 长 的 路 径 串 归 一 原 则 当 JDK 路 径 被 迫 改 变 的 时 候, 仅 需 更 改 JAVA_HOME 的 变 量 值 即 可, 否 则, 你 就 要 更 改 任 何 用 绝 对 路 径 引 用 JDK 目 录 的 文 档, 要 是 万 一 你 没 有 改 全, 某 个 程 序 找 不 到 JDK, 后 果 是 可 想 而 知 为 第 三 方 软 件 服 务 基 于 Java 的 第 三 方 软 件 会 引 用 约 定 好 的 JAVA_HOME 变 量, 那 么 它 们 能 够 找 到 JDK 的 位 置, 不 然, 将 不 能 正 常 使 用 该 软 件 如 果 某 个 软 件 不 能 正 常 使 用, 不 妨 想 想 是 不 是 这 个 问 题 PATH: 提 供 给 操 作 系 统 寻 找 到 Java 命 令 工 具 的 路 径 通 常 是 配 置 到 JDK 安 装 路 径 \bin 完 成 配 置 以 后, 使 用 编 译 器 和 解 释 器 就 会 很 方 便, 可 以 在 任 何 路 径 下 使 用 bin 目 录 下 的 Java 命 令, 而 不 需 要 写 出 完 整 的 路 径 :C:\Program Files\Java\jdk1.6.0_10 \bin\java CLASSPATH: 提 供 程 序 在 运 行 期 寻 找 所 需 资 源 的 路 径, 比 如 :.class 类 文 件 文 件 图 片 等 等 在 windows 环 境 下 配 置. 代 表 当 前 路 径, 那 么 在 执 行 java 命 令 时, 就 会 先 到 当 前 路 径 寻 找 class 类 文 件 这 个 配 置 对 于 Java 初 学 者 比 较 难 理 解, 我 们 在 后 面 的 Java 运 行 过 程 中, 再 详 细 体 会 的 配 置 注 意 : 在 windows 操 作 系 统 上, 最 好 在 CLASSPATH 的 配 置 里 面, 始 终 在 前 面 保 持.; 通 过 在 windows 窗 口 设 置 环 境 变 量, 可 以 永 久 更 改 系 统 环 境 变 量 也 可 以 在 dos 命 令 行 窗 口, 通 过 dos 命 令 的 方 式 修 改 环 境 变 量, 具 体 命 令 如 下 : set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_10; set path=%java_home%\bin; set classpath=.; 但 通 过 这 种 方 式 修 改 的 环 境 变 量 只 在 当 前 的 dos 命 令 行 窗 口 有 效, 对 于 其 他 的 dos 命 令 行 窗 口 则 无 效 第 17 页

1.6.4 第 四 步 : 检 测 安 装 配 置 是 否 成 功 进 行 完 上 面 的 步 骤, 基 本 的 安 装 和 配 置 就 好 了, 怎 么 知 道 安 装 成 功 没 有 呢? (1) 点 击 开 始 点 击 运 行, 在 弹 出 的 对 话 框 中 输 入 cmd, 如 下 图 示 : (2) 然 后 点 击 确 定, 在 弹 出 的 dos 命 令 行 窗 口 里 面, 输 入 javac, 然 后 回 车, 出 现 如 下 界 面 则 表 示 安 装 配 置 成 功 现 在 Java 的 开 发 环 境 就 配 置 好 了, 如 果 出 现 下 面 的 提 示, 说 明 刚 才 的 环 境 变 量 的 配 置 有 问 题, 需 要 从 头 一 步 一 步 检 查 第 18 页

注 意 : 如 果 更 改 了 系 统 环 境 变 量 的 配 置, 必 须 重 新 打 开 dos 窗 口, 就 是 打 开 一 个 新 的 dos 窗 口, 环 境 变 量 的 新 配 置 才 会 有 效, 否 则,dos 窗 口 就 还 应 用 旧 的 环 境 变 量 的 旧 配 置 有 些 人 已 经 跃 跃 欲 试 的 想 要 马 上 开 始 学 习 如 何 编 写 Java 程 序 了, 下 面 先 来 体 会 第 一 个 Java 程 序 1.7 一 个 基 本 的 Java 应 用 程 序 HelloWorld 像 其 它 编 程 语 言 一 样,Java 编 程 语 言 也 被 用 来 创 建 应 用 程 序 一 个 共 同 的 应 用 程 序 范 例 是 在 屏 幕 上 显 示 字 串 Hello World! 下 列 代 码 给 出 了 这 个 Java 应 用 程 序 如 果 是 第 一 次 看 到 Java 代 码, 可 能 都 不 明 白 每 一 个 代 码 的 意 义, 没 有 关 系, 主 要 是 来 体 会 一 下 Java 程 序 是 什 么 样 子, 在 脑 海 里 有 个 印 象, 然 后 可 以 先 模 仿 着 做 1.7.1 HelloWorld 1.// 这 里 是 注 释 2.// HelloWorld 应 用 示 例 3.// 4.public class HelloWorld{ 5. public static void main (String args[]){ 6. System.out.println(" 你 好, 欢 迎 来 到 Java 快 车!"); 7. 8. 以 上 程 序 行 是 在 dos 窗 口 上 打 印 你 好, 欢 迎 来 到 Java 快 车! 所 需 的 最 少 组 件 1.7.2 描 述 HelloWorld 1.// 这 里 是 注 释 2.// HelloWorld 应 用 示 例 3.// 程 序 中 的 1-3 行 是 注 释 行 第 19 页

4. public class HelloWorld{ 第 4 行 声 明 类 名 为 HelloWorld 类 名 (ClassName) 是 在 源 文 件 中 指 明 的, 它 可 在 与 源 代 码 相 同 的 目 录 上 创 建 一 个 ClassName.class 文 件 在 本 例 题 中, 编 译 器 创 建 了 一 个 称 为 HelloWorld.class 的 文 件, 它 包 含 了 公 共 类 HelloWorld 的 编 译 代 码 5. public static void main (String args[]){ 第 5 行 是 程 序 执 行 的 起 始 点 ( 入 口 ) Java 解 释 器 必 须 发 现 这 一 严 格 定 义 的 点, 否 则 将 拒 绝 运 行 程 序 其 它 程 序 语 言 ( 特 别 是 C 和 C++) 也 采 用 main() 声 明 作 为 程 序 执 行 的 起 始 点 此 声 明 的 不 同 部 分 将 在 本 课 程 的 后 几 部 分 介 绍 如 果 在 程 序 的 命 令 行 中 给 出 了 任 何 自 变 量 ( 命 令 行 参 数 ), 它 们 将 被 传 递 给 main() 方 法 中 被 称 作 args 的 String 数 组 在 本 例 题 中, 未 使 用 自 变 量 public 说 明 方 法 main() 可 被 任 何 程 序 访 问, 包 括 Java 解 释 器 static 是 一 个 告 知 编 译 器 main() 是 用 于 类 HelloWorldApp 中 的 方 法 的 关 键 字 为 使 main() 在 程 序 做 其 它 事 之 前 就 开 始 运 行, 这 一 关 键 字 是 必 要 的 void 表 明 main() 不 返 回 任 何 信 息 这 一 点 是 重 要 的, 因 为 Java 编 程 语 言 要 进 行 谨 慎 的 类 型 检 查, 包 括 检 查 调 用 的 方 法 确 实 返 回 了 这 些 方 法 所 声 明 的 类 型 String args[] 是 一 个 字 符 串 类 型 的 数 组 声 明, 它 是 main 方 法 的 参 数, 它 将 包 含 位 于 类 名 之 后 的 命 令 行 中 的 自 变 量 Java HelloWorld args[0] args[1] { 两 个 大 括 号 一 起 中 间 的 内 容 叫 方 法 体, 代 表 这 个 方 法 所 执 行 的 代 码 6. System.out.println (" 你 好, 欢 迎 来 到 Java 快 车!" ); 第 6 行 声 明 如 何 使 用 类 名 对 象 名 和 方 法 调 用 它 使 用 由 System 类 的 out 成 员 引 用 的 PrintStream 对 象 的 println () 方 法, 将 字 串 你 好, 欢 迎 来 到 Java 快 车! 打 印 到 标 准 输 出 上 在 这 个 例 子 中,println() 方 法 被 输 入 了 一 个 字 串 自 变 量 并 将 其 写 在 了 标 准 输 出 流 上 7. 8. 本 程 序 的 7-8 行 分 别 是 方 法 main() 和 类 HelloWorld 的 下 括 号 1.7.3 编 译 并 运 行 HelloWorld 编 译 当 你 创 建 了 HelloWorld.java 源 文 件 后, 用 下 列 命 令 行 进 行 编 译 : 第 20 页

javac HelloWorld.java 如 果 编 译 器 未 返 回 任 何 提 示 信 息, 表 示 编 译 完 成, 生 成 一 个 新 文 件 HelloWorld. class, 该 文 件 称 为 字 节 码 文 件,class 文 件 名 和 对 应 的 java 文 件 名 是 相 同 的 class 文 件 被 存 储 在 与 源 文 件 相 同 的 目 录 中, 除 非 另 有 指 定 如 果 在 编 译 中 遇 到 问 题, 请 参 阅 本 模 块 的 查 错 提 示 信 息 部 分 运 行 序 : 为 运 行 你 的 HelloWorld 应 用 程 序, 需 使 用 Java 解 释 器 和 位 于 bin 目 录 下 的 java 程 java HelloWorld 你 好, 欢 迎 来 到 Java 快 车! 1.7.4 编 译 查 错 以 下 是 编 译 时 的 常 见 错 误 : --javac:command not found PATH 变 量 未 正 确 设 置 以 包 括 javac 编 译 器 javac 编 译 器 位 于 JDK 目 录 下 的 bin 目 录 --HelloWorld.java:6: Method printl(java.lang.string) not found in class java.io.printstream.system. out.printl (" 你 好, 欢 迎 来 到 Java 快 车!"); 方 法 名 是 println 而 不 是 printl, 少 敲 了 一 个 n --In class HelloWorld:main must be public or static 该 错 误 的 出 现 是 因 为 main 方 法 没 有 static 或 public 修 饰 符 以 下 是 运 行 时 的 错 误 : --can t find class HelloWorld ( 这 个 错 误 是 在 控 制 台 敲 入 java HelloWorld 时 产 生 的 ) 通 常, 它 表 示 在 命 令 行 中 所 指 定 的 类 名 的 拼 写 与 filename.class 文 件 的 拼 写 不 同 Java 编 程 语 言 是 一 种 大 小 写 区 别 对 待 的 语 言 例 如 : public class Helloworld 创 建 了 一 个 Helloworld.class, 它 不 是 编 译 器 所 预 期 的 类 名 (HelloWorld.class) -- 命 名 如 果.java 文 件 包 括 一 个 公 共 类, 那 么 它 必 须 使 用 与 那 个 公 共 类 相 同 的 文 件 名 例 如 在 前 例 中 的 类 的 定 义 是 public class Helloworld 源 文 件 名 则 必 须 是 Helloworld.java 第 21 页

-- 类 的 数 量 在 源 文 件 中 每 次 只 能 定 义 一 个 公 共 类 1.8 Java 的 运 行 过 程 用 一 个 图 来 描 述 这 个 过 程 会 比 较 容 易 理 解 : 编 写 代 码 首 先 把 我 们 想 要 计 算 机 做 的 事 情, 通 过 Java 表 达 出 来, 写 成 Java 文 件, 这 个 过 程 就 是 编 写 代 码 的 过 程 如 上 图 所 示 的 Hello.java 文 件 编 译 写 完 Java 代 码 后, 机 器 并 不 认 识 我 们 写 的 Java 代 码, 需 要 进 行 编 译 成 为 字 节 码, 编 译 后 的 文 件 叫 做 class 文 件 如 上 图 所 示 的 Hello.class 文 件 类 装 载 ClassLoader 类 装 载 的 功 能 是 为 执 行 程 序 寻 找 和 装 载 所 需 要 的 类 ClassLoader 能 够 加 强 代 码 的 安 全 性, 主 要 方 式 是 : 把 本 机 上 的 类 和 网 络 资 源 类 相 分 离, 在 调 入 类 的 时 候 进 行 检 查, 因 而 可 以 限 制 任 何 特 洛 伊 木 马 的 应 用 字 节 码 (byte-code) 校 验 字 节 码 校 验 的 功 能 是 对 class 文 件 的 代 码 进 行 校 验, 保 证 代 码 的 安 全 性 Java 软 件 代 码 在 实 际 运 行 之 前 要 经 过 几 次 测 试 JVM 将 代 码 输 入 一 个 字 节 码 校 验 器 以 测 试 代 码 段 格 式 并 进 行 规 则 检 查 -- 检 查 伪 造 指 针 违 反 对 象 访 问 权 限 或 试 图 改 变 对 象 类 型 的 非 法 代 码 第 22 页

字 节 码 校 验 器 对 程 序 代 码 进 行 四 遍 校 验, 这 可 以 保 证 代 码 符 合 JVM 规 范 并 且 不 破 坏 系 统 的 完 整 性 如 果 校 验 器 在 完 成 四 遍 校 验 后 未 返 回 出 错 信 息, 则 下 列 各 点 可 被 保 证 : - 类 符 合 JVM 规 范 的 类 文 件 格 式 - 无 访 问 限 制 异 常 - 代 码 未 引 起 操 作 数 栈 上 溢 或 下 溢 - 所 有 操 作 代 码 的 参 数 类 型 将 总 是 正 确 的 - 无 非 法 数 据 转 换 发 生, 如 将 整 数 转 换 为 对 象 引 用 - 对 象 域 访 问 是 合 法 的 解 释 可 是 机 器 也 不 能 认 识 class 文 件, 还 需 要 被 解 释 器 进 行 解 释, 解 释 成 机 器 码, 计 算 机 的 处 理 器 才 能 最 终 理 解 Java 程 序 员 所 要 表 达 的 指 令 运 行 最 后 由 运 行 环 境 中 的 Runtime 对 指 令 进 行 运 行, 真 正 实 现 我 们 想 要 机 器 完 成 的 工 作 说 明 由 上 面 的 讲 述, 大 家 看 到,Java 通 过 一 个 编 译 阶 段 和 一 个 运 行 阶 段, 来 让 机 器 最 终 理 解 我 们 想 要 它 完 成 的 工 作, 并 按 照 我 们 的 要 求 进 行 运 行 在 这 两 个 阶 段 中, 需 要 我 们 去 完 成 的 就 是 编 译 阶 段 的 工 作, 也 就 是 说 : 我 们 需 要 把 我 们 想 要 机 器 完 成 的 工 作 用 Java 语 言 表 达 出 来, 写 成 Java 源 文 件, 然 后 把 源 文 件 进 行 编 译, 形 成 class 文 件, 最 后 就 可 以 在 Java 运 行 环 境 中 运 行 了 运 行 阶 段 的 工 作 由 Java 平 台 自 身 提 供, 我 们 不 需 要 做 什 么 工 作 1.9 Java 技 术 三 大 特 性 1.9.1 虚 拟 机 Java 虚 拟 机 JVM(Java Virtual Machine) 在 Java 编 程 里 面 具 有 非 常 重 要 的 地 位, 相 当 于 前 面 学 到 的 Java 运 行 环 境, 虚 拟 机 的 基 本 功 能 如 下 : (1) 通 过 ClassLoader 寻 找 和 装 载 class 文 件 (2) 解 释 字 节 码 成 为 指 令 并 执 行, 提 供 class 文 件 的 运 行 环 境 (3) 进 行 运 行 期 间 垃 圾 回 收 (4) 提 供 与 硬 件 交 互 的 平 台 Java 虚 拟 机 是 在 真 实 机 器 中 用 软 件 模 拟 实 现 的 一 种 想 象 机 器 Java 虚 拟 机 代 码 被 存 储 在.class 文 件 中 ; 每 个 文 件 都 包 含 最 多 一 个 public 类 Java 虚 拟 机 规 范 为 不 同 的 硬 件 平 台 提 供 了 一 种 编 译 Java 技 术 代 码 的 规 范, 该 规 范 使 Java 软 件 独 立 于 平 台, 因 为 编 译 是 针 对 作 为 虚 拟 机 的 一 般 机 器 而 做 这 个 一 般 机 器 可 用 软 件 模 拟 并 运 行 于 各 种 现 存 的 计 算 机 系 统, 第 23 页

也 可 用 硬 件 来 实 现 编 译 器 在 获 取 Java 应 用 程 序 的 源 代 码 后, 将 其 生 成 字 节 码, 它 是 为 JVM 生 成 的 一 种 机 器 码 指 令 每 个 Java 解 释 器, 不 管 它 是 Java 技 术 开 发 工 具, 还 是 可 运 行 applets 的 Web 浏 览 器, 都 可 执 行 JVM JVM 为 下 列 各 项 做 出 了 定 义 : - 指 令 集 ( 相 当 于 中 央 处 理 器 [CPU]) - 寄 存 器 - 类 文 件 格 式 - 栈 - 垃 圾 收 集 堆 - 存 储 区 JVM 的 代 码 格 式 由 紧 缩 有 效 的 字 节 码 构 成 由 JVM 字 节 码 编 写 的 程 序 必 须 保 持 适 当 的 类 型 约 束 大 部 分 类 型 检 查 是 在 编 译 时 完 成 任 何 从 属 的 Java 技 术 解 释 器 必 须 能 够 运 行 任 何 含 有 类 文 件 的 程 序, 这 些 类 文 件 应 符 合 Java 虚 拟 机 规 范 中 所 指 定 的 类 文 件 格 式 虚 拟 机 是 Java 平 台 无 关 的 保 障 正 是 因 为 有 虚 拟 机 这 个 中 间 层,Java 才 能 够 实 现 与 平 台 无 关 虚 拟 机 就 好 比 是 一 个 Java 运 行 的 基 本 平 台, 所 有 的 Java 程 序 都 运 行 在 虚 拟 机 上, 如 下 图 所 示 : Java 源 程 序 (*.java 文 件 ) javac 编 译 Java 类 文 件 (*.class 文 件 ) 平 台 无 关 被 装 载 进 虚 拟 机 Java 虚 拟 机 相 关 平 台 Linux Windows Unix 1.9.2 垃 圾 回 收 什 么 是 垃 圾 在 程 序 运 行 的 过 程 中, 存 在 被 分 配 了 的 内 存 块 不 再 被 需 要 的 情 况, 那 么 这 些 内 存 块 对 程 序 来 讲 就 是 垃 圾 第 24 页

产 生 了 垃 圾, 自 然 就 需 要 清 理 这 些 垃 圾, 更 为 重 要 的 是 需 要 把 这 些 垃 圾 所 占 用 的 内 存 资 源, 回 收 回 来, 加 以 再 利 用, 从 而 节 省 资 源, 提 高 系 统 性 能 垃 圾 回 收 - 不 再 需 要 的 已 分 配 内 存 应 取 消 分 配 ( 释 放 内 存 ) - 在 其 它 语 言 中, 取 消 分 配 是 程 序 员 的 责 任 - Java 编 程 语 言 提 供 了 一 种 系 统 级 线 程 以 跟 踪 内 存 分 配 : 垃 圾 收 集 机 制 - 可 检 查 和 释 放 不 再 需 要 的 内 存 - 可 自 动 完 成 上 述 工 作 许 多 编 程 语 言 都 允 许 在 程 序 运 行 时 动 态 分 配 内 存, 分 配 内 存 的 过 程 由 于 语 言 句 法 不 同 而 有 所 变 化, 但 总 是 要 将 指 针 返 回 到 内 存 的 起 始 位 置, 当 分 配 内 存 不 再 需 要 时 ( 内 存 指 针 已 溢 出 范 围 ), 程 序 或 运 行 环 境 应 释 放 内 存 在 C,C++ 或 其 它 语 言 中, 程 序 员 负 责 释 放 内 存 有 时, 这 是 一 件 很 困 难 的 事 情 因 为 你 并 不 总 是 事 先 知 道 内 存 应 在 何 时 被 释 放 当 在 系 统 中 没 有 能 够 被 分 配 的 内 存 时, 可 导 致 程 序 瘫 痪, 这 种 问 题 被 称 作 内 存 漏 洞 Java 编 程 语 言 解 除 了 程 序 员 释 放 内 存 的 责 任 它 可 提 供 一 种 系 统 级 线 程 以 跟 踪 每 一 次 内 存 的 分 配 情 况 在 Java 虚 拟 机 的 空 闲 周 期, 垃 圾 收 集 线 程 检 查 并 释 放 那 些 可 被 释 放 的 内 存 垃 圾 收 集 在 Java 技 术 程 序 的 生 命 周 期 中 自 动 进 行, 它 解 除 了 释 放 内 存 的 要 求, 这 样 能 够 有 效 避 免 内 存 漏 洞 和 内 存 泄 露 ( 内 存 泄 露 就 是 程 序 运 行 期 间, 所 占 用 的 内 存 一 直 往 上 涨, 很 容 易 造 成 系 统 资 源 耗 尽 而 降 低 性 能 或 崩 溃 ) 提 示 (1) 在 Java 里 面, 垃 圾 回 收 是 一 个 自 动 的 系 统 行 为, 程 序 员 不 需 要 控 制 垃 圾 回 收 的 功 能 和 行 为 比 如 垃 圾 回 收 什 么 时 候 开 始, 什 么 时 候 结 束, 还 有 到 底 哪 些 资 源 需 要 回 收 等 (2) 程 序 员 可 以 通 过 设 置 对 象 为 null( 后 面 会 讲 到 ) 来 标 示 某 个 对 象 不 再 被 需 要 了, 这 只 是 表 示 这 个 对 象 可 以 被 回 收 了, 并 不 是 马 上 被 回 收 (3) 有 一 些 跟 垃 圾 回 收 相 关 的 方 法, 比 如 :System.gc(), 调 用 gc 方 法 暗 示 着 Java 虚 拟 机 做 了 一 些 努 力 来 回 收 未 用 对 象, 以 便 能 够 快 速 地 重 用 这 些 对 象 当 前 占 用 的 内 存 当 控 制 权 从 方 法 调 用 中 返 回 时, 虚 拟 机 已 经 尽 最 大 努 力 从 所 有 丢 弃 的 对 象 中 回 收 了 空 间 1.9.3 代 码 安 全 Java 如 何 保 证 编 写 的 代 码 是 安 全 可 靠 的 呢? 第 一 关 : 编 写 的 代 码 首 先 要 被 编 译 成 为 class 文 件, 如 果 代 码 写 得 有 问 题, 编 译 期 间 就 会 发 现, 然 后 提 示 有 编 译 错 误, 无 法 编 译 通 过 第 25 页

第 二 关 : 通 过 编 译 关 后, 在 类 装 载 的 时 候, 还 会 进 行 类 装 载 检 查, 把 本 机 上 的 类 和 网 络 资 源 类 相 分 离, 在 调 入 类 的 时 候 进 行 检 查, 因 而 可 以 限 制 任 何 特 洛 伊 木 马 的 应 用 第 三 关 : 类 装 载 后, 在 运 行 前, 还 会 进 行 字 节 码 校 验, 以 判 断 你 的 程 序 是 安 全 的 第 四 关 : 如 果 你 的 程 序 在 网 络 上 运 行, 还 有 沙 箱 (Sand Box) 的 保 护, 什 么 是 沙 箱 呢? 就 是 如 果 你 的 程 序 没 有 获 得 授 权, 只 能 在 沙 箱 限 定 的 范 围 内 运 行, 是 不 能 够 访 问 本 地 资 源 的, 从 而 保 证 安 全 性 如 下 图 所 示 : 学 习 到 这 里, 大 家 应 该 对 Java 有 了 一 定 的 了 解 了 Java 的 内 容 很 丰 富, 对 于 初 学 者 来 说, 不 可 能 一 次 性 将 所 有 看 到 的 知 识 点 理 解 透 彻 在 学 习 完 第 二 章 后, 对 第 一 章 的 理 解 就 深 入 一 层 ; 学 习 完 第 三 章 后, 对 第 一 章 和 第 二 章 的 理 解 就 又 深 入 一 层 ; 直 到 学 习 完 第 八 章 后, 对 整 个 Java 基 础 才 会 有 比 较 全 面 的 了 解, 所 以 这 并 不 是 一 步 一 个 脚 印 的 学 习 过 程, 而 是 一 个 循 序 渐 进 不 断 加 深 的 学 习 过 程, 需 要 同 学 们 反 复 揣 摩, 体 会 Java 的 思 想 第 26 页

1.10 学 习 目 标 学 习 目 标 中 标 注 的 知 识 点 十 分 详 细, 非 常 适 合 初 学 者, 能 帮 助 初 学 者 打 好 坚 实 的 Java 基 础 按 照 学 习 目 标 复 习, 避 免 漏 掉 知 识 点 对 于 标 注 理 解 的, 表 示 能 够 描 述 知 识 点, 就 是 能 对 别 人 讲 解, 能 说 出 相 关 原 因 或 现 象 1. 了 解 Java 语 言 是 什 么 ( 从 四 种 不 同 的 角 度 理 解 Java 语 言 ) 2. 了 解 Java 能 干 什 么 3. 了 解 Java 分 哪 三 个 版 本, 分 别 擅 长 哪 方 面 的 开 发 4. 熟 悉 如 何 构 建 Java 的 开 发 环 境 5. 掌 握 如 何 配 置 环 境 变 量 为 什 么 配 置 这 些 环 境 变 量 6. 掌 握 简 述 开 发 HelloWorld 的 步 骤 7. 能 够 描 述 HelloWorld 的 组 成 部 分 及 中 文 解 释 8. 总 结 在 开 发 HelloWorld 程 序 时 遇 到 的 编 译 错 误 和 运 行 异 常, 并 在 笔 记 中 记 录 下 来 9. 能 够 描 述 Java 程 序 的 运 行 过 程 10. 能 够 描 述 Java 虚 拟 机 的 功 能 11. 能 够 描 述 垃 圾 回 收 机 制 12. 能 够 描 述 Java 代 码 的 安 全 性 第 27 页

1.11 练 习 1. 简 述 Java 从 代 码 到 运 行 的 全 过 程 2. 简 述 虚 拟 机 的 工 作 机 制 3. 简 述 Java 的 垃 圾 回 收 机 制 4. 简 述 path classpath JAVA_HOME 各 自 的 含 义 和 配 置 方 式 5. 简 述 软 件 开 发 基 本 步 骤 6. 设 计 一 个 最 简 单 的 输 出 程 序, 要 求 在 屏 幕 上 输 出 以 下 结 果 : 在 Java 快 车 学 习 Java 是 一 个 很 轻 松 的 事 我 很 喜 欢 Java 7. 写 四 个 程 序, 分 别 打 印 一 个 矩 形 一 个 椭 圆 一 个 箭 头 以 及 一 个 菱 形, 如 下 所 示 : 8. 用 8 个 输 出 语 句 显 示 一 个 棋 盘 图 案, 如 下 所 示 : 9. 写 一 个 程 序 计 算 从 0 到 10 的 数 字 的 平 方 和 立 方, 并 按 如 下 格 式 打 印 出 来 : 第 28 页

2 基 础 语 法 我 们 在 学 习 汉 语 的 时 候, 开 始 学 的 是 一 些 单 个 的 字, 只 有 认 识 了 单 个 的 字, 然 后 才 能 组 成 词, 然 后 才 能 慢 慢 的 到 句 子, 然 后 到 文 章 学 习 计 算 机 语 言 跟 这 个 过 程 是 一 样 的, 首 先 我 们 要 学 习 一 些 计 算 机 看 得 懂 的 单 个 的 字, 然 后 写 成 一 句 代 码, 最 后 很 多 句 代 码 组 成 程 序 那 么 这 些 单 个 字 在 Java 里 面 就 是 关 键 字, 让 我 们 的 Java 语 法 学 习 从 关 键 字 开 始 吧 2.1 关 键 字 2.1.1 什 么 是 关 键 字 名 关 键 字 对 Java 技 术 编 译 器 有 特 殊 的 含 义, 它 们 可 标 识 数 据 类 型 名 或 程 序 构 造 (construct) 其 实 就 是 个 约 定 或 者 规 定, 比 如 我 们 看 到 红 灯 就 知 道 要 停 下 来, 看 到 绿 灯 就 可 以 前 进 了 这 些 都 是 人 类 约 定 好 的 游 戏 规 则, 在 我 们 的 日 常 生 活 中 有 特 殊 的 意 义, 不 可 改 变, 违 反 它 就 要 付 出 代 价 关 键 字 是 Java 语 言 和 Java 的 开 发 和 运 行 平 台 之 间 的 约 定, 程 序 员 只 要 按 照 这 个 约 定 使 用 了 某 个 关 键 字,Java 的 开 发 和 运 行 平 台 就 能 够 认 识 它, 并 正 确 地 处 理, 展 示 出 程 序 员 想 要 的 效 果 2.1.2 Java 中 的 关 键 字 abstract assert boolean break byte case catch char class continue default do double else enum extends while final finally float for if implements import instanceof int interface long native new void package private protected public return short static super switch synchronized this throw throws transient volatile try strictfp abstract: 表 明 类 或 类 中 的 方 法 是 抽 象 的 ; assert: 声 明 断 言 ; boolean: 基 本 数 据 类 型 之 一, 布 尔 类 型 ; break: 提 前 跳 出 一 个 块 ; byte: 基 本 数 据 类 型 之 一, 字 节 类 型 ; case: 在 switch 语 句 中, 表 明 其 中 的 一 个 分 支 ; catch: 用 于 处 理 例 外 情 况, 用 来 捕 捉 异 常 ; 第 29 页

char: 基 本 数 据 类 型 之 一, 字 符 类 型 ; class: 类 ; continue: 回 到 一 个 块 的 开 始 处 ; default: 用 在 switch 语 句 中, 表 明 一 个 默 认 的 分 支 ; do: 用 在 "do while" 循 环 结 构 中 ; double: 基 本 数 据 类 型 之 一, 双 精 度 浮 点 数 类 型 ; else: 在 条 件 语 句 中, 表 明 当 条 件 不 成 立 时 的 分 支 ; extends: 用 来 表 明 一 个 类 是 另 一 个 类 的 子 类 ; final: 用 来 表 明 一 个 类 不 能 派 生 出 子 类, 或 类 中 的 方 法 不 能 被 覆 盖, 或 声 明 一 个 变 量 是 常 量 ; finally: 用 于 处 理 异 常 情 况, 用 来 声 明 一 个 肯 定 会 被 执 行 到 的 块 ; float: 基 本 数 据 类 型 之 一, 单 精 度 浮 点 数 类 型 ; for: 一 种 循 环 结 构 的 引 导 词 ; if: 条 件 语 句 的 引 导 词 ; implements: 表 明 一 个 类 实 现 了 给 定 的 接 口 ; import: 表 明 要 访 问 指 定 的 类 或 包 ; instanceof: 用 来 测 试 一 个 对 象 是 否 是 一 个 指 定 类 的 实 例 ; int: 基 本 数 据 类 型 之 一, 整 数 类 型 ; interface: 接 口 ; long: 基 本 数 据 类 型 之 一, 长 整 数 类 型 ; native: 用 来 声 明 一 个 方 法 是 由 与 机 器 相 关 的 语 言 ( 如 C/C++/FORTRAN 语 言 ) 实 现 的 ; new: 用 来 申 请 新 对 象 ; package: 包 ; private: 一 种 访 问 方 式 : 私 有 模 式 ; protected: 一 种 访 问 方 式 : 保 护 模 式 ; public: 一 种 访 问 方 式 : 公 共 模 式 ; return: 从 方 法 中 返 回 值 ; short: 基 本 数 据 类 型 之 一, 短 整 数 类 型 ; static: 表 明 域 或 方 法 是 静 态 的, 即 该 域 或 方 法 是 属 于 类 的 ; strictfp: 用 来 声 明 FP-strict( 双 精 度 或 单 精 度 浮 点 数 ) 表 达 式, 参 见 IEEE 754 算 术 规 范 ; super: 当 前 对 象 的 父 类 对 象 的 引 用 ; switch: 分 支 结 构 的 引 导 词 ; synchronized: 表 明 一 段 代 码 的 执 行 需 要 同 步 ; this: 当 前 对 象 的 引 用 ; throw: 抛 出 一 个 异 常 ; throws: 声 明 方 法 中 抛 出 的 所 有 异 常 ; transient: 声 明 不 用 序 列 化 的 域 ; try: 尝 试 一 个 可 能 抛 出 异 常 的 程 序 块 void: 表 明 方 法 不 返 回 值 ; volatile: 表 明 两 个 或 多 个 变 量 必 须 同 步 地 发 生 变 化 ; while: 用 在 循 环 结 构 中 ; enum: 声 明 枚 举 类 型 ; 第 30 页

说 明 : 1. 这 些 关 键 字 的 具 体 含 义 和 使 用 方 法, 会 在 后 面 使 用 的 时 候 详 细 讲 述 2. Java 的 关 键 字 也 是 随 新 的 版 本 发 布 在 不 断 变 动 中 的, 不 是 一 成 不 变 的 3. 所 有 关 键 字 都 是 小 写 的 2.2 标 识 符 每 个 人 都 有 名 字, 每 个 事 物 也 都 有 名 字, 有 了 名 字, 就 可 以 通 过 语 言 表 示 出 来 Java 的 文 件 类 方 法 变 量 也 都 有 名 字 中 国 人 的 名 字 有 默 认 的 命 名 规 则, 比 如 不 使 用 阿 拉 伯 数 字, 不 使 用 标 点 符 号, 不 使 用 长 辈 的 名 字, 等 等 Java 中 有 什 么 命 名 规 则 呢? 2.2.1 什 么 是 标 识 符 在 Java 编 程 语 言 中, 标 识 符 是 标 识 变 量 类 或 方 法 的 有 效 字 符 序 列 简 单 地 说 标 识 符 就 是 一 个 名 字 2.2.2 标 识 符 命 名 规 则 命 名 规 则 如 下 : (1) 首 字 母 只 能 以 字 母 下 划 线 $ 开 头, 其 后 可 以 跟 字 母 下 划 线 $ 和 数 字 示 例 :$abc _ab ab123 等 都 是 有 效 的 (2) 标 识 符 不 能 是 关 键 字 (3) 标 识 符 区 分 大 小 写 ( 事 实 上 整 个 Java 编 程 里 面 都 是 区 分 大 小 写 的 ) Girl 和 girl 是 两 个 不 同 的 标 识 符 (4) 标 识 符 长 度 没 有 限 制, 但 不 宜 过 长 (5) 如 果 标 识 符 由 多 个 单 词 构 成, 那 么 从 第 二 个 单 词 开 始, 首 字 母 大 写 示 例 :getuser setmodel EmployeeModel 等 (6) 标 识 符 尽 量 命 名 的 有 意 义, 让 人 能 够 望 文 知 意 (7) 尽 量 少 用 带 $ 符 号 的 标 识 符, 主 要 是 习 惯 问 题, 大 家 都 不 是 很 习 惯 使 用 带 $ 符 号 的 标 识 符 ; 还 有 内 部 类 中,$ 具 有 特 殊 的 含 义 (8) 虽 然 Java 语 言 使 用 16-bit 双 字 节 字 符 编 码 标 准 (Unicode 字 符 集 ), 最 多 可 以 识 别 65536 个 字 符 (0-65535) 建 议 标 识 符 中 最 好 使 用 ASCII 字 母 虽 然 中 文 标 识 符 也 能 够 正 常 编 译 和 运 行, 却 不 建 议 使 用 public class Test { public static void main(string[] args) { String Java 快 车 = " 中 文 标 识 符 测 试 "; System.out.println("Java 快 车 ==" + Java 快 车 ); 运 行 结 果 :Java 快 车 == 中 文 标 识 符 测 试 第 31 页

2.2.3 示 例 下 列 哪 些 是 正 确 的 标 识 符 : my Variable 9javakc a+b book1-2-3 java&c It's 错 误 的 标 识 符 及 其 原 因 分 析 如 下 : My Variable // 含 有 空 格 9javakc // 首 字 符 为 数 字 a+b // 加 号 不 是 字 母 book1-2-3 // 减 号 不 是 字 母 java&c // 与 号 不 是 字 母 It's // 单 引 号 不 是 字 母 2.3 数 据 类 型 2.3.1 什 么 叫 数 据 类 型 数 据 类 型 简 单 的 说 就 是 对 数 据 的 分 类, 对 数 据 各 自 的 特 点 进 行 类 别 的 划 分, 划 分 的 每 种 数 据 类 型 都 具 有 区 别 于 其 它 类 型 的 特 征, 每 一 类 数 据 都 有 相 应 的 特 点 和 操 作 功 能 例 如 数 字 类 型 的 就 能 够 进 行 加 减 乘 除 的 操 作 在 现 实 生 活 中, 我 们 通 常 会 针 对 不 同 的 提 问, 做 出 不 同 类 型 的 回 答, 比 如 : 你 叫 什 么 名 字? -- 刘 德 华 你 今 天 多 大 年 纪 了? --24 你 家 住 哪 里? -- 北 京 市 海 淀 区 上 地 信 息 路 请 告 诉 我, 你 的 身 高? --1.75 你 带 课 本 了, 是 吗? -- 是 的 1+1=2, 对 吗? -- 对 笑 话? 大 家 仔 细 分 析 一 下 回 答 的 信 息 ( 数 据 ), 是 不 是 有 类 别 之 分? 如 果 类 别 搞 错 了, 是 不 是 会 出 类 似 的 在 程 序 中, 计 算 机 也 需 要 某 种 方 式 来 判 断 某 个 数 字 是 什 么 类 型 的 这 通 常 是 需 要 程 序 员 显 示 来 声 明 某 个 数 据 是 什 么 类 型 的,Java 就 是 这 样 的 Java 是 一 种 强 类 型 的 语 言, 凡 是 使 用 到 的 变 量, 在 编 译 之 前 一 定 要 被 显 示 的 声 明 第 32 页

Java 的 安 全 和 健 壮 性 部 分 来 自 于 它 是 强 类 型 语 言 这 一 事 实 首 先, 每 个 变 量 有 类 型, 每 个 表 达 式 有 类 型, 而 且 每 种 类 型 是 严 格 定 义 的 其 次, 所 有 的 数 值 传 递, 不 管 是 直 接 的 还 是 通 过 方 法 调 用 经 由 参 数 传 过 去 的 都 要 先 进 行 类 型 相 容 性 的 检 查 有 些 语 言 没 有 自 动 强 迫 进 行 数 据 类 型 相 容 性 的 检 查 或 对 冲 突 的 类 型 进 行 转 换 的 机 制 Java 编 译 器 对 所 有 的 表 达 式 和 参 数 都 要 进 行 类 型 相 容 性 的 检 查 以 保 证 类 型 是 兼 容 的 任 何 类 型 的 不 匹 配 都 是 错 误 的, 在 编 译 器 完 成 编 译 以 前, 错 误 必 须 被 改 正 2.3.2 Java 数 据 类 型 的 分 类 Java 里 面 的 数 据 类 型 从 大 的 方 面 分 为 两 类, 一 是 基 本 数 据 类 型, 一 是 引 用 类 型 基 本 的 JAVA 数 据 类 型 层 次 图 如 下 : 布 尔 类 型 (boolean) 字 符 型 (char) 基 本 数 据 类 型 定 点 类 型 字 节 型 (byte) 短 整 型 (short) 整 型 (int) 数 据 类 型 数 值 类 型 浮 点 类 型 长 整 型 (long) 单 精 度 (float) 双 精 度 (double) 引 用 数 据 类 型 数 组 接 口 类 2.3.3 Java 中 的 基 本 数 据 类 型 Java 中 的 基 本 数 据 类 型 可 分 为 四 种 : (1) 逻 辑 型 :boolean (2) 文 本 型 :char (3) 整 数 型 :byte short int long (4) 浮 点 型 :float double 第 33 页

2.3.3.1 逻 辑 型 boolean 逻 辑 值 有 两 种 状 态, 即 人 们 经 常 使 用 的 on 和 off 或 true 和 false 或 yes 和 no, 这 样 的 值 是 用 boolean 类 型 来 表 示 的 boolean 有 两 个 文 字 值, 即 true 和 false 以 下 是 一 个 有 关 boolean 类 型 变 量 的 声 明 和 初 始 化 : boolean truth = true; // 声 明 变 量 truth 注 意 : 在 整 数 类 型 和 boolean 类 型 之 间 无 转 换 计 算 有 些 语 言 ( 特 别 值 得 强 调 的 是 C 和 C++) 允 许 将 数 字 值 转 换 成 逻 辑 值 ( 所 谓 非 零 即 真 ), 这 在 Java 编 程 语 言 中 是 不 允 许 的 ; boolean 类 型 只 允 许 使 用 boolean 值 (true 或 false) true 和 false 不 是 关 键 字 2.3.3.2 文 本 型 char char 类 型 用 来 表 示 单 个 字 符 一 个 char 代 表 一 个 16-bit 无 符 号 的 ( 不 分 正 负 的 ) Unicode 字 符, 一 个 char 字 符 必 须 包 含 在 单 引 号 内 示 例 : 'a' // 表 示 简 单 的 字 符 '1' // 用 数 字 也 可 以 表 示 字 符 下 面 就 错 了, 只 能 使 用 单 个 字 符 'ab' // 错 误 '12' // 错 误 什 么 是 Unicode 编 码 Unicode 编 码 又 叫 统 一 码 万 国 码 或 单 一 码, 是 一 种 在 计 算 机 上 使 用 的 字 符 编 码 它 为 每 种 语 言 中 的 每 个 字 符 设 定 了 统 一 并 且 唯 一 的 二 进 制 编 码, 以 满 足 跨 语 言 跨 平 台 进 行 文 本 转 换 处 理 的 要 求 1990 年 开 始 研 发,1994 年 正 式 公 布 随 着 计 算 机 工 作 能 力 的 增 强,Unicode 也 在 面 世 以 来 的 十 多 年 里 得 到 普 及 Unicode 字 符 集 最 多 可 以 识 别 65535 个 字 符, 每 个 国 建 的 字 母 表 的 字 母 都 是 Unicode 表 中 的 一 个 字 符, 比 如 汉 字 中 的 你 字 就 是 Unicode 表 中 的 第 20320 个 字 符, 还 包 含 日 文 里 的 片 假 名 平 假 名 韩 文 以 及 其 他 语 言 中 的 文 字 在 Java 中 的 定 义 示 例 : char c = 'a'; char c = '1'; 取 值 范 围 和 默 认 值 : 第 34 页

名 称 长 度 范 围 默 认 值 char 16 位 0~2 16-1 '\u0000' Java 里 面 的 转 义 字 符 转 义 字 符 是 指, 用 一 些 普 通 字 符 的 组 合 来 代 替 一 些 特 殊 字 符, 由 于 其 组 合 改 变 了 原 来 字 符 表 示 的 含 义, 因 此 称 为 转 义 常 见 的 转 义 字 符 : \n 回 车 (\u000a) \t 水 平 制 表 符 (\u0009) \b 退 格 (\u0008) \r 换 行 (\u000d) \f 换 页 (\u000c) \' 单 引 号 (\u0027) \" 双 引 号 (\u0022) \\ 反 斜 杠 (\u005c) 2.3.3.3 整 数 型 byte short int long byte: 字 节 型 short: 短 整 型 int: 整 型 long: 长 整 型 在 Java 中, 整 数 型 的 值 都 是 带 符 号 的 数 字, 可 以 用 十 进 制 八 进 制 和 十 六 进 制 来 表 示 所 谓 几 进 制, 就 是 满 多 少 就 进 位 的 意 思, 如 十 进 制 表 示 逢 十 进 位, 八 进 制 就 表 示 逢 八 进 位 示 例 : 2: 十 进 制 的 2 077: 首 位 的 0 表 示 这 个 一 个 8 进 制 的 数 值, 相 当 于 十 进 制 的 63, 计 算 公 式 :7*8+7=63 0x7C: 首 位 的 0x 表 示 这 个 一 个 16 进 制 的 数 值, 相 当 于 十 进 制 的 124, 计 算 公 式 : 7*16+12=124 在 Java 中 的 定 义 示 例 : 示 例 :byte bt = 5; 表 示 在 Java 中 定 义 一 个 变 量 bt, 类 型 是 byte 类 型, 值 是 5 同 理 可 以 定 义 其 它 的 类 型 : 比 如 : short sh = 5; int i = 5; long lon = 5; 这 些 都 是 可 以 的, 如 果 要 明 确 表 示 是 long 型 的 值, 可 以 在 后 面 直 接 跟 一 个 字 母 L 或 者 l L 表 示 一 个 long 值 也 就 是 写 成 :long abc4 =5L; 请 注 意 : 第 35 页

在 Java 编 程 语 言 中 使 用 大 写 或 小 写 L 同 样 都 是 有 效 的, 但 由 于 小 写 l 与 数 字 1 容 易 混 淆, 因 而, 尽 量 不 要 使 用 小 写 整 数 型 的 值, 如 果 没 有 特 别 指 明, 默 认 是 int 型 取 值 范 围 和 默 认 值 : 名 称 长 度 范 围 默 认 值 byte 8 位 -2 7 ~2 7-1 0 short 16 位 -2 15 ~2 15-1 0 int 32 位 -2 31 ~2 31-1 0 long 64 位 -2 63 ~2 63-1 0L 2.3.3.4 浮 点 型 float double Java 用 浮 点 型 来 表 示 实 数, 简 单 地 说 就 是 带 小 数 的 数 据 用 关 键 字 float 或 double 来 定 义 浮 点 类 型, 如 果 一 个 数 字 包 括 小 数 点 或 指 数 部 分, 或 者 在 数 字 后 带 有 字 母 F 或 f(float) D 或 d(double), 则 该 数 字 文 字 为 浮 点 型 的 示 例 : 12.3 // 浮 点 型 数 据 12.3E10 // 一 个 大 浮 点 数 据,E 或 e 表 示 指 数 值, 相 当 于 12.3*10 10 在 Java 中 的 定 义 示 例 : float f1 = 3.14F; float f2 = 3.14f; double d1 = 3.14; double d2 = 3.14D; double d3 = 3.14d; 请 注 意 : 浮 点 型 的 值, 如 果 没 有 特 别 指, 默 认 是 double 型 的 定 义 float 型 的 时 候, 一 定 要 指 明 是 float 型 的, 可 以 通 过 在 数 字 后 面 添 加 F 或 者 f 来 表 示 定 义 double 型 的 时 候, 可 以 不 用 指 明, 默 认 就 是 double 型 的, 也 可 以 通 过 在 数 字 后 面 添 加 D 或 者 d 来 表 示 取 值 范 围 和 默 认 值 : 名 称 长 度 范 围 默 认 值 float 32 位 0.0f double 64 位 0.0d Java 技 术 规 范 的 浮 点 数 的 格 式 是 由 电 力 电 子 工 程 师 学 会 (IEEE)754 定 义 的, 是 独 立 于 平 台 的 可 以 通 过 Float.MAX_VALUE 和 Float.MIN_VALUE 取 得 Float 的 最 大 最 小 值 ; 可 以 通 过 Double.MAX_VALUE 和 Double.MIN_VALUE 来 取 得 Double 的 最 大 最 小 值 第 36 页

2.3.3.5 特 别 介 绍 : 字 符 串 型 String 字 符 型 只 能 表 示 一 个 字 符, 那 么 多 个 字 符 怎 么 表 示 呢? Java 中 使 用 String 这 个 类 来 表 示 多 个 字 符, 表 示 方 式 是 用 双 引 号 把 要 表 示 的 字 符 串 引 起 来, 字 符 串 里 面 的 字 符 数 量 是 任 意 多 个 字 符 本 身 符 合 Unicode 标 准, char 类 型 的 反 斜 线 符 号 ( 转 义 字 符 ) 适 用 于 String 与 C 和 C++ 不 同,String 不 能 用 \0 作 为 结 束 String 的 文 字 应 用 双 引 号 封 闭, 如 下 所 示 : The quick brown fox jumped over the lazy dog. char 和 String 类 型 变 量 的 声 明 和 初 始 化 如 下 所 示 : char ch = 'A'; // 声 明 并 初 始 化 一 个 字 符 变 量 String str1 = "java 快 车 "; // 字 符 串 类 型 String str2 = ""; // 表 示 空 字 符 串 String str3 = null; // 表 示 空 ( 注 意 不 是 空 字 符 串 ) 注 意 : (1)String 不 是 原 始 的 数 据 类 型, 而 是 一 个 类 (class) (2)String 包 含 的 字 符 数 量 是 任 意 多 个, 而 字 符 类 型 只 能 是 一 个 要 特 别 注 意 : "a" 表 示 的 是 字 符 串, 而 'a' 表 示 的 是 字 符 类 型, 它 们 的 意 义 和 功 能 都 不 同 (3)String 的 默 认 值 是 null 2.4 变 量 和 常 量 2.4.1 变 量 变 量 是 Java 程 序 的 一 个 基 本 存 储 单 元, 它 可 以 用 来 引 用 另 一 个 存 储 单 元 变 量 由 一 个 标 识 符, 类 型 及 一 个 可 选 初 始 值 的 组 合 定 义 此 外, 所 有 的 变 量 都 有 一 个 作 用 域, 定 义 变 量 的 可 见 性, 生 存 期 变 量 的 值 是 可 以 改 变 的, 可 以 通 过 操 作 变 量 来 操 作 变 量 所 对 应 的 内 存 区 域 或 值 块 的 值 a 3 变 量 名 变 量 值 存 储 单 元 3 第 37 页

变 量 的 创 建 通 过 声 明 完 成, 执 行 变 量 声 明 语 句 时, 系 统 根 据 变 量 的 数 据 类 型 在 内 存 中 开 辟 相 应 的 存 储 空 间 并 赋 予 初 始 值 来 表 示 赋 值 就 是 为 一 个 声 明 的 变 量 或 者 常 量 赋 予 具 体 的 值, 也 就 是 赋 予 值 的 意 思 使 用 一 个 等 号 = 变 量 的 定 义 规 则 : (1) 遵 从 所 有 标 识 符 的 规 则 (2) 所 有 变 量 都 可 大 小 写 混 用, 但 首 字 符 应 小 写 (3) 尽 量 不 要 使 用 下 划 线 和 $ 符 号 (4) 可 以 先 声 明 再 赋 值, 如 : int i; i=9; 也 可 以 声 明 的 同 时 进 行 赋 值 : int i=9; 这 句 话 的 意 思 就 是, 声 明 一 个 类 型 为 int 的 变 量 i, 并 将 它 赋 值 为 9 (5) 没 有 赋 值 的 变 量 是 不 可 以 使 用 的 如 : int i; System.out.println(i);// 这 句 代 码 是 错 误 的 几 点 说 明 : (1) 变 量 在 计 算 机 内 部 对 应 着 一 个 存 储 单 元, 而 且 总 是 具 有 某 种 数 据 类 型 : 基 本 数 据 类 型 或 引 用 数 据 类 型 (2) 变 量 总 是 具 有 与 其 数 据 类 型 相 对 应 的 值 (3) 每 个 变 量 均 具 有 : 名 字 类 型 一 定 大 小 的 存 储 单 元 以 及 值 (4) 变 量 有 一 个 作 用 范 围, 超 出 它 声 明 语 句 所 在 的 块 就 无 效 2.4.2 常 量 常 量 是 变 量 中 的 一 个 特 例, 用 final 关 键 字 修 饰, 常 量 是 值 是 不 可 以 改 变 的, 也 就 是 说 常 量 引 用 的 存 储 单 元 中 的 数 据 是 不 可 更 改 的 对 常 量 命 名 的 定 义 规 则 : 建 议 大 家 尽 量 全 部 大 写, 并 用 下 划 线 将 词 分 隔 如 :JAVAKC_CLASS PI FILE_PATH 2.5 注 释 什 么 是 注 释 呢? 就 是 标 注 解 释 的 意 思, 主 要 用 来 对 Java 代 码 进 行 说 明 Java 中 有 三 种 注 释 方 式 第 38 页

(1)// 注 释 单 行 语 句 示 例 : // 定 义 一 个 值 为 10 的 int 变 量 int a = 10; (2)/* */ 多 行 注 释 示 例 : /* 这 是 一 个 注 释, 不 会 被 Java 用 来 运 行 这 是 第 二 行 注 释, 可 以 有 任 意 多 行 */ (3)/** */ 文 档 注 释 紧 放 在 变 量 方 法 或 类 的 声 明 之 前 的 文 档 注 释, 表 示 该 注 释 应 该 被 放 在 自 动 生 成 的 文 档 中 ( 由 javadoc 命 令 生 成 的 HTML 文 件 ) 以 当 作 对 声 明 项 的 描 述 示 例 : /** * 这 是 一 个 文 档 注 释 的 测 试 * 它 会 通 过 javadoc 生 成 标 准 的 java 接 口 文 档 */ 在 javadoc 注 释 中 加 入 一 个 以 @ 开 头 的 标 记, 结 合 javadoc 指 令 的 参 数, 可 以 在 生 成 的 API 文 档 中 产 生 特 定 的 标 记 常 用 的 javadoc 标 记 : @author: 作 者 @version: 版 本 @deprecated: 不 推 荐 使 用 的 方 法 @param: 方 法 的 参 数 类 型 @return: 方 法 的 返 回 类 型 @see:" 参 见 ", 用 于 指 定 参 考 的 内 容 @exception: 抛 出 的 异 常 @throws: 抛 出 的 异 常, 和 exception 同 义 javadoc 标 记 的 应 用 范 围 : 在 类 和 接 口 文 档 注 释 中 的 标 记 有 :@see @deprecated @author @version 在 方 法 或 者 构 造 方 法 中 的 标 记 有 :@see @deprecated @param @return @exception @throws 在 属 性 文 档 注 释 中 的 标 记 :@see @deprecated 2.6 运 算 符 和 表 达 式 程 序 的 基 本 功 能 是 处 理 数 据, 任 何 编 程 语 言 都 有 自 己 的 运 算 符 为 实 现 逻 辑 和 运 算 要 求, 编 第 39 页

程 语 言 设 置 了 各 种 不 同 的 运 算 符, 且 有 优 先 级 顺 序, 所 以 有 的 初 学 者 使 用 复 杂 表 达 式 的 时 候 搞 不 清 楚 下 面 按 优 先 顺 序 列 出 了 各 种 运 算 符 : 优 先 级 运 算 符 分 类 运 算 符 由 高 到 低 一 元 运 算 符 ++ -- - 算 术 运 算 符 * / % + - () 关 系 运 算 符 < > <= >= ==!= 逻 辑 运 算 符! && 三 目 运 算 符 布 尔 表 达 式? 表 达 式 1: 表 达 式 2 赋 值 运 算 符 = *= /= %= += -= 表 达 式 是 由 常 量 变 量 对 象 方 法 调 用 和 操 作 符 组 成 的 式 子 表 达 式 必 须 符 合 一 定 的 规 范, 才 可 被 系 统 理 解 编 译 和 运 行 表 达 式 的 值 就 是 对 表 达 式 自 身 运 算 后 得 到 的 结 果 根 据 运 算 符 的 不 同, 表 达 式 相 应 地 分 为 以 下 几 类 : 算 术 表 达 式 关 系 表 达 式 逻 辑 表 达 式 赋 值 表 达 式, 这 些 都 属 于 数 值 表 达 式 2.6.1 一 元 运 算 符 因 操 作 数 是 一 个 故 称 为 一 元 运 算 符 运 算 符 含 义 示 例 - 改 变 数 值 的 符 号, 取 反 -10 -x ++ 左 结 合 ++x; x++; -- 左 结 合 --x; x--; 需 要 注 意 的 是 ++ 或 -- 操 作 : ++x 因 为 ++ 在 前, 所 以 先 加 后 用 x++ 因 为 ++ 在 后, 所 以 先 用 后 加 有 一 种 特 殊 的 情 况 :a+ ++b 和 a+++b 是 不 一 样 的 ( 因 为 有 一 个 空 格 ) int a = 10; int b = 10; int sum = a + ++b; System.out.println("a=" + a + ",b=" + b + ",sum=" + sum); 运 行 结 果 是 : a=10,b=11,sum=21 int a = 10; int b = 10; int sum = a++ + b; 第 40 页

System.out.println("a=" + a + ",b=" + b + ",sum=" + sum); 运 行 结 果 是 :a=11,b=10,sum=20 2.6.2 算 术 运 算 算 术 运 算 是 指 :+ - * / 等 基 本 运 算 运 算 符 含 义 代 码 示 例 运 算 示 例 + 加 法 x+y 1+2 结 果 :3 ;1.2+1 结 果 :2.2 - 减 法 x-y 1-2 结 果 :-1 ;1.2-1 结 果 :0.2 * 乘 法 x*y 1*2 结 果 :2 ;1.2*1 结 果 :1.2 / 除 法 x/y 5/2 结 果 :2 ;5.2/2 结 果 :2.6 % 求 模 ( 余 ) x%y 5%2 结 果 :1 这 些 操 作 可 以 对 不 同 类 型 的 数 字 进 行 混 合 运 算, 为 了 保 证 操 作 的 精 度, 系 统 在 运 算 过 程 中 会 做 相 应 的 转 化 数 字 精 度 的 问 题, 我 们 在 这 里 不 再 讨 论 下 图 中 展 示 了 运 算 过 程 中, 数 据 自 动 向 上 造 型 的 原 则 1. 实 线 箭 头 表 示 没 有 信 息 丢 失 的 转 换, 也 就 是 安 全 性 的 转 换, 虚 线 的 箭 头 表 示 有 精 度 损 失 的 转 化, 也 就 是 不 安 全 的 2. 当 两 个 操 作 数 类 型 不 相 同 时, 操 作 数 在 运 算 前 会 子 松 向 上 造 型 成 相 同 的 类 型, 再 进 行 运 算 示 例 如 下 : int a = 22; int b = 5; double c = 5.0; System.out.println(b + "+" + c + "=" + (b + c)); //10.0 System.out.println(b + "-" + c + "=" + (b - c)); //0.0 System.out.println(b + "*" + c + "=" + (b * c)); //25.0 System.out.println(a + "/" + b + "=" + (a / b)); //4 System.out.println(a + "%" + b + "=" + (a % b)); //2 System.out.println(a + "/" + c + "=" + (a / c)); //4.4 System.out.println(a + "%" + c + "=" + (a % c)); //2.0 用 加 号 (+) 进 行 串 链 接 第 41 页

运 算 符 + 能 够 进 行 String 对 象 的 链 接 并 生 成 一 个 新 的 String: String salutation = "Dr. "; String name = "Jack " + "Arthur"; String title = salutation + name; 最 后 一 行 的 结 果 是 : Dr. Jack Arthur 如 果 + 运 算 符 中 有 一 个 自 变 量 为 String 对 象, 则 其 它 自 变 量 将 被 转 换 成 String 所 有 对 象 都 可 被 自 动 转 换 成 String, 尽 管 这 样 做 的 结 果 可 能 是 意 义 含 糊 的 不 是 字 符 串 的 对 象 是 通 过 使 用 tostring() 成 员 方 法 而 转 换 成 串 的 等 价 物 的 2.6.3 关 系 ( 比 较 ) 运 算 符 Java 具 有 完 备 的 关 系 运 算 符, 这 些 关 系 运 算 符 同 数 学 中 的 关 系 运 算 符 是 一 致 的 具 体 说 明 如 下 : 运 算 符 含 义 示 例 < 小 于 x<y > 大 于 x>y <= 小 于 等 于 x<=y >= 大 于 等 于 x>=y == 等 于 x==y!= 不 等 于 x!=y 关 系 运 算 符 用 于 比 较 两 个 数 据 之 间 的 大 小 关 系, 产 生 的 结 果 都 是 布 尔 型 的 值, 一 般 情 况 下, 在 逻 辑 与 控 制 中 会 经 常 使 用 关 系 运 算 符, 用 于 选 择 控 制 的 分 支, 实 现 逻 辑 要 求 instanceof 操 作 符 用 于 判 断 一 个 引 用 类 型 所 引 用 的 对 象 是 否 是 某 个 指 定 的 类 或 子 类 的 实 例, 如 果 是, 返 回 真 (true), 否 则 返 回 假 (false) 操 作 符 左 边 的 操 作 元 是 一 个 引 用 类 型, 右 边 的 操 作 元 是 一 个 类 名 或 者 接 口, 形 式 如 下 : obj instanceof ClassName 或 者 obj instanceof InterfaceName 需 要 注 意 的 是 : 关 系 运 算 符 中 的 "==" 和 "!=" 既 可 以 操 作 基 本 数 据 类 型, 也 可 以 操 作 引 用 数 据 类 型 操 作 引 用 数 据 类 型 时, 比 较 的 是 引 用 的 内 存 地 址 所 以 在 比 较 非 基 本 数 据 类 型 时, 应 该 使 用 equals 方 法 简 单 示 例 如 下 : public class TestRelation { public static void main(string args[]) { // 变 量 初 始 化 int a = 30; int b = 20; // 定 义 结 果 变 量 boolean r1, r2, r3, r4, r5, r6; 第 42 页

// 计 算 结 果 r1 = a == b; r2 = a!= b; r3 = a > b; r4 = a < b; r5 = a >= b; r6 = a <= b; // 输 出 结 果 System.out.println("a = " + a + " b = " + b); System.out.println("a==b = " + r1); System.out.println("a!=b = " + r2); System.out.println("a>b = " + r3); System.out.println("a<b = " + r4); System.out.println("a>=b = " + r5); System.out.println("a<=b = " + r6); 运 行 结 果 如 下 : a = 30 b = 20 a==b = false a!=b = true a>b = true a<b = false a>=b = true a<=b = false 2.6.4 逻 辑 运 算 运 算 符!( 定 义 为 非 ) && ( 定 义 为 与 ) ( 定 义 为 或 ) 执 行 布 尔 逻 辑 表 达 式 逻 辑 非 关 系 值 表 A!A true false false true 逻 辑 与 关 系 值 表 A B A&&B true true true true false false false true false false false false 第 43 页

逻 辑 或 关 系 值 表 A B A B true true true true false true false true true false false false 在 运 用 逻 辑 运 算 符 进 行 相 关 的 操 作, 就 不 得 不 说 短 路 现 象 代 码 如 下 : if(1==1 && 1==2 && 1==3){ 代 码 从 左 至 右 执 行, 执 行 第 一 个 逻 辑 表 达 式 后 :true && 1==2 && 1==3 执 行 第 二 个 逻 辑 表 达 式 后 :true && false && 1==3 因 为 其 中 有 一 个 表 达 式 的 值 是 false, 可 以 判 定 整 个 表 达 式 的 值 是 false, 就 没 有 必 要 执 行 第 三 个 表 达 式 了, 所 以 Java 虚 拟 机 不 执 行 1==3 代 码, 就 好 像 被 短 路 掉 了 逻 辑 或 也 存 在 短 路 现 象, 当 执 行 到 有 一 个 表 达 式 的 值 为 true 时, 整 个 表 达 式 的 值 就 为 true, 后 面 的 代 码 就 不 执 行 了 短 路 现 象 在 多 重 判 断 和 逻 辑 处 理 中 非 常 有 用 我 们 经 常 这 样 使 用 : public void a(string str) { if (str!= null && str.trim().length() > 0) { //do some thing; 如 果 str 为 null, 那 么 执 行 str.trim().length() 就 会 报 错, 短 路 现 象 保 证 了 我 们 的 代 码 能 够 正 确 执 行 在 书 写 布 尔 表 达 式 时, 首 先 处 理 主 要 条 件, 如 果 主 要 条 件 已 经 不 满 足, 其 他 条 件 也 就 失 去 了 处 理 的 意 义 也 提 高 了 代 码 的 执 行 效 率 2.6.5 三 目 运 算 三 目 运 算 符 (?:) 相 当 于 条 件 判 断, 表 达 式 x?y:z 用 于 判 断 x 是 否 为 真, 如 果 为 真, 表 达 式 的 值 为 y, 否 则 表 达 式 的 值 为 z 例 如 : public class Test { public static void main(string[] args) { int i = (5 > 3)? 6 : 7; System.out.println("the i=" + i); 运 行 结 果 为 :the i=6 第 44 页

其 实 三 目 运 算 符 的 基 本 功 能 相 当 于 if-else( 马 上 就 要 学 到 了 ), 使 用 三 目 运 算 符 是 因 为 它 的 表 达 比 相 同 功 能 的 if-else 更 简 洁 上 面 的 例 子 改 成 用 if-else 表 达 如 下 : public class Test { public static void main(string[] args) { int i = 0; if (5 > 3) { i = 6; else { i = 7; System.out.println("the i=" + i); 运 行 结 果 为 :the i=6 2.6.6 赋 值 运 算 符 基 本 的 赋 值 运 算 符 是 = 他 的 优 先 级 别 低 于 其 他 的 运 算 符, 所 以 对 该 运 算 符 往 往 最 后 读 取 一 开 始 可 能 会 以 为 它 是 等 于, 其 实 不 是 的 它 的 作 用 是 将 一 个 表 达 式 的 值 赋 给 一 个 左 值 一 个 表 达 式 或 者 是 一 个 左 值, 或 者 是 一 个 右 值 所 谓 左 值 是 指 一 个 能 用 于 赋 值 运 算 左 边 的 表 达 式 左 值 必 须 能 够 被 修 改, 不 能 是 常 量 我 们 现 在 是 用 变 量 作 左 值, 以 后 还 可 以 看 到, 指 针 和 引 用 也 可 以 作 左 值 例 如 : int a, b, c; a = 3; b = 4; c = (a + b) * (2 * a - b); // 得 出 14 += 是 先 做 加 法 运 算, 再 进 行 赋 值 操 作, 比 如 : int a; a = 3; a += 2;// 得 出 5 其 他 的 赋 值 运 算 符 和 += 类 似 2.7 位 运 算 符 ( 选 修 ) 优 先 级 运 算 符 分 类 运 算 符 由 一 元 运 算 符 ~ 高 移 位 运 算 符 << >> >>> 到 位 运 算 ~ & ^ 低 赋 值 运 算 符 <<= >>= >>>= &= ~= = ^= 第 45 页

2.7.1 位 运 算 位 运 算 符 包 括 :&( 与 ), ( 或 ),~( 取 反 ),^( 异 或 ); 位 运 算 是 对 整 数 的 二 进 制 位 进 行 相 关 操 作, 详 细 运 算 如 下 : 非 位 关 系 值 表 A ~A 1 0 0 1 与 位 关 系 值 表 A B A 1 0 0 0 1 0 1 1 1 0 0 0 或 位 关 系 值 表 A B A 1 0 1 0 1 1 1 1 1 0 0 0 异 或 位 关 系 值 表 A B A 1 0 1 0 1 1 1 1 0 0 0 0 位 运 算 示 例 : int a = 15; int b = 2; System.out.println(a + "&" + b + "=" + (a & b)); System.out.println(a + " " + b + "=" + (a b)); System.out.println(a + "^" + b + "=" + (a ^ b)); System.out.println("~" + b + "=" + (~b)); 第 46 页

运 算 结 果 如 下 : 15&2=2 15 2=15 15^2=13 ~2=-3 2.7.2 移 位 运 算 符 移 位 运 算 符 操 作 的 对 象 就 是 二 进 制 的 位, 可 以 单 独 用 移 位 运 算 符 来 处 理 int 型 或 long 型 整 数, 在 运 算 byte 和 short 类 型 数 据 时, 会 自 动 向 上 造 型 成 int, 再 运 算 运 算 符 含 义 示 例 << 左 移 运 算 符, 将 运 算 符 左 边 的 对 象 向 左 移 动 运 算 符 右 边 指 定 的 位 数 ( 在 低 位 补 0) >> " 有 符 号 " 右 移 运 算 符, 将 运 算 符 左 边 的 对 象 向 右 移 动 运 算 符 右 边 指 定 的 位 数 使 用 符 号 扩 展 机 制, 也 就 是 说, 如 果 值 为 正, 则 在 高 位 补 0, 如 果 值 为 负, 则 在 高 位 补 1. >>> " 无 符 号 " 右 移 运 算 符, 将 运 算 符 左 边 的 对 象 向 右 移 动 运 算 符 右 边 指 定 的 位 数 采 用 0 扩 展 机 制, 也 就 是 说, 无 论 值 的 正 负, 都 在 高 位 补 0. 100<<3 : 800 100>>3 :12-100>>>3 :536870 899 以 int 类 型 的 2039 为 例, 代 码 如 下 : System.out.println(Integer.toBinaryString(2039)); System.out.println(Integer.toBinaryString(-2039)); System.out.println(Integer.toBinaryString(2039 >> 5)); System.out.println(Integer.toBinaryString(-2039 >> 5)); System.out.println(Integer.toBinaryString(2039 >>> 5)); System.out.println(Integer.toBinaryString(-2039 >>> 5)); System.out.println(Integer.toBinaryString(2039 << 5)); System.out.println(Integer.toBinaryString(-2039 << 5)); 第 47 页

运 行 结 果 如 下 : 11111110111 11111111111111111111100000001001 111111 11111111111111111111111111000000 111111 111111111111111111111000000 1111111011100000 11111111111111110000000100100000 注 意 : 负 数 的 二 进 制 表 现 形 式 是 正 数 取 反 加 一 x<<y 相 当 于 x*2 y ;x>>y 相 当 于 x/2 y 从 计 算 速 度 上 讲, 移 位 运 算 要 比 算 术 运 算 快 如 果 x 是 负 数, 那 么 x>>>3 没 有 什 么 算 术 意 义, 只 有 逻 辑 意 义 移 位 运 算 符 将 它 们 右 侧 的 操 作 数 模 32 简 化 为 int 类 型 左 侧 操 作 数, 模 64 简 化 为 long 类 型 右 侧 操 作 数 因 而, 任 何 int x, x >>> 32 都 会 导 致 不 变 的 x 值, 而 不 是 你 可 能 预 计 的 零 2.8 控 制 语 句 2.8.1 分 支 控 制 语 句 分 支 语 句 又 称 条 件 语 句, 条 件 语 句 使 部 分 程 序 可 根 据 某 些 表 达 式 的 值 被 有 选 择 地 执 行 Java 编 程 语 言 支 持 双 路 if 和 多 路 switch 分 支 语 句 2.8.1.1 if 语 句 if-else 语 句 的 基 本 句 法 是 : if( 布 尔 表 达 式 ){ 语 句 块 1; else{ 语 句 块 2; 说 明 : (1) 布 尔 表 达 式 返 回 值 为 true 或 false (2) 如 果 为 true, 则 执 行 语 句 或 块 1, 执 行 完 毕 跳 出 if-else 语 句 (3) 如 果 为 false, 则 跳 过 语 句 或 块 1, 然 后 执 行 else 下 的 语 句 或 块 2 第 48 页

true 布 尔 表 达 式 false 语 句 块 1 语 句 块 2 例 如 : int a=10; int b=10; if (a >= b) { System.out.println("a 大 于 等 于 b"); else { System.out.println("a 小 于 b"); 在 Java 编 程 语 言 中,if () 用 的 是 一 个 布 尔 表 达 式, 而 不 是 数 字 值, 这 一 点 与 C/C++ 不 同 前 面 已 经 讲 过, 布 尔 类 型 和 数 字 类 型 不 能 相 互 转 换 因 而, 如 果 出 现 下 列 情 况 : if (x) // x 是 int 型 你 应 该 使 用 下 列 语 句 替 代 : if (x! = 0) 注 意 : (1)if 块 和 else 块 可 以 包 含 任 意 的 java 代 码, 自 然 也 就 可 以 包 含 新 的 if-else, 也 就 是 说 :if-else 是 可 以 嵌 套 的, 嵌 套 的 规 则 是 不 可 以 交 叉, 必 须 完 全 包 含 比 如 : if (a1 > a2) { if (a1 > a3) { // 包 含 在 里 面 的 块 必 须 先 结 束 else { // 同 样 可 以 包 含 if-else 块 (2)else 部 分 是 选 择 性 的, 并 且 当 测 试 条 件 为 假 时 如 不 需 做 任 何 事,else 部 分 可 被 省 略 也 就 是 说 if 块 可 以 独 立 存 在, 但 是 else 块 不 能 独 立 存 在, 必 须 要 有 if 块 才 能 有 else 块 (3) 如 果 if 块 和 else 块 的 语 句 只 有 一 句 时, 可 以 省 略 {, 例 如 : if (a1 > a2) System.out.println(" 这 是 if 块 "); 第 49 页

else System.out.println(" 这 是 else 块 "); 上 面 的 代 码 从 语 法 角 度 是 完 全 正 确 的, 但 是 从 代 码 的 可 阅 读 性 上, 容 易 让 人 产 生 迷 惑, 所 以 我 们 不 建 议 大 家 这 么 写 例 如 下 : (4) 还 可 以 把 else 和 if 组 合 使 用, 就 是 使 用 else if, 表 达 否 则 如 果 的 意 思, 示 if (score >= 90) { grade = "very good"; else if (score >= 70) { grade = "good"; else if (score >= 60) { grade = "pass"; else { grade = "No pass"; (5) 如 果 不 用 {, 则 else 总 是 与 最 接 近 它 的 前 一 个 if 相 匹 配, 例 如 : if (x > 5) if (y > 5) System.out.println("x and y are > 5"); else System.out.println("x is <= 5"); 执 行 顺 序 与 上 面 的 对 应 匹 配 形 式 不 同, 而 是 与 下 面 形 式 匹 配 if (x > 5) if (y > 5) System.out.println("x and y are > 5"); else System.out.println("x is <= 5"); 2.8.1.2 switch 语 句 switch 表 示 选 择 分 支 的 情 况,switch 语 句 的 句 法 是 : switch ( 表 达 式 1){ case 表 达 式 2: 语 句 块 2; break; case 表 达 式 3: 语 句 块 3; break; default: 语 句 块 4; break; 第 50 页

说 明 : (1) 表 达 式 1 的 值 必 须 与 整 型 兼 容 或 者 enum 枚 举 类 型 的 常 量 值, 包 含 byte short int 和 char, 不 能 是 字 符 串 或 对 象, 也 不 能 是 long 型 的 值 (2)case 分 支 要 执 行 的 程 序 语 句 (3) 表 达 式 2 3 4 是 可 能 出 现 的 值 (4) 不 同 的 case 分 支 对 应 着 不 同 的 语 句 或 块 序 列 (5)break 表 示 跳 出 这 一 分 支 (6) 当 变 量 或 表 达 式 的 值 不 能 与 任 何 case 值 相 匹 配 时, 可 选 缺 省 符 (defauit) 指 出 了 应 该 执 行 的 程 序 代 码 示 例 : public class Test { public static void main(string[] args) { int colornum = 5; switch (colornum) { case 0: System.out.println(Color.red); break; case 1: System.out.println(Color.green); break; default: System.out.println(Color.black); break; 运 行 结 果 : java.awt.color[r=0,g=0,b=0] (6) 如 果 没 有 break 语 句 作 为 某 一 个 case 代 码 段 的 结 束 句, 则 程 序 的 执 行 将 继 续 到 下 一 个 case, 而 不 检 查 case 表 达 式 的 值 示 例 : import java.awt.color; public class Test { public static void main(string[] args) { int colornum = 0; switch (colornum) { case 0: System.out.println(Color.red); case 1: 第 51 页

System.out.println(Color.green); default: System.out.println(Color.black); break; 运 行 结 果 : java.awt.color[r=255,g=0,b=0] java.awt.color[r=0,g=255,b=0] java.awt.color[r=0,g=0,b=0] 2.8.2 循 环 控 制 语 句 循 环 语 句 使 语 句 或 块 的 执 行 得 以 重 复 进 行 Java 编 程 语 言 支 持 三 种 循 环 构 造 类 型 :for, while 和 do 循 环 for 和 while 循 环 是 在 执 行 循 环 体 之 前 测 试 循 环 条 件, 而 do 循 环 是 在 执 行 完 循 环 体 之 后 测 试 循 环 条 件 这 就 意 味 着 for 和 while 循 环 可 能 连 一 次 循 环 体 都 未 执 行, 而 do 循 环 将 至 少 执 行 一 次 循 环 体 2.8.2.1 for 循 环 for 循 环 的 句 法 是 : for ( 初 值 表 达 式 ; 测 试 表 达 式 ; 改 变 量 表 达 式 / 步 长 ){ 语 句 块 其 执 行 顺 序 如 下 : (1) 首 先 运 行 初 值 表 达 式 (2) 然 后 计 算 测 试 表 达 式, 如 果 表 达 式 为 true, 执 行 语 句 或 块 ; 如 果 表 达 式 为 false, 退 出 for 循 环 (3) 最 后 执 行 步 长, 第 一 次 循 环 结 束 (4) 第 二 次 循 环 开 始 : 首 先 判 断 测 试 表 达 式, 转 到 第 2 步 继 续 运 行 第 52 页

初 值 表 达 式 测 试 表 达 式 false true 语 句 或 块 改 变 量 表 达 式 示 例 : for (int i = 0; i < 10; i++) { System.out.println("Java 快 车 "); System.out.println("Finally!"); 注 意 :for 循 环 的 执 行 顺 序 : 先 执 行 初 始 值 表 达 式 int i = 0; 再 执 行 一 遍 测 试 表 达 式 i < 10; 如 果 测 试 表 达 式 返 回 true, 则 执 行 循 环 体, 就 是 System 的 输 出 语 句, 如 果 测 试 表 达 式 返 回 false, 则 整 个 循 环 结 束, 然 后 执 行 增 量 表 达 式 我 们 称 这 是 第 一 次 循 环 结 束 了, 初 始 值 表 达 式 只 执 行 一 次, 第 二 次 循 环 从 测 试 表 达 式 开 始, 方 法 和 步 骤 和 第 一 次 一 样 循 环 就 这 样 一 次 一 次 地 进 行, 直 到 测 试 表 达 式 返 回 false, 整 个 循 环 就 结 束 了, 这 个 for 语 句 的 生 命 周 期 就 结 束 了 for 语 句 里 面 的 3 个 部 分 都 可 以 省 略, 但 是 我 们 不 建 议 这 么 做 示 例 如 下 : 示 例 1:3 个 部 分 全 部 省 略, 就 是 一 个 无 限 循 环 public class Test { public static void main(string[] args) { for (;;) { System.out.println("Java 快 车 "); 示 例 2: 省 略 测 试 表 达 式 和 增 量 表 达 式 部 分, 就 是 一 个 无 限 循 环 public class Test { public static void main(string[] args) { 第 53 页

for (int i = 0;;) { System.out.println("Java 快 车 " + i); 示 例 3: 可 以 省 略 增 量 表 达 式 部 分, 就 是 一 个 无 限 循 环 public class Test { public static void main(string[] args) { for (int i = 0; i < 3;) { System.out.println("Java 快 车 " + i); 示 例 4: 可 以 省 略 增 量 表 达 式 部 分, 就 是 一 个 无 限 循 环 public class Test { public static void main(string[] args) { for (int i = 0;; i++) { System.out.println("Java 快 车 " + i); 示 例 5: 在 for 语 句 的 括 号 里 的 表 达 式 省 略 后, 仍 然 能 完 成 全 部 功 能 public class Test { public static void main(string[] args) { int i = 0; for (;; ) { if(i==10){ // 如 果 条 件 成 立, 使 用 break 跳 出 循 环 break; System.out.println("Java 快 车 " + i); i++; for 循 环 的 组 合 很 多, 要 灵 活 运 行, 避 免 死 循 环 2.8.2.2 while 循 环 while 循 环 的 句 法 是 : while ( 布 尔 表 达 式 ) { 语 句 块 第 54 页

说 明 : 当 布 尔 表 达 式 为 true 时, 执 行 语 句 或 块, 否 则 跳 出 while 循 环 布 尔 表 达 式 false true 语 句 块 示 例 : int i = 0; while (i < 10) { System.out.println("javakc"); i++; System.out.println("Finally!"); 请 确 认 循 环 控 制 变 量 在 循 环 体 被 开 始 执 行 之 前 已 被 正 确 初 始 化, 并 确 认 循 环 控 制 变 量 是 真 时, 循 环 体 才 开 始 执 行 控 制 变 量 必 须 被 正 确 更 新 以 防 止 死 循 环 2.8.2.3 do-while 循 环 do-while 循 环 的 句 法 是 : do { 语 句 块 ; while ( 测 试 值 表 达 式 ); 说 明 : 先 执 行 语 句 或 块, 然 后 再 判 断 布 尔 表 达 式 与 while 语 句 不 同, 当 布 尔 表 达 式 一 次 都 不 为 true 时,while 语 句 一 开 始 判 断 就 跳 出 循 环, 一 次 都 不 执 行 语 句 或 块, 而 在 do 语 句 中 则 要 执 行 一 次 第 55 页

语 句 或 块 true 布 尔 表 达 式 false 示 例 : int i = 0; do { System.out.println("javakc"); i++; while (i < 10); System.out.println("Finally!"); 像 while 循 环 一 样, 请 确 认 循 环 控 制 变 量 在 循 环 体 中 被 正 确 初 始 化 和 测 试 并 被 适 时 更 新 作 为 一 种 编 程 惯 例,for 循 环 一 般 用 在 那 种 循 环 次 数 事 先 可 确 定 的 情 况, 而 while 和 do 用 在 那 种 循 环 次 数 事 先 不 可 确 定 的 情 况 2.8.2.4 特 殊 循 环 流 程 控 制 下 列 语 句 可 被 用 在 更 深 层 次 的 控 制 循 环 语 句 中 : break [label]; continue[label]; label: 语 句 ;// 这 里 必 须 是 任 意 的 合 法 的 语 句 break 语 句 被 用 来 从 switch 语 句 循 环 语 句 和 预 先 给 定 了 label 的 块 中 退 出, 跳 出 离 break 最 近 的 循 环 continue 语 句 被 用 来 略 过 并 跳 到 循 环 体 的 结 尾, 终 止 本 次 循 环, 继 续 下 一 次 循 环 label 可 标 识 控 制 需 要 转 换 到 的 任 何 有 效 语 句, 它 被 用 来 标 识 循 环 构 造 的 复 合 语 句 当 嵌 套 在 几 层 循 环 中 想 退 出 循 环 时, 正 常 的 break 只 退 出 一 重 循 环, 你 可 以 用 标 号 标 出 你 想 退 出 哪 一 个 语 句 它 类 似 以 前 被 人 诟 病 的 goto 语 句, 我 们 应 该 尽 量 避 免 使 用 例 1:break 的 使 用 public class Test { public static void main(string[] args) { for (int i = 0; i < 10; i++) { if (i == 5) { break; System.out.println("i==" + i); 第 56 页

运 行 的 结 果 :i==0 一 直 到 i==4 因 为 当 i==5 的 时 候, 执 行 break, 跳 出 for 循 环 例 2:continue 的 使 用 public class Test { public static void main(string[] args) { for (int i = 0; i < 5; i++) { if (i == 3) { continue; System.out.println("i==" + i); 运 行 的 结 果 :i==0 一 直 到 i==4, 就 是 不 包 括 i==3 因 为 当 i==3 的 时 候, 执 行 continue, 终 止 本 次 循 环, 继 续 下 一 次 循 环 例 3:label 的 使 用 public class Test { public static void main(string[] args) { L: for (int i = 0; i < 5; i++) { if (i == 3) { break L; System.out.println("i==" + i); 运 行 的 结 果 是 :i==0 一 直 到 i==2 在 这 里 看 不 出 执 行 效 果, 如 果 是 两 层 嵌 套 的 循 环, 使 用 label 就 可 以 跳 出 外 层 的 循 环 了 例 4:label 的 使 用 public class Test { public static void main(string[] args) { for (int i = 0; i < 5; i++) { L: if (i == 3) { break L; System.out.println("i==" + i); 运 行 的 结 果 是 :i==0 一 直 到 i==4 例 5:label 的 使 用 public class Test { 第 57 页

public static void main(string[] args) { L: for (int i = 0; i < 5; i++) { if (i == 3) { continue L; System.out.println("i==" + i); 运 行 的 结 果 是 :i==0 i==1 i==2 i==4 2.8.2.5 循 环 的 使 用 技 巧 1. 如 果 两 个 或 两 个 以 上 的 for 嵌 套 使 用, 则 执 行 循 环 次 数 多 的 放 最 里 面, 即 执 行 次 数 由 内 到 外 布 局, 这 样 可 以 提 高 执 行 速 度 2. 变 量 的 定 义 等 应 当 尽 量 放 在 for 外 面, 而 不 是 放 里 面 3. 知 道 循 环 次 数 时 使 用 for 循 环, 不 知 道 循 环 次 数 时 使 用 while 循 环 4. 尽 量 使 用 for 而 不 是 while: 因 为 for 初 值, 结 束 条 件, 循 环 增 量 都 放 在 一 起, 看 起 来 方 便 第 58 页

2.9 学 习 目 标 1. 了 解 什 么 是 关 键 字? 2. 了 解 学 习 Java 中 的 关 键 字 需 要 注 意 什 么? 3. 了 解 什 么 是 标 识 符? 4. 能 够 描 述 标 识 符 的 命 名 规 则 5. Java 中 数 据 类 型 的 分 类 6. Java 中 有 哪 些 基 本 数 据 类 型 7. 掌 握 8 个 基 本 数 据 类 型 的 范 围, 并 使 用 数 据 类 型 声 明 变 量 8. 深 刻 理 解 Java 中 的 变 量, 变 量 的 赋 值, 变 量 的 存 储 9. 代 码 写 出 Java 中 的 注 释 10. 学 习 Java 中 的 运 算 符, 能 够 说 出 每 种 运 算 符 的 运 算 法 则, 并 能 够 代 码 示 例 11. 描 述 if 语 句 的 句 法 结 构, 能 够 说 出 if 语 句 的 运 行 过 程, 并 能 够 灵 活 使 用 if 语 句 和 if 语 句 的 嵌 套 12. 描 述 switch 语 句 的 句 法 结 构, 能 够 说 出 switch 语 句 的 运 行 过 程, 并 能 够 灵 活 使 用 switch 语 句, 理 解 break 13. 描 述 for 语 句 的 句 法 结 构, 能 够 说 出 for 语 句 的 运 行 过 程, 并 能 够 灵 活 使 用 for 语 句 和 for 语 句 的 嵌 套 14. 描 述 while 语 句 的 句 法 结 构, 能 够 说 出 while 语 句 的 运 行 过 程, 并 能 够 灵 活 使 用 while 语 句 15. 描 述 do-while 语 句 的 句 法 结 构, 能 够 说 出 do-while 语 句 的 运 行 过 程, 并 能 够 灵 活 使 用 do-while 语 句 16. 总 结 循 环 语 句 的 本 质 17. 理 解 循 环 语 句 中 的 break 和 continue, 并 代 码 示 例 18. 理 解 循 环 语 句 中 的 Label, 并 代 码 示 例 第 59 页

2.10 练 习 1. 叙 述 标 识 符 的 定 义 规 则, 指 出 下 面 的 标 识 符 中 那 些 是 不 正 确 的, 并 说 明 理 由 here, _there, this, it, 2to1, _it 2. Java 中 有 那 些 基 本 数 据 类 型? 分 别 用 什 么 符 号 来 表 示, 各 自 的 取 值 范 围 是 多 少? 3. 指 出 正 确 的 表 达 式 A. byte b=128; B. char c=65536; C. long len=0xfffl; D. double dd=0.9239d; 4. 下 面 哪 几 个 语 句 将 引 起 编 译 错? A. float f=2039.0; B. double d=2039.0; C. byte b=2039; D. char c=2039; 5. 描 述 短 路 现 象 6. 执 行 下 列 代 码 后 的 x 和 y 的 结 果 分 别 是 什 么? int x,y,a=2; x=a++; y=++a; 7. 下 面 的 程 序 输 出 结 果 是 :a=6 b=5, 请 将 程 序 补 充 完 整 public class A{ public static void main(string args[]){ int a=5,b=6; a= ; b=a-b; a= ; System.out.println("a="+a+ "b="+b); 8. 下 面 哪 个 语 句 序 列 没 有 错 误, 能 够 通 过 编 译? A. int i=0; if(i){ System.out.println("Hi"); 第 60 页

B. boolean b=true; boolean b2=true; if(b==b2) { System.out.println("So true"); C. int i=1; int j=2; if(i==1 j==2) System.out.println("OK"); D. int i=1; int j=2; if (i==1 & j==2) System.out.println("OK"); 9. 阅 读 以 下 代 码 行 : boolean a=false; boolean b=true; boolean c=(a&&b)&&(!b); int result= c==false?1:2; 这 段 程 序 执 行 完 后,c 与 result 的 值 是 : A. c=false; result=1; B. c=true; result=2; C. c=true; result=1; D. c=false; result=2; 10. 下 列 代 码 哪 行 会 出 错? 1) public void modify() { 2) int i, j, k; 3) i = 100; 4) while ( i > 0 ) { 5) j = i * 2; 6) System.out.println (" The value of j is " + j ); 7) k = k + 1; 8) i--; 9) 10) A 第 4 行 B 第 6 行 C 第 7 行 D 第 8 行 11. 指 出 下 列 程 序 的 运 行 结 果 int i = 9; switch ( i ) { default: System.out.print("default"); case 0: 第 61 页

System.out.print("zero"); break; case 1: System.out.print("one"); case 2: System.out.print("two"); A. default B. defaultzero C. 编 译 错 D. 没 有 任 何 输 出 以 下 是 编 程 题 : 12. 将 1 到 1000 内 的 全 部 数 字 打 印 出 来, 数 字 之 间 用, 分 隔 13. 声 明 两 个 int 类 型 的 变 量 x y, 并 将 62 97 分 别 赋 值 给 x y, 比 较 x y 的 大 小, 输 出 其 中 的 大 者 14. 将 1 到 1000 之 间 的 奇 数 打 印 出 来 15. 判 断 一 个 数 能 否 同 时 被 3 和 5 整 除 16. 输 入 三 个 数, 找 出 最 大 一 个 数, 并 打 印 出 来 17. 给 出 一 百 分 制 成 绩, 要 求 输 出 成 绩 等 级 A, B, C, D, E 90 分 以 上 为 A,80~89 分 为 B,70~79 分 为 C,60~69 分 为 D,60 分 以 下 为 E 请 输 入 成 绩 :67 D 请 输 入 成 绩 :89 B 请 输 入 成 绩 :56 D 18. 设 计 一 个 程 序, 输 入 一 个 数 字 (0~6), 用 中 文 显 示 星 期 几 请 输 入 数 字 :6 星 期 日 请 输 入 数 字 :2 星 期 三 请 输 入 数 字 :8 错 误 第 62 页

19. 写 一 个 程 序, 要 求 输 入 一 个 数 字, 数 字 中 包 含 5 个 数 位 把 数 字 分 解 成 单 独 的 数 位, 并 打 印 每 一 个 数 位 例 如, 假 定 用 于 键 入 43263 这 个 数 字, 那 么 程 序 应 打 印 结 果 :4 3 2 6 3 20. 某 公 司 计 划 提 高 员 工 工 资, 若 基 本 工 资 大 于 等 于 3000 元, 增 加 工 资 20%; 若 小 于 3000 元 大 于 等 于 2000 元, 则 增 加 工 资 15%; 若 小 于 2000 元 则 增 加 工 资 10% 请 根 据 用 户 输 入 的 基 本 工 资, 计 算 出 增 加 后 的 工 资 请 输 入 员 工 工 资 :3600 现 在 的 工 资 是 :4320 元 请 输 入 员 工 工 资 :2800 现 在 的 工 资 是 :3220 元 请 输 入 员 工 工 资 :1700 现 在 的 工 资 是 :1870 元 21. 设 s=1*2*3*4*5* *n, 求 s 不 大 于 400000 时 最 大 的 n 22. 编 写 程 序, 在 控 制 台 输 出 如 下 图 案 : * ** *** **** * ** *** **** 23. 编 写 一 个 程 序, 说 明 while 和 do/while 的 区 别 24. 使 用 for 语 句 打 印 显 示 下 列 数 字 形 式 :n=4 1 1 2 1 1 2 3 2 1 1 2 3 4 3 2 1 25. 编 程 实 现 求 一 个 十 进 制 数 字 的 二 进 制 形 式 26. 每 位 司 机 都 关 心 车 辆 的 油 耗 情 况 有 位 司 机 记 录 了 自 己 行 使 的 公 里 数, 以 及 每 次 加 油 多 少 升 请 设 计 一 个 程 序, 要 求 输 入 行 使 的 英 里 数, 以 及 每 次 加 了 多 少 升 汽 油 程 序 应 计 算 并 显 示 每 次 加 油 后, 每 升 汽 油 可 供 行 驶 多 少 公 里 程 序 还 应 综 合 所 有 的 输 入, 计 算 并 第 63 页

输 出 每 升 汽 油 可 以 供 行 驶 多 少 公 里 输 出 结 果 如 下 : 请 输 入 加 油 量 :30 请 输 入 公 里 数 :300 结 果 : 每 升 油 行 使 10 公 里 平 均 : 每 升 油 行 使 10 公 里 请 输 入 加 油 量 :20 请 输 入 公 里 数 :210 结 果 : 每 升 油 行 使 10.5 公 里 平 均 : 每 升 油 行 使 10.2 公 里 请 输 入 加 油 量 :10 请 输 入 公 里 数 :110 结 果 : 每 升 油 行 使 11 公 里 平 均 : 每 升 油 行 使 10.33 公 里 27. 一 家 大 型 化 工 厂 采 用 佣 金 方 式 为 推 销 员 父 薪 酬 推 销 员 每 月 领 到 基 本 工 资 900 元, 再 加 上 一 周 销 售 毛 利 的 9% 例 如, 一 名 推 销 员 在 某 一 周 销 售 了 毛 利 为 5000 元 的 化 工 产 品, 那 么 除 了 领 取 固 定 的 900 元 之 外, 还 要 加 上 5000 元 的 9%, 总 计 1350 元 开 发 一 个 程 序, 用 于 输 入 推 销 员 上 一 周 的 毛 利, 然 后 计 算 并 显 示 那 名 推 销 员 的 收 入 请 输 入 推 销 员 上 一 周 的 毛 利 :6000 推 销 员 的 收 入 是 :1440 元 请 输 入 推 销 员 上 一 周 的 毛 利 :7000 推 销 员 的 收 入 是 :1530 元 请 输 入 推 销 员 上 一 周 的 毛 利 :8000 推 销 员 的 收 入 是 :1620 元 28. 开 发 一 个 程 序, 计 算 每 名 员 工 的 薪 水 公 司 规 定, 每 周 每 名 员 工 在 其 工 作 的 前 40 个 小 时 内, 每 小 时 都 领 取 固 定 工 资 60 元 超 出 40 小 时 后, 每 工 作 一 小 时, 算 一 个 半 小 时 你 的 程 序 根 据 输 入 的 小 时 数, 计 算 并 显 示 员 工 上 一 周 的 薪 水 总 额 第 64 页

员 工 上 周 工 作 总 时 间 是 :45 员 工 上 周 的 薪 水 是 :2850 元 员 工 上 周 工 作 总 时 间 是 :50 员 工 上 周 的 薪 水 是 :3300 元 员 工 上 周 工 作 总 时 间 是 :55 员 工 上 周 的 薪 水 是 :3750 元 29. 企 业 发 放 的 奖 金 根 据 利 润 提 成 利 润 (I) 低 于 或 等 于 10 万 元 时, 奖 金 可 提 10%; 利 润 高 于 10 万 元, 低 于 20 万 元 时, 低 于 10 万 元 的 部 分 按 10% 提 成, 高 于 10 万 元 的 部 分, 可 可 提 成 7.5%;20 万 到 40 万 之 间 时, 高 于 20 万 元 的 部 分, 可 提 成 5%;40 万 到 60 万 之 间 时 高 于 40 万 元 的 部 分, 可 提 成 3%;60 万 到 100 万 之 间 时, 高 于 60 万 元 的 部 分, 可 提 成 1.5%, 高 于 100 万 元 时, 超 过 100 万 元 的 部 分 按 1% 提 成, 从 键 盘 输 入 当 月 利 润 I, 求 应 发 放 奖 金 总 数? 第 65 页

3 Java 类 和 对 象 3.1 理 解 面 向 对 象 3.1.1 为 什 么 要 面 向 对 象 传 统 的 开 发 方 法 是 面 向 过 程 的, 面 向 过 程 是 一 种 以 事 件 为 中 心 的 编 程 思 想 就 是 分 析 出 解 决 问 题 所 需 要 的 步 骤, 然 后 用 函 数 把 这 些 步 骤 一 步 一 步 实 现, 使 用 的 时 候 一 个 一 个 依 次 调 用 就 可 以 了 面 向 过 程 其 实 是 最 为 实 际 的 一 种 思 考 方 式, 就 是 算 面 向 对 象 的 方 法 也 是 含 有 面 向 过 程 的 思 想, 可 以 说 面 向 过 程 是 一 种 基 础 的 方 法, 它 考 虑 的 是 实 际 的 实 现 一 般 的 面 向 过 程 是 从 上 往 下 步 步 求 精, 当 程 序 规 模 不 是 很 大 时, 面 向 过 程 的 方 法 还 会 体 现 出 一 种 优 势, 因 为 程 序 的 流 程 会 很 清 楚 比 如 拿 学 生 早 上 做 的 事 情 来 说 说 这 种 面 向 过 程, 粗 略 的 可 以 将 过 程 拟 为 : (1) 起 床 (2) 穿 衣 (3) 洗 脸 刷 牙 (4) 去 学 校 这 4 步 就 是 一 步 一 步 的 完 成, 它 的 顺 序 很 重 要, 你 只 须 一 个 一 个 的 实 现 就 行 了 面 向 过 程 开 发 具 有 如 下 缺 点 : 软 件 重 用 性 差 重 用 性 是 指 同 一 事 物 不 经 修 改 或 稍 加 修 改 就 可 多 次 重 复 使 用 的 性 质 软 件 重 用 性 是 软 件 工 程 追 求 的 目 标 之 一 软 件 可 维 护 性 差 软 件 工 程 强 调 软 件 的 可 维 护 性, 强 调 文 档 资 料 的 重 要 性, 规 定 最 终 的 软 件 产 品 应 该 由 完 整 一 致 的 配 置 成 分 组 成 在 软 件 开 发 过 程 中, 始 终 强 调 软 件 的 可 读 性 可 修 改 性 和 可 测 试 性 是 软 件 的 重 要 的 质 量 指 标 实 践 证 明, 用 传 统 方 法 开 发 出 来 的 软 件, 维 护 时 其 费 用 和 成 本 仍 然 很 高, 其 原 因 是 可 修 改 性 差, 维 护 困 难, 导 致 可 维 护 性 差 开 发 出 的 软 件 不 能 满 足 用 户 需 要 用 传 统 的 结 构 化 方 法 开 发 大 型 软 件 系 统 涉 及 各 种 不 同 领 域 的 知 识, 在 开 发 需 求 模 糊 或 需 求 动 态 变 化 的 系 统 时, 所 开 发 出 的 软 件 系 统 往 往 不 能 真 正 满 足 用 户 的 需 要, 用 户 需 求 的 变 化 往 往 造 成 系 统 结 构 的 较 大 变 化, 从 而 需 要 花 费 很 大 代 价 才 能 实 现 这 种 变 化 面 向 对 象 (Object-Oriented, 简 称 OO) 是 一 种 以 事 物 为 中 心 的 编 程 思 想 对 象 是 真 实 世 界 中 的 事 物 在 人 脑 中 的 映 象 在 实 际 生 活 中, 我 们 每 时 每 刻 都 与 对 象 在 打 交 道, 我 们 用 的 钢 笔, 骑 的 自 行 车, 乘 坐 的 公 共 汽 车 等 都 是 对 象 这 些 对 象 是 能 看 得 见 摸 得 着, 第 66 页

实 际 存 在 的 东 西, 我 们 称 之 为 实 体 对 象 ; 有 的 对 象 是 针 对 非 具 体 物 体 的, 但 是 在 逻 辑 关 系 上 的 反 映, 比 如 : 钢 笔 与 墨 水 的 关 系, 人 与 自 行 车 的 关 系, 我 们 称 之 为 逻 辑 对 象 如 果 是 用 面 向 对 象 的 方 法 来 模 拟 学 生 早 上 做 的 事 情 可 以 抽 象 出 一 个 学 生 的 类, 它 包 括 四 个 方 法, 但 是 具 体 的 顺 序 就 不 能 体 现 出 来 根 据 类 创 建 一 个 对 象, 再 调 用 对 象 的 方 法, 在 调 用 方 法 时 体 现 出 顺 序 张 三 起 床 张 三 穿 衣 服 张 三 洗 脸 刷 牙 张 三 去 学 校 基 于 对 象 的 编 程 更 符 合 人 的 思 维 模 式, 编 写 的 程 序 更 加 健 壮 和 强 大, 更 重 要 的 是, 面 向 对 象 编 程 鼓 励 创 造 性 的 程 序 设 计 3.1.2 对 象 的 基 本 构 成 现 实 中 的 人 是 一 个 实 体 对 象, 分 析 实 体 对 象 的 构 成, 发 现 有 这 样 一 些 共 同 点, 这 些 实 体 对 象 都 有 自 己 的 状 态 描 述, 比 如 : 人 有 姓 名 身 高 体 重 发 型 着 装 等, 有 了 这 些 描 述, 我 们 可 以 想 象 出 一 个 人 的 样 子 我 们 把 这 些 描 述 称 之 为 属 性, 属 性 是 静 态 的, 这 些 属 性 用 来 决 定 了 对 象 的 具 体 表 现 形 式 除 了 这 些 静 态 的, 实 体 对 象 还 有 自 己 的 动 作, 通 过 这 些 动 作 能 够 完 成 一 定 的 功 能, 我 们 称 之 为 方 法, 比 如 : 人 能 写 字, 能 刷 牙, 能 跑 步, 打 篮 球, 踢 足 球 等 我 们 知 道 了 对 象 的 方 法, 也 就 知 道 了 这 个 对 象 可 以 做 什 么, 有 什 么 用 依 照 这 个 理 论 我 们 再 分 析 一 下 汽 车, 首 先 想 到 的 是 静 态 的 属 性, 有 颜 色 车 牌 号 标 志 发 动 机 的 功 率 乘 载 人 数 自 重 轮 子 数 目 等 等 然 后 是 动 态 的 功 能 : 加 速 减 速 刹 车 转 弯 等 等 总 之 一 句 话, 对 象 同 时 具 备 静 态 的 属 性 和 动 态 的 功 能 3.1.3 如 何 进 行 对 象 抽 象 抽 象 是 在 思 想 上 把 各 种 对 象 或 现 象 之 间 的 共 同 的 本 质 属 性 抽 取 出 来, 而 舍 去 个 别 的 非 本 质 的 属 性 的 思 维 方 法 也 就 是 说 把 一 系 列 相 同 或 类 似 的 实 体 对 象 的 特 点 抽 取 出 来, 采 用 一 个 统 一 的 表 达 方 式, 这 就 是 抽 象 述 : 比 如 : 张 三 这 个 人 身 高 180cm, 体 重 75kg, 会 打 篮 球, 会 跑 步 李 四 这 个 人 身 高 170cm, 体 重 70kg, 会 打 篮 球, 会 跑 步 现 在 想 要 采 用 一 个 统 一 的 类 来 描 述 张 三 和 李 四, 那 么 我 们 就 可 以 采 用 如 下 的 表 述 方 法 来 表 人 { 静 态 属 性 : 姓 名 ; 身 高 ; 第 67 页

体 重 ; 动 态 动 作 : 打 篮 球 (); 跑 步 (); 3.1.4 Java 中 的 类 和 对 象 3.1.4.1 Java 中 的 类 把 抽 象 出 来 的 类 型 使 用 Java 表 达 出 来, 那 就 是 类 class 类 是 对 具 有 相 似 性 质 的 一 类 事 物 的 抽 象, 类 封 装 了 一 类 对 象 的 属 性 和 方 法 实 例 化 一 个 类, 可 以 获 得 属 于 该 类 的 一 个 实 例 ( 即 对 象 ) 类 在 Java 编 程 语 言 中 作 为 定 义 新 类 型 的 一 种 途 径, 类 是 组 成 Java 程 序 的 基 本 要 素 类 声 明 可 定 义 新 类 型 并 描 述 这 些 类 型 是 如 何 实 现 的 比 如 前 面 讨 论 过 的 人 汽 车, 使 用 Java 表 达 出 来 就 是 一 个 类 3.1.4.2 Java 中 的 对 象 样 对 象 是 类 的 一 个 实 例, 类 的 具 体 化, 也 称 实 例 对 象 实 例 就 是 实 际 例 子, 就 好 像 真 实 存 在 一 类 可 被 认 为 是 一 个 模 板 --- 你 正 在 描 述 的 一 个 对 象 模 型 一 个 对 象 就 是 你 每 次 使 用 的 时 候 创 建 的 一 个 类 的 实 例 的 结 果 比 如 前 面 讨 论 的 张 三 和 李 四, 他 们 就 是 通 过 人 这 个 类 的 创 建 出 来 的 实 例, 这 样 就 在 计 算 机 内 存 中, 把 现 实 中 的 张 三 李 四 表 达 出 来 了, 就 像 张 三 李 四 已 经 活 在 计 算 机 的 内 存 中 了 3.2 如 何 使 用 一 个 Java 类 前 面 学 习 了 如 何 定 义 一 个 类, 下 面 来 学 习 如 何 使 用 一 个 类 3.2.1 new 关 键 字 假 如 定 义 了 一 个 表 示 日 期 的 类, 有 三 个 整 数 变 量 ; 日 月 和 年 的 意 义 即 由 这 些 整 数 变 量 给 出 如 下 所 示 : class MyDate { int day; 第 68 页

int month; int year; public String tostring() { int num=0; return day+","+month+","+year; 名 称 MyDate 按 照 类 声 明 的 大 小 写 约 定 处 理, 而 不 是 由 语 意 要 求 来 定 在 可 以 使 用 变 量 之 前, 实 际 内 存 必 须 被 分 配 这 个 工 作 是 通 过 使 用 关 键 字 new 来 实 现 的 如 下 所 示 : MyDate mybirth; mybirth = new MyDate() 第 一 个 语 句 ( 声 明 ) 仅 为 引 用 分 配 了 足 够 的 空 间, 而 第 二 个 语 句 则 通 过 调 用 对 象 的 构 造 方 法 为 构 成 MyDate 的 三 个 整 数 分 配 了 空 间 对 象 的 赋 值 使 变 量 mybirth 重 新 正 确 地 引 用 新 的 对 象 这 两 个 操 作 被 完 成 后,MyDate 对 象 的 内 容 则 可 通 过 mybirth 进 行 访 问 关 键 字 new 意 味 着 内 存 的 分 配 和 初 始 化,new 调 用 的 方 法 就 是 类 的 构 造 方 法 假 使 定 义 任 意 一 个 class XXXX, 可 以 调 用 new XXXX() 来 创 建 任 意 多 的 对 象, 对 象 之 间 是 分 隔 的 就 像 有 一 个 汽 车 的 类, 可 以 使 用 new 关 键 字 创 建 多 个 具 体 的 对 象, 比 如 有 红 旗 的 汽 车 奇 瑞 的 汽 车 大 众 的 汽 车 等 等, 它 们 都 是 独 立 的 单 元, 相 互 之 间 是 隔 离 的 一 个 对 象 的 引 用 可 被 存 储 在 一 个 变 量 里, 因 而 一 个 变 量 点 成 员 ( 如 mybirth.day) 可 用 来 访 问 每 个 对 象 的 单 个 成 员 请 注 意 在 没 有 对 象 引 用 的 情 况 下, 仍 有 可 能 使 用 对 象, 这 样 的 对 象 称 作 匿 名 对 象 使 用 一 个 语 句 同 时 为 引 用 mybirth 和 由 引 用 mybirth 所 指 的 对 象 分 配 空 间 也 是 可 能 的 MyDate mybirth = new MyDate(); mybirth 栈 内 存 0x1fb8ee3 day month year 堆 内 存 0 0 0 3.2.2 使 用 对 象 中 的 属 性 和 方 法 要 调 用 对 象 中 的 属 性 和 方 法, 使 用. 操 作 符 对 象 创 建 以 后 就 有 了 自 己 的 属 性, 通 过 使 用. 操 作 符 实 现 对 其 属 性 的 访 问 例 如 : mybirth.day = 26; mybirth.month = 7; mybirth.year = 2000; 第 69 页

对 象 创 建 以 后, 通 过 使 用. 操 作 符 实 现 对 其 方 法 的 调 用, 方 法 中 的 局 部 变 量 被 分 配 内 存 空 间, 方 法 执 行 完 毕, 局 部 变 量 即 刻 释 放 内 存 例 如 : mybirth.tostring(); 3.3 Java 类 的 基 本 构 成 一 个 完 整 的 Java 类 通 常 由 下 面 六 个 部 分 组 成 : 包 定 义 语 句 import 语 句 类 定 义 { 成 员 变 量 构 造 方 法 成 员 方 法 其 中 : 只 有 类 定 义 和 { 是 不 可 或 缺 的, 其 余 部 分 都 可 以 根 据 需 要 来 定 义 下 面 分 别 来 学 习 各 个 部 分 的 基 本 规 则, 看 看 如 何 写 Java 的 类, 建 议 初 学 者, 先 看 类 成 员 变 量 方 法 部 分, 再 看 包 import 部 分 3.3.1 包 3.3.1.1 什 么 是 包 计 算 机 操 作 系 统 使 用 文 件 夹 或 者 目 录 来 存 放 相 关 或 者 同 类 的 文 档, 在 Java 编 程 语 言 中, 提 供 了 一 个 包 的 概 念 来 组 织 相 关 的 类 包 在 物 理 上 就 是 一 个 文 件 夹, 逻 辑 上 代 表 一 个 分 类 概 念 包 是 类 接 口 或 其 它 包 的 集 合, 包 对 类 进 行 有 效 管 理 的 机 制 包 对 于 下 列 工 作 非 常 有 用 : 包 将 包 含 类 代 码 的 文 件 组 织 起 来, 易 于 查 找 和 使 用 适 当 的 类 包 不 止 是 包 含 类 和 接 口, 还 能 够 包 含 其 它 包 形 成 层 次 的 包 空 间 有 助 于 避 免 命 名 冲 突 当 使 用 很 多 类 时, 确 保 类 和 方 法 名 称 的 唯 一 性 是 非 常 困 难 的 包 能 够 形 成 层 次 命 名 空 间, 缩 小 了 名 称 冲 突 的 范 围, 易 于 管 理 名 称 控 制 代 码 访 问 权 限 为 便 于 管 理 数 目 众 多 的 类,Java 语 言 中 引 入 了 包 的 概 念, 可 以 说 是 对 定 义 的 Java 类 进 行 分 组, 将 多 个 功 能 相 关 的 类 定 义 到 一 个 包 中, 以 解 决 命 名 冲 突 引 用 不 方 便 安 全 性 等 问 题 比 如 户 籍 制 度, 每 个 公 民 除 有 自 己 的 名 字 张 三 李 四 外 还 被 规 定 了 他 的 户 籍 地 假 定 有 两 个 人 都 叫 张 三, 只 称 呼 名 字 就 无 法 区 分 他 们, 但 如 果 事 先 登 记 他 们 的 户 籍 分 别 在 北 京 和 上 海, 就 可 以 很 容 易 的 用 北 京 的 张 三 上 海 的 张 三 将 他 们 区 分 开 来 如 果 北 京 市 仍 有 多 个 张 三, 还 可 以 细 分 为 北 京 市. 海 淀 区 的 张 三 北 京 市. 西 城 区. 平 安 大 街 的 张 三 等 等, 直 到 能 惟 一 标 识 每 个 张 三 为 止 第 70 页

3.3.1.2 JDK 中 常 用 的 包 JDK 中 定 义 的 类 就 采 用 了 包 机 制 进 行 层 次 式 管 理, 简 而 言 之 : 从 逻 辑 上 讲, 包 是 一 组 相 关 类 的 集 合 ; 从 物 理 上 讲, 同 包 即 同 目 录 java.lang---- 包 含 一 些 Java 语 言 的 核 心 类, 包 含 构 成 Java 语 言 设 计 基 础 的 类 在 此 包 中 定 义 的 最 重 要 的 一 个 类 是 Object, 代 表 类 层 次 的 根,Java 是 一 个 单 根 系 统, 最 终 的 根 就 是 Object java.awt---- 包 含 了 构 成 抽 象 窗 口 工 具 集 (abstract window toolkits) 的 多 个 类, 这 些 类 被 用 来 构 建 和 管 理 应 用 程 序 的 图 形 用 户 界 面 (GUI) javax.swing---- 完 全 Java 版 的 图 形 用 户 界 面 (GUI) 解 决 方 案, 提 供 了 很 多 完 备 的 组 件, 可 以 应 对 复 杂 的 桌 面 系 统 构 建 等 java.net---- 包 含 执 行 与 网 络 相 关 的 操 作 的 类, 如 URL, Socket, ServerSocket java.io---- 包 含 能 提 供 多 种 输 入 / 输 出 功 能 的 类 java.util---- 包 含 一 些 实 用 工 具 类, 如 定 义 系 统 特 性 使 用 与 日 期 日 历 相 关 的 方 法 还 有 重 要 的 集 合 框 架 3.3.1.3 代 码 中 如 何 表 达 包 Java 语 言 使 用 package 语 句 来 实 现 包 的 定 义 package 语 句 必 须 作 为 Java 源 文 件 的 非 注 释 语 句 第 一 条 语 句, 指 明 该 文 件 中 定 义 的 类 所 在 的 包 若 缺 省 该 语 句, 则 指 定 为 无 名 包, 其 语 法 格 式 为 : package pkg1[.pkg2[.pkg3 ]]; // [] 表 示 可 选 Java 编 译 器 把 包 对 应 于 文 件 系 统 的 目 录 管 理, 因 此 包 也 可 以 嵌 套 使 用, 即 一 个 包 中 可 以 含 有 类 的 定 义 也 可 以 含 有 子 包, 其 嵌 套 层 数 没 有 限 制 package 语 句 中, 用. 来 指 明 包 的 层 次 程 序 中 package 的 使 用 :Test.java package p1; public class Test { public void display() { System.out.println("in method display()"); Java 语 言 要 求 包 声 明 的 层 次 和 实 际 保 存 类 的 字 节 码 文 件 的 目 录 结 构 存 在 对 应 关 系, 以 便 将 来 使 用 该 类 时 能 通 过 包 名 ( 也 就 是 目 录 名 ) 查 找 到 所 需 要 的 类 文 件 简 单 地 说 就 是 包 的 层 次 结 构 第 71 页

需 要 和 文 件 夹 的 层 次 对 应 注 意 : 每 个 源 文 件 只 有 一 个 包 的 声 明, 而 且 包 名 应 该 全 部 小 写 3.3.1.4 编 译 和 生 成 包 如 果 在 程 序 Test.java 中 已 定 义 了 包 p1, 就 必 须 将 编 译 生 成 的 字 节 码 文 件 Test.class 保 存 在 与 包 名 同 名 的 子 目 录 中, 可 以 选 用 下 述 两 种 方 式 之 一 : 直 接 编 译 : javac Test.java 则 编 译 器 会 在 当 前 目 录 下 生 成 Test.class 文 件, 再 在 手 动 创 建 一 个 名 为 p1 的 文 件 夹, 将 Test.class 复 制 到 该 p1 目 录 下 带 包 编 译 : 带 包 编 译 是 简 化 的 编 译 命 令 javac -d.\ Test.java 编 译 器 会 自 动 在 当 前 目 录 下 建 立 一 个 子 目 录 p1, 并 将 生 成 的.class 文 件 自 动 保 存 到 p1 文 件 夹 下 javac -d.\test\ Test.java 编 译 器 会 自 动 在 当 前 目 录 下 的 test 文 件 夹 中 建 立 一 个 子 目 录 p1, 并 将 生 成 的.class 文 件 自 动 保 存 到 p1 文 件 夹 下 前 提 是 当 前 目 录 下 必 须 有 test 文 件 夹, 否 则 报 错 : 未 找 到 目 录 :.\test\ javac -d D:\test\ Test.java 编 译 器 会 自 动 在 D 盘 根 目 录 下 的 test 文 件 夹 中 建 立 一 个 子 目 录 p1, 并 将 生 成 的.class 文 件 自 动 保 存 到 p1 文 件 夹 下 前 提 是 D 盘 根 目 录 下 必 须 有 test 文 件 夹, 否 则 报 错 : 未 找 到 目 录 :D:\test\ 3.3.1.5 带 包 运 行 运 行 带 包 的 程 序, 需 要 使 用 类 的 全 路 径, 也 就 是 带 包 的 路 径, 比 如 上 面 的 那 个 程 序, 就 使 用 如 下 的 代 码 进 行 运 行 : java p1.test 3.3.2 import 语 句 3.3.2.1 用 法 为 了 能 够 使 用 某 一 个 包 的 成 员, 我 们 需 要 在 Java 程 序 中 明 确 导 入 该 包 使 用 import 语 句 可 完 成 此 功 能 在 java 源 文 件 中 import 语 句 应 位 于 package 语 句 之 后, 所 有 类 的 定 义 之 前, 可 以 没 有, 也 可 以 有 多 条, 其 语 法 格 式 为 : 第 72 页

import package1[.package2 ].(classname *); java 运 行 时 环 境 将 到 CLASSPATH + package1.[package2 ] 路 径 下 寻 找 并 载 入 相 应 的 字 节 码 文 件 classname.class * 号 为 通 配 符, 代 表 所 有 的 类 也 就 是 说 import 语 句 为 编 译 器 指 明 了 寻 找 类 的 途 径 例, 使 用 import 语 句 引 入 类 程 序 :TestPackage.java import p1.test; // 或 者 import p1.*; public class TestPackage { public static void main(string args[]) { Test t = new Test(); // Test 类 在 p1 包 中 定 义 t.display(); java 编 译 器 默 认 为 所 有 的 java 程 序 引 入 了 JDK 的 java.lang 包 中 所 有 的 类 (import java.lang.*;), 其 中 定 义 了 一 些 常 用 类 :System String Object Math 等 因 此 我 们 可 以 直 接 使 用 这 些 类 而 不 必 显 式 引 入 但 使 用 其 它 非 无 名 包 中 的 类 则 必 须 先 引 入 后 使 用 3.3.3 访 问 修 饰 符 Java 语 言 允 许 对 类 中 定 义 的 各 种 属 性 和 方 法 进 行 访 问 控 制, 即 规 定 不 同 的 保 护 等 级 来 限 制 对 它 们 的 使 用 为 什 么 要 这 样 做?Java 语 言 引 入 类 似 访 问 控 制 机 制 的 目 的 在 于 实 现 信 息 的 封 装 和 隐 藏 Java 语 言 为 对 类 中 的 属 性 和 方 法 进 行 有 效 地 访 问 控 制, 将 它 们 分 为 四 个 等 级 : private 无 修 饰 符 protected public, 具 体 规 则 如 下 : 变 量 和 方 法 可 以 使 用 四 个 访 问 级 别 中 的 任 意 一 个 修 饰, 类 可 以 使 用 公 共 或 无 修 饰 级 别 修 饰 变 量 方 法 或 类 有 缺 省 ( 无 修 饰 符 ) 访 问 性, 如 果 它 没 有 显 式 受 保 护 修 饰 符 作 为 它 的 声 明 的 一 部 分 的 话 这 种 访 问 性 意 味 着, 访 问 可 以 来 自 任 何 方 法, 当 然 这 些 方 法 只 能 在 作 为 对 象 的 同 一 个 包 中 的 成 员 类 当 中 以 修 饰 符 protected 标 记 的 变 量 或 方 法 实 际 上 比 以 缺 省 访 问 控 制 标 记 的 更 易 访 问 一 个 protected 方 法 或 变 量 可 以 从 同 一 个 包 中 的 类 当 中 的 任 何 方 法 进 行 访 问, 也 可 以 是 从 任 何 子 类 第 73 页

中 的 任 何 方 法 进 行 访 问 当 它 适 合 于 一 个 类 的 子 类 但 不 是 不 相 关 的 类 时, 就 可 以 使 用 这 种 受 保 护 访 问 来 访 问 成 员 3.3.4 类 定 义 Java 程 序 的 基 本 单 位 是 类, 你 建 立 类 之 后, 就 可 用 它 来 建 立 许 多 你 需 要 的 对 象 Java 把 每 一 个 可 执 行 的 成 分 都 变 成 类 类 的 定 义 形 式 如 下 : < 权 限 修 饰 符 > [ 一 般 修 饰 符 ] class < 类 名 > [extends 父 类 ][implements 接 口 ]{ [< 属 性 定 义 >] [< 构 造 方 法 定 义 >] [< 方 法 定 义 >] 这 里, 类 名 要 是 合 法 的 标 识 符 在 类 定 义 的 开 始 与 结 束 处 必 须 使 用 花 括 号 你 也 许 想 建 立 一 个 矩 形 类, 那 么 可 以 用 如 下 代 码 : public class Rectangle{...// 矩 形 具 体 的 属 性 和 方 法 3.3.5 构 造 方 法 什 么 是 构 造 方 法 类 有 一 个 特 殊 的 成 员 方 法 叫 作 构 造 方 法, 它 的 作 用 是 创 建 对 象 并 初 始 化 成 员 变 量 在 创 建 对 象 时, 会 自 动 调 用 类 的 构 造 方 法 构 造 方 法 定 义 规 则 Java 中 的 构 造 方 法 必 须 与 该 类 具 有 相 同 的 名 字, 并 且 没 有 方 法 的 返 回 类 型 ( 包 括 没 有 void) 另 外, 构 造 方 法 一 般 都 应 用 public 类 型 来 说 明, 这 样 才 能 在 程 序 任 意 的 位 置 创 建 类 的 实 例 -- 对 象 下 面 是 一 个 Rectangle 类 的 构 造 方 法, 它 带 有 两 个 参 数, 分 别 表 示 矩 形 的 长 和 宽 : public class Rectangle { int width; int height; public Rectangle(int w, int h) { width = w; height = h; public Rectangle() { 第 74 页

每 个 类 至 少 有 一 个 构 造 方 法 如 果 不 写 一 个 构 造 方 法,Java 编 程 语 言 将 提 供 一 个 默 认 的, 该 构 造 方 法 没 有 参 数, 而 且 方 法 体 为 空 注 意 : 如 果 一 个 类 中 已 经 定 义 了 构 造 方 法 则 系 统 不 再 提 供 默 认 的 构 造 方 法 3.3.6 析 构 方 法 ( 选 修 ) 当 垃 圾 回 收 器 将 要 释 放 无 用 对 象 的 内 存 时, 先 调 用 该 对 象 的 finalize() 方 法 如 果 在 程 序 终 止 前 垃 圾 回 收 器 始 终 没 有 执 行 垃 圾 回 收 操 作, 那 么 垃 圾 回 收 器 将 始 终 不 会 调 用 无 用 对 象 的 finalize() 方 法 在 Java 的 Object 基 类 中 提 供 了 protected 类 型 的 finalize() 方 法, 因 此 任 何 Java 类 都 可 以 覆 盖 finalize() 方 法, 通 常, 在 析 构 方 法 中 进 行 释 放 对 象 占 用 的 相 关 资 源 的 操 作 Java 虚 拟 机 的 垃 圾 回 收 操 作 对 程 序 完 全 是 透 明 的, 因 此 程 序 无 法 预 料 某 个 无 用 对 象 的 finalize() 方 法 何 时 被 调 用 如 果 一 个 程 序 只 占 用 少 量 内 存, 没 有 造 成 严 重 的 内 存 需 求, 垃 圾 回 收 器 可 能 没 有 释 放 那 些 无 用 对 象 占 用 的 内 存, 因 此 这 些 对 象 的 finalize() 方 法 还 没 有 被 调 用, 程 序 就 终 止 了 程 序 即 使 显 式 调 用 System.gc() 或 Runtime.gc() 方 法, 也 不 能 保 证 垃 圾 回 收 操 作 一 定 执 行, 也 就 不 能 保 证 对 象 的 finalize() 方 法 一 定 被 调 用 当 垃 圾 回 收 器 在 执 行 finalize() 方 法 的 时 候, 如 果 出 现 了 异 常, 垃 圾 回 收 器 不 会 报 告 异 常, 程 序 继 续 正 常 运 行 @Override protected void finalize(){ System.out.println("in finalize"); 在 Java 编 程 里 面, 一 般 不 需 要 我 们 去 写 析 构 方 法, 这 里 只 是 了 解 一 下 就 可 以 了 3.3.7 成 员 变 量 成 员 变 量 是 指 类 的 一 些 属 性 定 义, 标 志 类 的 静 态 特 征, 它 的 基 本 格 式 如 下 : < 权 限 修 饰 符 > [ 一 般 修 饰 符 ] 类 型 < 属 性 名 称 > [= 初 始 值 ]; 访 问 修 饰 符 : 可 以 使 用 四 种 不 同 的 访 问 修 饰 符 中 的 一 种, 包 括 public( 公 共 的 ) protected( 受 保 护 的 ), 无 修 饰 符 和 private( 私 有 的 ) public 访 问 修 饰 符 表 示 属 性 可 以 从 任 何 其 它 代 码 调 用 private 表 示 属 性 只 可 以 由 该 类 中 的 其 它 方 法 来 调 用 protected 将 在 以 后 的 课 程 中 讨 论 修 饰 符 : 是 对 属 性 特 性 的 描 述, 例 如 后 面 会 学 习 到 的 :static final 等 等 类 型 : 属 性 的 数 据 类 型, 可 以 是 任 意 的 类 型 第 75 页

属 性 名 称 : 任 何 合 法 标 识 符 初 始 值 : 赋 值 给 属 性 的 初 始 值 如 果 不 设 置, 那 么 会 自 动 进 行 初 始 化, 基 本 类 型 使 用 缺 省 值, 对 象 类 型 自 动 初 始 化 为 null 成 员 变 量 有 时 候 也 被 称 为 属 性 实 例 变 量 3.3.8 方 法 3.3.8.1 定 义 方 法 就 是 对 象 所 具 有 的 动 态 功 能 Java 类 中 方 法 的 声 明 采 用 以 下 格 式 : < 权 限 修 饰 符 > [ 修 饰 符 ] 返 回 值 类 型 < 方 法 名 称 > ( 参 数 列 表 ) [throws 异 常 列 表 ]{ [ 方 法 体 ] 访 问 修 饰 符 : 可 以 使 用 四 种 不 同 的 访 问 修 饰 符 中 的 一 种, 包 括 public protected 无 修 饰 符 和 private public 访 问 修 饰 符 表 示 方 法 可 以 从 任 何 其 它 代 码 调 用 private 表 示 方 法 只 可 以 由 该 类 中 的 其 它 方 法 来 调 用 protected 将 在 以 后 的 课 程 中 讨 论 修 饰 符 : 是 对 方 法 特 性 的 描 述, 例 如 后 面 会 学 习 到 的 :static final abstract synchronized 等 等 返 回 值 类 型 : 表 示 方 法 返 回 值 的 类 型 如 果 方 法 不 返 回 任 何 值, 它 必 须 声 明 为 void( 空 ) Java 技 术 对 返 回 值 是 很 严 格 的, 例 如, 如 果 声 明 某 方 法 返 回 一 个 int 值, 那 么 方 法 必 须 从 所 有 可 能 的 返 回 路 径 中 返 回 一 个 int 值 ( 只 能 在 等 待 返 回 该 int 值 的 上 下 文 中 被 调 用 ) 方 法 名 称 : 可 以 是 任 何 合 法 标 识 符, 并 带 有 用 已 经 使 用 的 名 称 为 基 础 的 某 些 限 制 条 件 参 数 列 表 : 允 许 将 参 数 值 传 递 到 方 法 中 列 举 的 元 素 由 逗 号 分 开, 而 每 一 个 元 素 包 含 一 个 类 型 和 一 个 标 识 符 在 下 面 的 方 法 中 只 有 一 个 形 式 参 数, 用 int 类 型 和 标 识 符 days 来 声 明 : public void test(int days){ throws 异 常 列 表 : 子 句 导 致 一 个 运 行 时 错 误 ( 异 常 ) 被 报 告 到 调 用 的 方 法 中, 以 便 以 合 适 的 方 式 处 理 它 异 常 在 后 面 的 课 程 中 介 绍 花 括 号 内 是 方 法 体, 即 方 法 的 具 体 语 句 序 列 3.3.8.2 示 例 比 如 现 在 有 一 个 车 的 类 Car, 车 具 有 一 些 基 本 的 属 性, 比 如 四 个 轮 子, 一 个 方 向 盘, 车 的 品 牌 等 等 当 然, 车 也 具 有 自 己 的 功 能, 也 就 是 方 法, 比 如 车 能 够 开 动 run 要 想 车 子 能 够 开 动, 需 要 给 车 子 添 加 汽 油, 也 就 是 说, 需 要 为 run 方 法 传 递 一 些 参 数 油 进 去 车 子 就 可 以 跑 起 来, 这 些 油 可 以 供 行 驶 多 少 公 里? 就 需 要 run 方 法 具 有 返 回 值 行 驶 里 程 数 第 76 页

package com.javakc; public class Car {// 车 这 个 类 private String make;// 一 个 车 的 品 牌 private int tyre;// 一 个 车 具 有 轮 胎 的 个 数 private int wheel;// 一 个 车 具 有 方 向 盘 的 个 数 public Car() { // 初 始 化 属 性 make = "BMW";// 车 的 品 牌 是 宝 马 tyre = 4;// 一 个 车 具 有 4 个 轮 胎 wheel = 1;// 一 个 车 具 有 一 个 方 向 盘 /** * 车 这 个 对 象 所 具 有 的 功 能, 能 够 开 动 * * @param oil 为 车 辆 加 汽 油 的 数 量 * @return 车 辆 行 驶 的 公 里 数 */ public double run(int oil) { // 进 行 具 体 的 功 能 处 理 return 100*oil/8; public static void main(string[] args){ Car c=new Car(); double mileage=c.run(100); System.out.println(" 行 驶 了 "+mileage+" 公 里 "); main 方 法 是 一 个 特 殊 的 方 法, 如 果 按 照 public static void main(string[] args) 的 格 式 写, 它 就 是 一 个 类 的 入 口 方 法, 也 叫 主 函 数 当 这 个 类 被 java 指 令 执 行 的 时 候, 首 先 执 行 的 是 main 方 法, 如 果 一 个 类 没 有 入 口 方 法, 就 不 能 使 用 java 指 令 执 行 它, 但 可 以 通 过 其 他 的 方 法 调 用 它 3.3.8.3 形 参 和 实 参 对 于 方 法 的 参 数 的 理 解, 分 为 形 参 和 实 参 : 形 参 : 就 是 形 式 参 数 的 意 思 是 在 定 义 方 法 的 时 候 使 用 的 参 数, 用 来 标 识 方 法 接 收 的 参 数 类 型, 在 调 用 该 方 法 时 传 入 实 参 : 就 是 实 际 参 数 的 意 思 是 在 调 用 方 法 时 传 递 给 该 方 法 的 实 际 参 数 比 如 : 上 面 的 例 子 中 int oil 就 是 个 形 式 参 数, 这 里 只 是 表 示 需 要 加 入 汽 油, 这 个 方 法 才 能 正 常 运 行, 但 具 体 加 入 多 少, 要 到 真 正 使 用 的 时 候, 也 就 是 调 用 这 个 方 法 的 时 候 才 具 体 确 定, 加 入 调 用 的 时 候 传 入 100, 这 就 是 个 实 际 参 数 形 参 和 实 参 有 如 下 基 本 规 则 : 第 77 页

形 参 和 实 参 的 类 型 必 须 要 一 致, 或 者 要 符 合 隐 含 转 换 规 则 形 参 类 型 不 是 引 用 类 型 时, 在 调 用 该 方 法 时, 是 按 值 传 递 的 在 该 方 法 运 行 时, 形 参 和 实 参 是 不 同 的 变 量, 它 们 在 内 存 中 位 于 不 同 的 位 置, 形 参 将 实 参 的 值 复 制 一 份, 在 该 方 法 运 行 结 束 的 时 候 形 参 被 释 放, 而 实 参 内 容 不 会 改 变 形 参 类 型 是 引 用 类 型 时, 在 调 用 该 方 法 时, 是 按 引 用 传 递 的 运 行 时, 传 给 方 法 的 是 实 参 的 地 址, 在 方 法 体 内 部 使 用 的 也 是 实 参 的 地 址, 即 使 用 的 就 是 实 参 本 身 对 应 的 内 存 空 间 所 以 在 函 数 体 内 部 可 以 改 变 实 参 的 值 3.3.8.4 参 数 可 变 的 方 法 ( 选 修 ) 从 JDK5.0 开 始, 提 供 了 参 数 可 变 的 方 法 当 不 能 确 定 一 个 方 法 的 入 口 参 数 的 个 数 时,5.0 以 前 版 本 的 Java 中, 通 常 的 做 法 是 将 多 个 参 数 放 在 一 个 数 组 或 者 对 象 集 合 中 作 为 参 数 来 传 递,5.0 版 本 以 前 的 写 法 是 : Int sum(integer[] numbers){ // 在 另 一 个 方 法 中 调 用 该 方 法 sum(new Integer[] {12,13,20); 而 在 5.0 版 本 中 可 以 写 为 : // 注 意 : 方 法 定 义 中 是 三 个 点 int sum(integer... numbers){ // 方 法 内 的 操 作 // 调 用 该 方 法 sum(12,13,20);// 正 确 sum(10,11); // 正 确 也 就 是 说, 传 入 参 数 的 个 数 并 不 确 定 但 请 注 意 : 传 入 参 数 的 类 型 必 须 是 一 致 的, 究 其 本 质, 就 是 一 个 数 组 显 然,JDK5.0 版 本 的 写 法 更 为 简 易, 也 更 为 直 观, 尤 其 是 方 法 的 调 用 语 句, 不 仅 简 化 很 多, 而 且 更 符 合 通 常 的 思 维 方 式, 更 易 于 理 解 3.4 this 关 键 字 关 键 字 this 是 用 来 指 向 当 前 对 象 或 类 实 例 的, 功 能 说 明 如 下 : 3.4.1 点 取 属 性 this.day 指 的 是 调 用 当 前 对 象 的 day 字 段, 示 例 如 下 : public class MyDate { private int day, month, year; public void tomorrow() { 第 78 页

this.day = this.day + 1; // 其 他 代 码 Java 编 程 语 言 自 动 将 所 有 实 例 变 量 和 方 法 引 用 与 this 关 键 字 联 系 在 一 起, 因 此,this 可 以 省 略 下 面 的 代 码 与 前 面 的 代 码 是 等 同 的 public class MyDate { private int day, month, year; public void tomorrow() { day = day + 1; // 在 day 前 面 没 有 使 用 this // 其 他 代 码 在 类 属 性 上 定 义 的 变 量 和 方 法 内 部 定 义 的 变 量 相 同 的 时 候, 到 底 是 调 用 谁? 例 如 : public class Test { int i = 2; public void t() { int i = 3; // 跟 属 性 的 变 量 名 称 是 相 同 的 System.out.println(" 实 例 变 量 i=" + this.i); System.out.println(" 方 法 内 部 的 变 量 i=" + i); 也 就 是 说 : this. 变 量 调 用 的 是 当 前 属 性 的 变 量 值, 直 接 使 用 变 量 名 称 调 用 的 是 相 对 距 离 最 近 的 变 量 的 值 3.4.2 调 用 类 中 其 他 方 法 public class Test { public void t() { this.t2(); public void t2() { System.out.println("t2 方 法 "); 3.4.3 作 为 方 法 名 来 初 始 化 对 象 this 用 在 构 造 方 法 中,this() 也 就 是 相 当 于 调 用 本 类 的 其 它 构 造 方 法, 它 必 须 作 为 构 造 方 法 的 第 一 句 示 例 如 下 : 第 79 页

public class Test { public Test() { this(3);// 在 这 里 调 用 本 类 的 另 外 的 构 造 方 法 public Test(int a) { public static void main(string[] args) { Test t = new Test(); 3.5 引 用 类 型 早 些 时 候 的 编 程 语 言 和 初 级 程 序 员 将 每 个 变 量 看 作 相 互 无 关 的 实 体 例 如, 如 果 一 个 程 序 需 处 理 某 个 日 期, 则 要 声 明 三 个 单 独 的 整 数 : int day, month, year; 上 述 语 句 作 了 两 件 事, 一 是 当 程 序 需 要 日 月 或 年 的 有 关 信 息 时, 它 将 操 作 一 个 整 数 ; 二 是 为 那 些 整 数 分 配 存 储 器 尽 管 这 种 作 法 很 容 易 理 解, 但 它 存 在 两 个 重 大 缺 陷 首 先, 如 果 程 序 需 同 时 记 录 几 个 日 期, 则 需 要 三 个 不 同 的 声 明 例 如, 要 记 录 两 个 生 日, 你 可 能 使 用 : int mybirthday, mybirthmonth, mybirthyear; int yourbirthday, yourbirthmonth, yourbirthyear; 这 种 方 法 很 快 就 会 引 起 混 乱, 因 为 需 要 的 名 称 很 多 第 二 个 缺 陷 是 这 种 方 法 忽 视 了 日 月 和 年 之 间 的 联 系 并 把 每 个 变 量 都 作 为 一 个 独 立 的 值, 每 个 变 量 都 是 一 个 独 立 单 元 为 了 解 决 这 个 问 题,Java 引 入 了 引 用 类 型, 允 许 程 序 员 自 己 定 义 类 型 3.5.1 什 么 是 引 用 类 型 引 用 类 型 (reference type) 指 向 一 个 对 象, 不 是 原 始 值, 指 向 对 象 的 变 量 是 引 用 变 量 在 Java 里 面 除 去 基 本 数 据 类 型 的 其 它 类 型 都 是 引 用 数 据 类 型, 自 己 定 义 的 class 类 都 是 引 用 类 型, 可 以 像 基 本 类 型 一 样 使 用 在 Java 程 序 运 行 时, 会 为 引 用 类 型 分 配 一 定 量 的 存 储 空 间 并 解 释 该 存 储 空 间 的 内 容 示 例 如 下 : public class MyDate { private int day = 8; private int month = 8; private int year = 2008; 第 80 页

public MyDate(int day, int month, int year){ public void print(){ public class TestMyDate { public static void main(string args[]) { // 这 个 today 变 量 就 是 一 个 引 用 类 型 的 变 量 MyDate today = new MyDate(23, 7, 2008); 3.5.2 引 用 类 型 的 赋 值 在 Java 编 程 语 言 中, 用 类 的 一 个 类 型 声 明 的 变 量 被 指 定 为 引 用 类 型, 这 是 因 为 它 正 在 引 用 一 个 非 原 始 类 型, 这 对 赋 值 具 有 重 要 的 意 义 请 看 下 列 代 码 片 段 : int x = 7; int y = x; String s = "Hello"; String t = s; 四 个 变 量 被 创 建 : 两 个 原 始 类 型 int 和 两 个 引 用 类 型 String x 的 值 是 7, 而 这 个 值 被 复 制 到 y;x 和 y 是 两 个 独 立 的 变 量 且 其 中 任 何 一 个 的 进 一 步 的 变 化 都 不 对 另 外 一 个 构 成 影 响 至 于 变 量 s 和 t, 只 有 一 个 String 对 象 存 在, 它 包 含 了 文 本 Hello,s 和 t 均 引 用 这 个 单 一 的 对 象 x y s t 7 7 0x1fb8ee3 0x1fb8ee3 Hello 将 变 量 t 重 新 定 义 为 :t= World ; 则 新 的 对 象 World 被 创 建, 而 t 引 用 这 个 对 象 上 述 过 程 被 描 述 如 下 : x y s t 7 7 0x1fb8ee3 0x1fb8f25 Hello World 3.5.3 按 值 传 递 还 是 按 引 用 传 递 这 个 在 Java 里 面 是 经 常 被 提 起 的 问 题, 也 有 一 些 争 论, 似 乎 最 后 还 有 一 个 所 谓 的 结 论 : 在 Java 里 面 参 数 传 递 都 是 按 值 传 递 事 实 上, 这 很 容 易 让 人 迷 惑, 下 面 先 分 别 看 看 什 么 是 按 值 传 递, 什 么 是 按 引 用 传 递, 只 要 能 正 确 理 解, 至 于 称 作 按 什 么 传 递 就 不 是 个 大 问 题 了 第 81 页

3.5.3.1 按 值 传 递 指 的 是 在 方 法 调 用 时, 传 递 的 参 数 是 按 值 的 拷 贝 传 递 示 例 如 下 : 1. public class TempTest { 2. private void test1(int a) { 3. // 做 点 事 情 4. a++; 5. 6. public static void main(string[] args) { 7. TempTest t = new TempTest(); 8. int a = 3; 9. t.test1(a);// 这 里 传 递 的 参 数 a 就 是 按 值 传 递 10. System.out.println("main 方 法 中 的 a===" + a); 11. 12. 按 值 传 递 重 要 特 点 : 传 递 的 是 值 的 拷 贝, 也 就 是 说 传 递 后 就 互 不 相 关 了 第 9 行 的 a 和 第 2 行 的 a 是 两 个 变 量, 当 改 变 第 2 行 a 的 值, 第 9 行 a 的 值 是 不 变 的, 所 以 打 印 结 果 是 3 main: a test1:a 3 4 我 们 把 第 9 行 的 a 称 之 为 实 参, 第 2 行 的 a 称 之 为 形 参 ; 对 于 基 本 数 据 类 型, 形 参 数 据 的 改 变, 不 影 响 实 参 的 数 据 3.5.3.2 按 引 用 传 递 指 的 是 在 方 法 调 用 时, 传 递 的 参 数 是 按 引 用 进 行 传 递, 其 实 传 递 的 引 用 的 地 址, 也 就 是 变 量 所 对 应 的 内 存 空 间 的 地 址 示 例 如 下 : 1. public class TempTest { 2. private void test1(a a) { 3. a.age = 20; 4. System.out.println("test1 方 法 中 的 age="+a.age); 5. 6. public static void main(string[] args) { 7. TempTest t = new TempTest(); 8. A a = new A(); 9. a.age = 10; 10. t.test1(a); // 这 里 传 递 的 参 数 a 就 是 按 引 用 传 递 11. System.out.println("main 方 法 中 的 age="+a.age); 12. 13. 14. class A { 15. public int age = 0; 16. 运 行 结 果 如 下 : test1 方 法 中 的 age=20 main 方 法 中 的 age=20 第 82 页

按 引 用 传 递 的 重 要 特 点 : 传 递 的 是 值 的 引 用, 也 就 是 说 传 递 前 和 传 递 后 都 指 向 同 一 个 引 用 ( 也 就 是 同 一 个 内 存 空 间 ) 要 想 正 确 理 解 按 引 用 传 递 的 过 程, 就 必 须 学 会 理 解 内 存 分 配 的 过 程, 内 存 分 配 示 意 图 可 以 辅 助 我 们 去 理 解 这 个 过 程 用 上 面 的 例 子 来 进 行 分 析 : (1) 运 行 开 始, 运 行 第 8 行, 创 建 了 一 个 A 的 实 例, 内 存 分 配 示 意 图 如 下 : main: a 3 0x1fb8ee age=0 这 是 一 个 A 的 实 例 (2) 运 行 第 9 行, 是 修 改 A 实 例 里 面 的 age 的 值, 运 行 后 内 存 分 配 示 意 图 如 下 : main:a 0x1fb8ee3 age=10 这 是 一 个 A 的 实 例 (3) 运 行 第 10 行, 是 把 main 方 法 中 的 变 量 a 所 引 用 的 内 存 空 间 地 址, 按 引 用 传 递 给 test1 方 法 中 的 a 变 量 请 注 意 : 这 两 个 a 变 量 是 完 全 不 同 的, 不 要 被 名 称 相 同 所 蒙 蔽, 但 它 们 指 向 了 同 一 个 A 实 例 内 存 分 配 示 意 图 如 下 : main:a test1:a 0x1fb8ee3 0x1fb8ee3 age=10 这 是 一 个 A 的 实 例 (4) 运 行 第 3 行, 为 test1 方 法 中 的 变 量 a 指 向 的 A 实 例 的 age 进 行 赋 值, 完 成 后 形 成 新 的 内 存 示 意 图 如 下 : main:a test1:a 0x1fb8ee3 0x1fb8ee3 age=20 这 是 一 个 A 的 实 例 此 时 A 实 例 的 age 值 的 变 化 是 由 test1 方 法 引 起 的 (5) 运 行 第 4 行, 根 据 此 时 的 内 存 示 意 图, 输 出 test1 方 法 中 的 age=20 (6) 运 行 第 11 行, 根 据 此 时 的 内 存 示 意 图, 输 出 main 方 法 中 的 age=20 第 83 页

对 上 述 例 子 的 改 变 理 解 了 上 面 的 例 子, 可 能 有 人 会 问, 那 么 能 不 能 让 按 照 引 用 传 递 的 值, 相 互 不 影 响 呢? 就 是 test1 方 法 里 面 的 修 改 不 影 响 到 main 方 法 里 面 呢? 新 加 的 : 方 法 是 在 test1 方 法 里 面 新 new 一 个 实 例 就 可 以 了 改 变 成 下 面 的 例 子, 其 中 第 3 行 为 1. public class TempTest { 2. private void test1(a a) { 3. a = new A();// 新 加 的 一 行 4. a.age = 20; 5. System.out.println("test1 方 法 中 的 age=" + a.age); 6. 7. public static void main(string[] args) { 8. TempTest t = new TempTest(); 9. A a = new A(); 10. age = 10; 11. t.test1(a); 12. System.out.println("main 方 法 中 的 age=" + a.age); 13. 14. 15. class A { 16. public int age = 0; 17. 运 行 结 果 为 : test1 方 法 中 的 age=20 main 方 法 中 的 age=10 为 什 么 这 次 的 运 行 结 果 和 前 面 的 例 子 不 一 样 呢, 还 是 使 用 内 存 示 意 图 来 理 解 一 下 : (1) 运 行 开 始, 运 行 第 9 行, 创 建 了 一 个 A 的 实 例, 内 存 分 配 示 意 图 如 下 : 0x1fb8ee3 main:a age=0 这 是 一 个 第 9 行 (2) 运 行 第 10 行, 是 修 改 A 实 例 里 面 的 age 的 值, 运 行 后 内 存 分 配 示 意 图 如 下 : 创 建 的 A 实 例 0x1fb8ee3 main:a age=10 这 是 一 个 第 9 行 创 建 的 A 实 例 (3) 运 行 第 11 行, 是 把 main 方 法 中 的 变 量 a 所 引 用 的 内 存 空 间 地 址, 按 引 用 传 递 给 test1 方 法 中 的 a 变 量 请 注 意 : 这 两 个 a 变 量 是 完 全 不 同 的, 不 要 被 名 称 相 同 所 蒙 蔽 main:a 0x1fb8ee3 age=10 这 是 一 个 第 9 行 test1:a 0x1fb8ee3 也 就 是 说 : 是 两 个 变 量 都 指 向 同 一 个 空 间 创 建 的 A 实 例 第 84 页

(4) 运 行 第 3 行, 为 test1 方 法 中 的 变 量 a 重 新 生 成 了 新 的 A 实 例 的, 完 成 后 形 成 的 新 的 内 存 示 意 图 如 下 : main:a 0x1fb8ee3 test1:a 0x1fb81f3 age=10 这 是 一 个 第 9 行 创 建 的 A 实 例 age=0 这 是 一 个 第 3 行 创 建 的 A 实 例 (5) 运 行 第 4 行, 为 test1 方 法 中 的 变 量 a 指 向 的 新 的 A 实 例 的 age 进 行 赋 值, 完 成 后 形 成 的 新 的 内 存 示 意 图 如 下 : main:a 0x1fb8ee3 test1:a 0x1fb81f3 age=10 这 是 一 个 第 9 行 创 建 的 A 实 例 age=20 这 是 一 个 第 3 行 变 的 创 建 的 A 实 例 注 意 : 这 个 时 候 test1 方 法 中 的 变 量 a 的 age 被 改 变, 而 main 方 法 中 的 是 没 有 改 (6) 运 行 第 5 行, 根 据 此 时 的 内 存 示 意 图, 输 出 test1 方 法 中 的 age=20 (7) 运 行 第 12 行, 根 据 此 时 的 内 存 示 意 图, 输 出 main 方 法 中 的 age=10 说 明 : 在 Java 里 面 参 数 传 递 都 是 按 值 传 递 这 句 话 的 意 思 是 : 按 值 传 递 是 传 递 的 值 的 拷 贝, 按 引 用 传 递 其 实 传 递 的 是 引 用 的 地 址 值, 所 以 统 称 按 值 传 递 在 Java 里 面 只 有 基 本 类 型 和 按 照 下 面 这 种 定 义 方 式 的 String 是 按 值 传 递, 其 它 的 都 是 按 引 用 传 递 就 是 直 接 使 用 双 引 号 定 义 字 符 串 方 式 :String str = "Java 快 车 "; 3.6 类 中 的 变 量 3.6.1 实 例 变 量 和 局 部 变 量 在 方 法 外 定 义 的 变 量 主 要 是 实 例 变 量, 它 们 是 在 使 用 new Xxxx () 创 建 一 个 对 象 时 被 分 配 内 存 空 间 的 每 当 创 建 一 个 对 象 时, 系 统 就 为 该 类 的 所 有 实 例 变 量 分 配 存 储 空 间 ; 创 建 多 个 对 象 就 有 多 份 实 例 变 量 通 过 对 象 的 引 用 就 可 以 访 问 实 例 变 量 第 85 页

在 方 法 内 定 义 的 变 量 或 方 法 的 参 数 被 称 为 局 部 (local) 变 量, 有 时 也 被 用 为 自 动 (automatic) 临 时 (temporary) 或 栈 (stack) 变 量 方 法 参 数 变 量 定 义 在 一 个 方 法 调 用 中 传 送 的 自 变 量, 每 次 当 方 法 被 调 用 时, 一 个 新 的 变 量 就 被 创 建 并 且 一 直 存 在 到 程 序 的 运 行 跳 离 了 该 方 法 当 执 行 进 入 一 个 方 法 遇 到 局 部 变 量 的 声 明 语 句 时, 局 部 变 量 被 创 建, 当 执 行 离 开 该 方 法 时, 局 部 变 量 被 取 消, 也 就 是 该 方 法 结 束 时 局 部 变 量 的 生 命 周 期 也 就 结 束 了 因 而, 局 部 变 量 有 时 也 被 引 用 为 临 时 或 自 动 变 量 在 成 员 方 法 内 定 义 的 变 量 对 该 成 员 变 量 是 局 部 的, 因 而, 你 可 以 在 几 个 成 员 方 法 中 使 用 相 同 的 变 量 名 而 代 表 不 同 的 变 量 该 方 法 的 应 用 如 下 所 示 : public class Test { private int i; // Test 类 的 实 例 变 量 public int firstmethod() { int j = 1; // 局 部 变 量 // 这 里 能 够 访 问 i 和 j System.out.println("firstMethod 中 i=" + i + ",j=" + j); return 1; // firstmethod() 方 法 结 束 public int secondmethod(float f) { // method parameter int j = 2; // 局 部 变 量, 跟 firstmethod() 方 法 中 的 j 是 不 同 的 // 这 个 j 的 范 围 是 限 制 在 secondmethod() 方 法 中 的 // 在 这 个 地 方, 可 以 同 时 访 问 i,j,f System.out.println("secondMethod 中 i=" + i + ",j=" + j + ",f=" +f); return 2; public static void main(string[] args) { Test t = new Test(); t.firstmethod(); t.secondmethod(3); 3.6.2 实 例 变 量 的 初 始 化 在 Java 程 序 中, 任 何 变 量 都 必 须 经 初 始 化 后 才 能 被 使 用 当 一 个 对 象 被 创 建 时, 实 例 变 量 在 分 配 内 存 空 间 时 按 程 序 员 指 定 的 初 始 化 值 赋 值, 否 则 系 统 将 按 下 列 默 认 值 进 行 初 始 化 : 数 据 类 型 初 始 值 byte 0 short 0 int 0 long 0L char '\u0000' 第 86 页

float 0.0F double 0.0D boolean false 所 有 引 用 类 型 null 注 意 : 一 个 具 有 空 值 null 的 引 用 不 引 用 任 何 对 象 试 图 使 用 它 引 用 的 对 象 将 会 引 起 一 个 异 常 异 常 是 出 现 在 运 行 时 的 错 误, 这 将 在 模 块 异 常 中 讨 论 在 方 法 外 定 义 的 变 量 被 自 动 初 始 化 局 部 变 量 必 须 在 使 用 之 前 做 手 工 ( 由 程 序 员 进 行 ) 初 始 化 如 果 编 译 器 能 够 确 认 一 个 变 量 在 初 始 化 之 前 可 能 被 使 用 的 情 形, 编 译 器 将 报 错 public class Test { private int i; // Test 类 的 实 例 变 量 public void test1() { int x = (int) (Math.random() * 100); int y; int z; if (x > 50) { y = 9; z = y + x; // 将 会 引 起 错 误, 因 为 y 可 能 还 没 有 被 初 始 化 就 使 用 了 public static void main(string[] args) { Test t = new Test(); t.test1(); 3.7 Java 类 的 基 本 运 行 顺 序 作 为 程 序 员, 应 该 对 自 己 写 的 程 序 具 备 充 分 的 掌 控 能 力, 应 该 清 楚 程 序 的 基 本 运 行 过 程, 否 则 糊 里 糊 涂 的, 不 利 于 对 程 序 的 理 解 和 控 制, 也 不 利 于 技 术 上 的 发 展 我 们 以 下 面 的 类 来 说 明 一 个 基 本 的 Java 类 的 运 行 顺 序 : 1. public class Test { 2. private String name; 3. private int age; 4. 5. public Test() { 6. name = "Tom"; 7. age = 20; 8. 9. public static void main(string[] args) { 10. Test t = new Test(); 11. System.out.println(t.name + " 的 年 龄 是 " + t.age ); 第 87 页

12. 13. 运 行 的 基 本 顺 序 是 : (1) 先 运 行 到 第 9 行, 这 是 程 序 的 入 口 (2) 然 后 运 行 到 第 10 行, 这 里 要 new 一 个 Test, 就 要 调 用 Test 的 构 造 方 法 (3) 就 运 行 到 第 5 行, 注 意 : 可 能 很 多 人 觉 得 接 下 来 就 应 该 运 行 第 6 行 了, 错! 初 始 化 一 个 对 象, 必 须 先 初 始 化 它 的 属 性 (4) 因 此 运 行 到 第 2 行, 然 后 是 第 3 行 (5) 属 性 初 始 化 完 过 后, 才 回 到 构 造 方 法, 执 行 里 面 的 代 码, 也 就 是 第 6 行 第 7 行 (6) 然 后 是 第 8 行, 表 示 new 一 个 Test 实 例 完 成 (7) 然 后 回 到 main 方 法 中 执 行 第 11 行 (8) 然 后 是 第 12 行,main 方 法 执 行 完 毕 说 明 : 这 里 只 是 说 明 一 个 基 本 的 运 行 过 程, 没 有 考 虑 更 多 复 杂 的 情 况 第 88 页

3.8 学 习 目 标 1. 理 解 为 什 么 要 面 向 对 象, 理 解 现 实 中 的 对 象 和 类 型 与 Java 中 的 类 和 对 象 的 相 互 关 系 2. 能 够 描 述 Java 中 类 的 6 个 组 成 部 分 3. 简 述 什 么 是 包? 包 的 功 能, 描 述 使 用 包 的 好 处 4. 了 解 Java 中 的 常 见 包, 能 够 写 出 5 个 以 上 的 JDK 中 的 包, 以 及 他 们 的 基 本 功 能 5. 能 够 描 述 import 关 键 字 的 用 法 6. 简 述 Java 的 访 问 修 饰 符 类 型? 分 别 有 什 么 功 能? 7. 能 够 描 述 类 定 义 的 完 整 的 语 法 结 构 8. 能 够 描 述 属 性 定 义 的 完 整 的 语 法 结 构 9. 能 够 描 述 构 造 方 法 定 义 的 完 整 的 语 法 结 构 10. 理 解 构 造 方 法 的 调 用 和 系 统 提 供 的 默 认 的 构 造 方 法 11. 理 解 析 构 方 法 12. 能 够 描 述 方 法 定 义 的 完 整 的 语 法 结 构 13. 分 别 说 明 : 在 类 上 在 属 性 上 在 方 法 上 等 能 使 用 那 些 访 问 修 饰 符 14. 什 么 是 形 参 ( 形 式 参 数 )? 什 么 是 实 参 ( 实 际 参 数 )? 15. 如 何 通 过 类 创 建 对 象, 如 何 调 用 对 象 的 方 法, 如 何 调 用 对 象 的 属 性 16. 什 么 是 引 用 数 据 类 型? 17. 什 么 是 按 值 传 递, 什 么 是 按 引 用 传 递? 18. this 关 键 字 的 用 法? 19. 什 么 时 候 使 用 this 关 键 字? 20. 什 么 是 实 例 变 量, 什 么 是 局 部 变 量? 21. 如 何 理 解 属 性 的 初 始 化? 22. 什 么 是 强 制 类 型 转 换 23. 简 述 Java 类 的 基 本 运 行 顺 序 第 89 页

3.9 练 习 1. 请 编 写 一 个 方 法 实 现 如 下 功 能 : 将 0 至 6 的 数 字 转 换 为 星 期 日 到 星 期 六 的 字 符 串 要 求 : 输 入 一 个 数 字 参 数, 返 回 字 符 串 2. 请 编 写 一 个 方 法 实 现 如 下 功 能 : 将 任 意 三 个 整 数 a,b,c 按 从 小 到 大 排 序 要 求 : 输 入 三 个 参 数, 返 回 一 个 排 好 顺 序 的 字 符 串 3. 请 编 写 一 个 方 法 实 现 如 下 功 能 : 计 算 1 加 到 n(n>=2 的 整 数 ) 的 总 和 4. 请 编 写 一 个 方 法 实 现 如 下 功 能 : 得 到 一 个 整 数 的 绝 对 值 5. 请 编 写 一 个 方 法, 输 入 两 个 参 数, 判 断 第 一 个 数 字 是 否 是 第 二 个 数 字 的 整 数 倍 数, 如 果 是, 返 回 true; 如 果 不 是, 返 回 false 6. 请 编 写 一 个 方 法, 输 入 正 方 形 的 边 长, 然 后 利 用 星 号 和 空 格, 打 印 具 有 那 个 边 长 的 一 个 空 心 正 方 形 假 定 输 入 参 数 是 5, 则 输 出 效 果 应 该 是 下 面 这 样 : 7. 回 文 是 一 种 特 殊 的 数 字 或 文 字 短 语, 无 论 顺 读, 还 是 倒 读, 结 果 都 是 一 样 的 例 如, 下 面 这 些 整 数 其 实 都 是 回 文 : 11 1221 5555 4554 12321 11611 编 写 一 个 方 法 判 断 是 否 是 回 文 : 输 入 数 字, 如 果 是 回 文, 返 回 true, 否 则 返 回 false 8. 请 编 写 一 个 方 法 实 现 如 下 功 能 : 输 入 三 个 非 零 的 整 数 值, 判 断 它 们 是 否 能 代 表 一 个 三 角 形 的 3 个 边 长, 如 果 能, 返 回 true; 如 果 不 能 返 回 false ( 提 示 : 判 断 三 个 边 长 能 否 组 成 三 角 形 的 规 则 是 : 任 意 两 个 边 长 之 和 大 于 第 三 个 边 长 ) 9. 请 编 写 一 个 方 法 实 现 如 下 功 能 : 用 程 序 找 出 每 位 数 的 立 方 和 等 于 该 数 本 身 值 的 所 有 的 3 位 数 ( 水 仙 花 数 ) 10. 有 一 个 序 列, 首 两 项 为 0,1, 以 后 各 项 值 为 前 两 项 值 之 和 写 一 个 方 法 来 实 现 求 这 个 序 列 的 和 11. 写 一 个 MyPoint 完 全 封 装 类, 其 中 含 有 私 有 的 int 类 型 的 x 和 y 属 性, 分 别 用 公 有 的 getx 和 setx gety 和 sety 方 法 访 问, 定 义 一 个 tostring 方 法 用 来 显 示 这 个 对 象 的 x y 的 值, 如 显 示 (1,2), 最 后 用 main 方 法 测 试 12. 为 MyPoint 类 添 加 public boolean equals(mypoint mp) 方 法, 创 建 两 个 MyPoint 对 象, 使 用 equals 方 法 比 较 两 个 对 象 是 否 相 等, 再 使 用 == 比 较 两 个 对 象 是 否 相 等, 思 考 两 种 比 较 的 不 同 之 处 第 90 页

4 Java 高 级 类 特 性 面 向 对 象 有 三 大 特 征, 即 封 装 继 承 多 态 4.1 封 装 封 装 这 个 词 听 起 来 好 象 是 将 什 么 东 西 包 裹 起 来 不 要 别 人 看 见 一 样, 就 好 象 是 把 东 西 装 进 箱 子 里 面, 这 样 别 人 就 不 知 道 箱 子 里 面 装 的 是 什 么 东 西 了 其 实 JAVA 中 的 封 装 这 个 概 念 也 就 和 这 个 是 差 不 多 的 意 思 封 装 是 JAVA 面 向 对 象 的 特 点 的 表 现, 封 装 是 一 种 信 息 隐 蔽 技 术 它 有 两 个 含 义 : 即 把 对 象 的 全 部 属 性 和 全 部 服 务 结 合 在 一 起, 形 成 一 个 不 可 分 割 的 独 立 单 位 ; 以 及 尽 可 能 隐 藏 对 象 的 内 部 结 构 也 就 是 说, 如 果 我 们 使 用 了 封 装 技 术 的 话, 别 人 就 只 能 用 我 们 做 出 来 的 东 西 而 看 不 见 我 们 做 的 这 个 东 西 的 内 部 结 构 了 封 装 的 功 能 : - 迫 使 用 户 去 使 用 一 个 界 面 访 问 数 据 - 使 代 码 更 好 维 护 - 隐 藏 对 象 的 实 现 细 节 封 装 迫 使 用 户 通 过 方 法 访 问 数 据 能 保 护 对 象 的 数 据 不 被 误 修 改, 还 能 使 对 象 的 重 用 变 得 更 简 单 数 据 隐 藏 通 常 指 的 就 是 封 装 它 将 对 象 的 外 部 界 面 与 对 象 的 实 现 区 分 开 来, 隐 藏 实 现 细 节 迫 使 用 户 去 使 用 外 部 界 面, 即 使 实 现 细 节 改 变, 还 可 通 过 界 面 承 担 其 功 能 而 保 留 原 样, 确 保 调 用 它 的 代 码 还 继 续 工 作 封 装 使 代 码 维 护 更 简 单 4.2 继 承 4.2.1 继 承 在 面 向 对 象 世 界 里 面, 常 常 要 创 建 某 对 象 ( 如 : 一 个 职 员 对 象 ), 然 后 需 要 一 个 该 基 本 对 象 的 更 专 业 化 的 版 本, 比 如, 可 能 需 要 一 个 经 理 的 对 象 显 然 经 理 实 际 上 是 一 个 职 员, 经 理 和 职 员 具 有 is-a 的 关 系, 经 理 只 是 一 个 带 有 附 加 特 征 的 职 员 因 此, 需 要 有 一 种 办 法 从 现 有 对 象 来 创 建 一 个 新 对 象, 这 个 方 式 就 是 继 承 现 实 中 的 事 务, 只 要 具 有 is-a 的 关 系, 在 java 中 都 可 以 用 继 承 表 示 继 承 是 面 向 对 象 软 件 技 术 当 中 的 一 个 概 念 如 果 一 个 对 象 A 继 承 自 另 一 个 对 象 B, 就 把 这 个 A 称 为 B 的 子 对 象, 而 把 B 称 为 A 的 父 对 象 继 承 可 以 使 得 子 对 象 具 有 父 对 象 的 各 种 属 性 和 方 法, 而 不 需 要 再 次 编 写 相 同 的 代 码 在 令 子 对 象 继 承 父 对 象 的 同 时, 可 以 重 新 定 义 某 些 属 性, 并 重 写 某 些 方 法, 即 覆 盖 父 对 象 的 原 有 属 性 和 方 法, 使 其 获 得 与 父 对 象 不 同 的 功 能 第 91 页

4.2.2 extends 关 键 字 在 Java 中 使 用 extends 关 键 字 来 表 达 继 承 的 关 系, 比 如 : 经 理 这 个 类 继 承 雇 员 这 个 类, 示 例 如 下 : public class Employee { String name; Date hiredate; Date dateofbirth; String jobtitle; int grade;... public class Manager extends Employee { String department; Employee[] subordinates;... 在 这 样 的 定 义 中,Manager 类 被 定 义, 具 有 Employee 所 拥 有 的 所 有 变 量 及 方 法 所 有 这 些 变 量 和 方 法 都 是 从 父 类 的 定 义 中 继 承 来 的 所 有 的 程 序 员 需 要 做 的 是 定 义 额 外 特 征 或 规 定 将 适 用 的 变 化 注 意 : 这 种 方 法 是 在 维 护 和 可 靠 性 方 面 的 一 个 伟 大 进 步 如 果 在 Employee 类 中 进 行 修 改, 那 么,Manager 类 就 会 自 动 修 改, 而 不 需 要 程 序 员 做 任 何 工 作, 除 了 对 它 进 行 编 译 4.2.3 父 子 类 的 初 始 化 顺 序 Java 技 术 安 全 模 式 要 求 在 子 类 执 行 任 何 东 西 之 前, 描 述 父 类 的 一 个 对 象 的 各 个 方 面 都 必 须 初 始 化 因 此,Java 编 程 语 言 总 是 在 执 行 子 构 造 方 法 前 调 用 父 类 构 造 方 法 的 版 本 有 继 承 的 类 在 运 行 的 时 候, 一 定 要 记 得 : 初 始 化 子 类 必 先 初 始 化 父 类, 这 是 Java 程 序 的 一 个 基 本 运 行 过 程 比 如 : public class Test extends Parent { private String name; private int age; public Test() { name="tom"; age=20; public static void main(string[] args) { Test t = new Test(); System.out.println(t.name + " 的 年 龄 是 " + t.age); class Parent { 第 92 页

private int num = 1; public Parent() { System.out.println(" 现 在 初 始 化 父 类 "); public void test() { System.out.println(" 这 是 父 类 的 test 方 法 "); 上 述 类 的 基 本 运 行 顺 序 是 : (1) 先 运 行 到 第 8 行, 这 是 程 序 的 入 口 (2) 然 后 运 行 到 第 9 行, 这 里 要 new 一 个 Test, 就 要 调 用 Test 的 构 造 方 法 (3) 就 运 行 到 第 4 行, 注 意 : 初 始 化 子 类 必 先 初 始 化 父 类 (4) 要 先 初 始 化 父 类, 所 以 运 行 到 第 15 行 (5) 然 后 是 第 14 行, 初 始 化 一 个 类, 必 须 先 初 始 化 它 的 属 性 (6) 然 后 是 第 16 行 (7) 然 后 是 第 17 行, 表 示 父 类 初 始 化 完 成 (8) 然 后 是 回 到 子 类, 开 始 初 始 化 属 性, 因 此 运 行 到 第 2 行, 然 后 是 第 3 行 (9) 子 类 属 性 初 始 化 完 过 后, 才 回 到 子 类 的 构 造 方 法, 执 行 里 面 的 代 码, 也 就 是 第 5 6 行 (10) 然 后 是 第 7 行, 表 示 new 一 个 Test 实 例 完 成 (11) 然 后 回 到 main 方 法 中 执 行 第 10 行 (12) 然 后 是 第 11 行 4.2.4 单 继 承 性 单 继 承 性 : 当 一 个 类 从 一 个 唯 一 的 类 继 承 时, 被 称 做 单 继 承 性 单 继 承 性 使 代 码 更 可 靠 接 口 提 供 多 继 承 性 的 好 处, 而 且 没 有 ( 多 继 承 的 ) 缺 点 Java 编 程 语 言 允 许 一 个 类 仅 能 继 承 一 个 其 它 类, 即 一 个 类 只 能 有 一 个 父 类 这 个 限 制 被 称 做 单 继 承 性 单 继 承 性 与 多 继 承 性 的 优 点 是 面 向 对 象 程 序 员 之 间 广 泛 讨 论 的 话 题 Java 编 程 语 言 加 强 了 单 继 承 性 限 制 而 使 代 码 更 为 可 靠, 尽 管 这 样 有 时 会 增 加 程 序 员 的 工 作 后 面 会 学 到 一 个 被 叫 做 接 口 (interface) 的 语 言 特 征, 它 允 许 多 继 承 性 的 大 部 分 好 处, 而 不 受 其 缺 点 的 影 响 使 用 继 承 性 的 子 类 的 一 个 例 子 如 图 所 示 : 第 93 页

4.2.5 构 造 方 法 不 能 被 继 承 尽 管 一 个 子 类 从 父 类 继 承 所 有 的 方 法 和 变 量, 但 它 不 继 承 构 造 方 法, 掌 握 这 一 点 很 重 要 一 个 类 能 得 到 构 造 方 法, 只 有 两 个 办 法 或 者 写 构 造 方 法, 或 者 根 本 没 有 写 构 造 方 法, 类 有 一 个 默 认 的 构 造 方 法 4.3 方 法 的 覆 盖 和 重 载 4.3.1 方 法 的 覆 盖 4.3.1.1 什 么 是 方 法 的 覆 盖 (Overridden Methods) 在 类 继 承 中, 子 类 可 以 修 改 从 父 类 继 承 来 的 行 为, 也 就 是 说 子 类 能 创 建 一 个 与 父 类 方 法 有 不 同 功 能 的 方 法, 但 具 有 相 同 的 : 名 称 返 回 类 型 参 数 列 表 如 果 在 子 类 中 定 义 一 个 方 法, 其 方 法 名 称 返 回 值 类 型 及 参 数 列 表 正 好 与 父 类 中 方 法 的 名 称 返 回 值 类 型 及 参 数 列 表 相 匹 配, 那 么 称, 子 类 的 方 法 覆 盖 了 父 类 的 方 法 4.3.1.2 示 例 如 下 在 Employee 和 Manager 类 中 的 这 些 方 法 : public class Employee { String name; int salary; public String getdetails() { return " Name: " + name + " \n " + "Salary: " + salary; public class Manager extends Employee { String department; public String getdetails() { return " Name: " + name + " \n " + " Manager of " + department; Manager 类 有 一 个 定 义 的 getdetails() 方 法, 因 为 它 是 从 Employee 类 中 继 承 的 基 本 的 方 法 被 子 类 的 版 本 所 代 替 或 覆 盖 了 4.3.1.3 方 法 的 覆 盖 规 则 子 类 的 方 法 的 名 称 以 及 子 类 方 法 参 数 的 顺 序 必 须 与 父 类 中 的 方 法 的 名 称 以 及 参 数 的 顺 序 相 同, 以 便 该 方 法 覆 盖 父 类 版 本 下 述 规 则 适 用 于 覆 盖 方 法 : 覆 盖 方 法 不 能 比 它 所 覆 盖 的 方 法 访 问 性 差 ( 即 访 问 权 限 不 允 许 缩 小 ) 第 94 页

覆 盖 方 法 不 能 比 它 所 覆 盖 的 方 法 抛 出 更 多 的 异 常 效 方 案 : 这 些 规 则 源 自 多 态 性 的 属 性 和 Java 编 程 语 言 必 须 保 证 类 型 安 全 的 需 要 考 虑 一 下 这 个 无 public class Parent { public void method() { public class Child extends Parent { private void method() {// 编 译 就 会 出 错 public class Test { public void othermethod() { Parent p1 = new Parent(); Parent p2 = new Child(); p1.method(); p2.method(); Java 编 程 语 言 语 义 规 定,p2.method() 导 致 方 法 的 Child 版 本 被 执 行, 但 因 为 方 法 被 声 明 为 private,p2( 声 明 为 Parent) 不 能 访 问 它 于 是, 语 言 语 义 冲 突 4.3.2 方 法 的 重 载 假 如 你 必 须 在 不 同 情 况 下 发 送 不 同 的 信 息 给 同 一 个 成 员 方 法 的 话, 该 怎 么 办 呢? 你 可 以 通 过 对 此 成 员 方 法 说 明 多 个 版 本 的 方 法 来 实 现 重 载 重 载 的 本 质 是 创 建 了 一 个 新 的 成 员 方 法 : 你 只 需 给 它 一 个 不 同 的 参 数 列 表 4.3.2.1 什 么 是 重 载 做 重 载 在 同 一 个 Java 类 中 ( 包 含 父 类 ), 如 果 出 现 了 方 法 名 称 相 同, 而 参 数 列 表 不 同 的 情 况 就 叫 参 数 列 表 不 同 的 情 况 包 括 : 个 数 不 同 类 型 不 同 顺 序 不 同 等 等 特 别 提 示, 仅 仅 参 数 变 量 名 称 不 同 是 不 可 以 的 4.3.2.2 示 例 如 下 例 所 示 : void getarea(int w,int h); void getarea(float w,float h); 在 第 二 种 情 况 下, 成 员 方 法 getarea() 接 受 两 个 浮 点 变 量 作 为 它 的 参 数, 编 译 器 根 据 调 用 时 的 不 同 参 数 来 决 定 该 调 用 哪 一 种 成 员 方 法, 假 如 你 把 两 个 整 数 提 供 给 成 员 方 法, 就 调 用 第 一 个 成 员 方 法 ; 假 如 你 把 两 个 浮 点 数 提 供 给 成 员 方 法, 第 二 个 成 员 方 法 就 被 调 用 第 95 页

法 当 写 代 码 来 调 用 这 些 方 法 中 的 一 个 方 法 时, 便 以 其 会 根 据 提 供 的 参 数 的 类 型 来 选 择 合 适 的 方 注 意 : 跟 成 员 方 法 一 样, 构 造 方 法 也 可 以 重 载 4.3.2.3 方 法 的 重 载 规 则 方 法 名 称 必 须 相 同 参 数 列 表 必 须 不 同 ( 个 数 不 同, 或 类 型 不 同, 或 参 数 排 列 顺 序 不 同 ) 方 法 的 返 回 类 型 可 以 相 同 也 可 以 不 相 同 仅 仅 返 回 类 型 不 同 不 足 以 成 为 方 法 的 重 载 注 意 : 调 用 语 句 的 参 数 表 必 须 有 足 够 的 不 同, 以 至 于 允 许 区 分 出 正 确 的 方 法 被 调 用 正 常 的 拓 展 晋 升 ( 如, 单 精 度 类 型 float 到 双 精 度 类 型 double) 可 能 被 应 用, 但 是 这 样 会 导 致 在 某 些 条 件 下 的 混 淆 4.3.2.4 比 较 方 法 的 覆 盖 和 重 载 重 载 方 法 : 在 一 个 类 ( 或 父 子 类 ) 中 用 相 同 的 名 字 创 建 多 个 方 法 ( 每 个 方 法 的 参 数 表 不 同 ) 方 法 覆 盖 : 在 一 个 类 中 创 建 的 方 法 与 父 类 中 方 法 的 名 字 返 回 类 型 和 参 数 表 相 同, 覆 盖 是 针 对 两 个 类 说 的, 而 且 必 须 是 子 类 ( 或 孙 类, 孙 孙 类 等 ) 覆 盖 掉 父 类 的 方 法 4.4 关 键 字 super 关 键 字 super 可 被 用 来 引 用 该 类 的 父 类, 它 被 用 来 引 用 父 类 的 成 员 变 量 或 方 法 父 类 行 为 被 调 用, 就 好 象 该 行 为 是 本 类 的 行 为 一 样, 而 且 调 用 行 为 不 必 发 生 在 父 类 中, 它 能 自 动 向 上 层 类 追 溯 super 关 键 字 的 功 能 : 点 取 父 类 中 被 子 类 隐 藏 了 的 数 据 成 员 点 取 已 经 覆 盖 了 的 方 法 作 为 方 法 名 表 示 父 类 构 造 方 法 4.4.1 点 取 父 类 中 被 子 类 隐 藏 了 的 数 据 成 员 或 方 法 public class Employee { private String name; private int salary; public String getdetails() { return "Name: " + name + "\nsalary: " + salary; public class Manager extends Employee { private String department; public String getdetails() { return super.getdetails() + // 调 用 父 类 的 方 法 第 96 页

"\ndepartment: " + department; 请 注 意,super.method() 格 式 的 调 用, 如 果 对 象 已 经 具 有 父 类 类 型, 那 么 它 的 方 法 的 整 个 行 为 都 将 被 调 用, 也 包 括 其 所 有 负 面 效 果 该 方 法 不 必 在 父 类 中 定 义, 它 也 可 以 从 某 些 祖 先 类 中 继 承 也 就 是 说 可 以 从 父 类 的 父 类 去 获 取, 具 有 追 溯 性, 一 直 向 上 去 找, 直 到 找 到 为 止, 这 是 一 个 很 重 要 的 特 点 4.4.2 调 用 父 类 构 造 方 法 在 许 多 情 况 下, 使 用 默 认 构 造 方 法 来 对 父 类 对 象 进 行 初 始 化 当 然 也 可 以 使 用 super 来 显 示 调 用 父 类 的 构 造 方 法 public class Employee { String name; public Employee(String n) { name = n; public class Manager extends Employee { String department; public Manager(String s, String d) { super(s); department = d; 注 意 : 无 论 是 super 还 是 this, 都 必 须 放 在 构 造 方 法 的 第 一 行 通 常 要 定 义 一 个 带 参 数 的 构 造 方 法, 并 要 使 用 这 些 参 数 来 控 制 一 个 对 象 的 父 类 部 分 的 构 造 可 能 通 过 从 子 类 构 造 方 法 的 第 一 行 调 用 关 键 字 super 的 手 段 调 用 一 个 特 殊 的 父 类 构 造 方 法 作 为 子 类 初 始 化 的 一 部 分 要 控 制 具 体 的 构 造 方 法 的 调 用, 必 须 给 super() 提 供 合 适 的 参 数 当 不 调 用 带 参 数 的 super 时, 缺 省 的 父 类 构 造 方 法 ( 即, 不 带 参 数 的 构 造 方 法 ) 被 隐 含 地 调 用 在 这 种 情 况 下, 如 果 没 有 缺 省 的 父 类 构 造 方 法, 将 导 致 编 译 错 误 public class Employee { String name; public Employee(String n) { name = n; public class Manager extends Employee { String department; public Manager(String s, String d) { super(s); // 调 用 父 类 参 数 为 String 类 型 的 构 造 方 法, 没 有 这 句 话, 编 译 会 出 错 department = d; 第 97 页

当 被 使 用 时,super 或 this 必 须 被 放 在 构 造 方 法 的 第 一 行 显 然, 两 者 不 能 被 放 在 一 个 单 独 行 中, 但 这 种 情 况 事 实 上 不 是 一 个 问 题 如 果 写 一 个 构 造 方 法, 它 既 没 有 调 用 super( ) 也 没 有 调 用 this( ), 编 译 器 自 动 插 入 一 个 调 用 到 父 类 构 造 方 法 中, 而 不 带 参 数 其 它 构 造 方 法 也 能 调 用 super( ) 或 this( ), 调 用 一 个 static 方 法 和 构 造 方 法 的 数 据 链 最 终 发 生 的 是 父 类 构 造 方 法 ( 可 能 几 个 ) 将 在 链 中 的 任 何 子 类 构 造 方 法 前 执 行 4.5 多 态 性 4.5.1 什 么 是 多 态 多 态 是 同 一 个 行 为 具 有 多 个 不 同 表 现 形 式 或 形 态 的 能 力 比 如 我 们 说 宠 物 这 个 对 象, 它 就 有 很 多 不 同 的 表 达 或 实 现, 比 如 有 小 猫 小 狗 蜥 蜴 等 等 那 么 我 到 宠 物 店 说 请 给 我 一 只 宠 物, 服 务 员 给 我 小 猫 小 狗 或 者 蜥 蜴 都 可 以, 我 们 就 说 宠 物 这 个 对 象 就 具 备 多 态 性 再 回 想 一 下 经 理 和 职 员 的 关 系, 经 理 类 具 有 父 类 职 员 类 的 所 有 属 性 成 员 和 方 法 这 就 是 说, 任 何 在 Employee 上 的 合 法 操 作 在 Manager 上 也 合 法 如 果 Employee 有 raisesalary() 和 fire() 两 个 方 法, 那 么 Manager 类 也 有 在 这 种 Manager 继 承 Employee 的 情 况 下, 一 个 Employee 既 可 以 是 一 个 普 通 的 Employee 类, 也 可 以 是 一 个 Manager 类 也 就 是 说 下 述 表 示 都 是 对 的 : Employee e = new Employee(); Employee e = new Manager(); 从 上 面 可 以 看 到 : 同 一 个 行 为 Employee 具 有 多 个 不 同 的 表 现 形 式 ( 既 可 以 是 一 个 普 通 的 Employee 类, 也 可 以 是 一 个 Manager 类 ), 这 就 被 称 为 多 态 注 意 : 方 法 没 有 多 态 的 说 法, 严 格 说 多 态 是 类 的 特 性 但 是 也 有 对 方 法 说 多 态 的, 了 解 一 下, 比 如 前 面 学 到 的 方 法 覆 盖 称 为 动 态 多 态, 是 一 个 运 行 时 问 题 ; 方 法 重 载 称 为 静 态 多 态, 是 一 个 编 译 时 问 题 4.5.2 多 态 与 类 型 一 个 对 象 只 有 一 个 格 式 ( 是 在 构 造 时 给 它 的 ) 但 是, 既 然 变 量 能 指 向 不 同 格 式 的 对 象, 那 么 变 量 就 是 多 态 性 的 也 就 是 说 一 个 对 象 只 有 一 种 形 式, 但 一 个 变 量 却 有 多 种 不 同 形 式 象 大 多 数 面 向 对 象 语 言 一 样,Java 实 际 上 允 许 父 类 类 型 的 引 用 变 量 指 向 一 个 子 类 的 对 象 因 此, 可 以 说 : Employee e = new Manager() 使 用 变 量 e 是 因 为, 你 能 访 问 的 对 象 部 分 只 是 Employee 的 一 个 部 分 ;Manager 的 特 殊 第 98 页

部 分 是 隐 藏 的 这 是 因 为 编 译 者 应 意 识 到,e 是 一 个 Employee, 而 不 是 一 个 Manager 因 而, 下 述 情 况 是 不 允 许 的 : e.department = " Finance " ; // 非 法 的, 编 译 时 会 出 错 可 能 有 的 人 会 不 理 解, 为 什 么 明 明 是 new 的 一 个 Manager, 却 不 能 访 问 Manager 的 属 性 数 据 原 因 在 于 编 译 的 时 候, 变 量 e 是 一 个 Employee 的 类 型, 编 译 器 并 不 去 管 运 行 时 e 指 向 的 具 体 对 象 是 一 个 Employee 的 对 象, 还 是 一 个 Manager 的 对 象, 所 以 它 只 能 访 问 到 Employee 里 面 定 义 的 属 性 和 方 法 所 以 说 编 译 时 看 数 据 类 型 那 么 要 想 访 问 到 Manager 里 面 的 department 该 怎 么 办 呢? 这 就 需 要 先 对 e 进 行 强 制 类 型 转 换, 把 它 还 原 成 为 Manager 类 型, 就 可 以 访 问 到 Manager 里 面 的 属 性 和 方 法 了, 如 下 : Employee e = new Manager(); Manager m = (Manager)e; m.department = " 开 发 部 "; // 这 就 是 合 法 的 了 4.5.3 到 底 运 行 哪 一 个 方 法? 这 里 会 给 我 们 带 来 一 个 麻 烦, 父 子 类 中 有 相 同 的 方 法, 那 么 在 运 行 时 到 底 调 用 哪 一 个 方 法 呢? 假 设 下 述 方 案 : Employee e = new Employee(); Manager m = new Manager(); 如 果 请 求 e.getdetails() 和 m.getdetails(), 就 会 调 用 不 同 的 行 为 Employee 对 象 将 执 行 与 Employee 有 关 的 getdetails 版 本, Manager 对 象 将 执 行 与 Manager 有 关 的 getdetails() 版 本 不 明 显 的 是 如 下 所 示 : Employee e = new Manager(); e.getdetails(); 或 某 些 相 似 效 果, 比 如 一 个 通 用 方 法 参 数 或 一 个 来 自 异 类 集 合 的 项 事 实 上, 你 得 到 与 变 量 的 运 行 时 类 型 ( 即, 变 量 所 引 用 的 对 象 的 类 型 ) 相 关 的 行 为, 而 不 是 与 变 量 的 编 译 时 类 型 相 关 的 行 为 这 是 面 向 对 象 语 言 的 一 个 重 要 特 征 它 也 是 多 态 性 的 一 个 特 征, 并 通 常 被 称 作 虚 拟 方 法 调 用 在 前 例 中, 被 执 行 的 e.getdetails() 方 法 来 自 对 象 的 真 实 类 型 Manager 因 此 规 则 是 : 编 译 时 看 数 据 类 型, 运 行 时 看 实 际 的 对 象 类 型 (new 操 作 符 后 跟 的 构 造 方 法 是 哪 个 类 的 ) 一 句 话 :new 谁 就 调 用 谁 的 方 法 4.5.4 instanceof 运 算 符 多 态 性 带 来 了 一 个 问 题 : 如 何 判 断 一 个 变 量 所 实 际 引 用 的 对 象 的 类 型 C++ 使 用 runtime-type information(rtti),java 使 用 instanceof 操 作 符 第 99 页

instanceof 运 算 符 功 能 : 用 来 判 断 某 个 实 例 变 量 是 否 属 于 某 种 类 的 类 型 一 旦 确 定 了 变 量 所 引 用 的 对 象 的 类 型 后, 可 以 将 对 象 恢 复 给 对 应 的 子 类 变 量, 以 获 取 对 象 的 完 整 功 能 示 例 如 下 : public class Employee extends Object{ public class Manager extends Employee { public class Contractor extends Employee{ 如 果 通 过 Employee 类 型 的 引 用 接 受 一 个 对 象, 它 变 不 变 成 Manager 或 Contractor 都 可 以 可 以 象 这 样 用 instanceof 来 测 试 : public void method(employee e) { if (e instanceof Manager) { // 如 果 雇 员 是 经 理, 可 以 做 的 事 情 写 在 这 里 else if (e instanceof Contractor) { // 如 果 雇 员 是 普 通 的 职 员, 可 以 做 的 事 情 写 在 这 里 else { // 说 明 是 临 时 雇 员, 可 以 做 的 事 情 写 在 这 里 4.5.5 多 态 对 象 的 类 型 转 换 在 你 接 收 父 类 的 一 个 引 用 时, 你 可 以 通 过 使 用 instanceof 运 算 符 判 定 该 对 象 实 际 上 是 你 所 要 的 子 类, 并 可 以 用 类 型 转 换 该 引 用 的 办 法 来 恢 复 对 象 的 全 部 功 能 public void method(employee e) { if (e instanceof Manager) { Manager m = (Manager)e; System.out.println(" This is the manager of " + m.department); // rest of operation 如 果 不 用 强 制 类 型 转 换, 那 么 引 用 e.department 的 尝 试 就 会 失 败, 因 为 编 译 器 不 能 将 被 称 做 department 的 成 员 定 位 在 Employee 类 中 如 果 不 用 instanceof 做 测 试, 就 会 有 类 型 转 换 失 败 的 危 险 通 常 情 况 下, 类 型 转 换 一 个 对 象 引 用 的 尝 试 是 要 经 过 几 种 检 查 的 : 向 上 强 制 类 型 转 换 类 层 次 总 是 允 许 的, 而 且 事 实 上 不 需 要 强 制 类 型 转 换 运 算 符 可 由 简 单 的 赋 值 实 现 严 格 讲 不 存 在 向 下 类 型 转 换, 其 实 就 是 强 制 类 型 转 换, 编 译 器 必 须 满 足 类 型 转 换 至 少 是 可 能 的 这 样 的 条 件 比 如, 任 何 将 Manager 引 用 类 型 转 换 成 Contractor 引 用 的 尝 试 是 肯 定 不 允 许 的, 因 为 Contractor 不 是 一 个 Manager 类 型 转 换 发 生 的 类 必 须 是 当 前 引 用 类 型 的 子 类 如 果 编 译 器 允 许 类 型 转 换, 那 么, 该 引 用 类 型 就 会 在 运 行 时 被 检 查 比 如, 如 果 第 100 页

instanceof 检 查 从 源 程 序 中 被 省 略, 而 被 类 型 转 换 的 对 象 实 际 上 不 是 它 应 被 类 型 转 换 进 去 的 类 型, 那 么, 就 会 发 生 一 个 运 行 时 错 误 (exception) 异 常 是 运 行 时 错 误 的 一 种 形 式, 而 且 是 后 面 章 节 的 主 题 4.6 static 4.6.1 static 修 饰 符 static 修 饰 符 能 够 与 属 性 方 法 和 内 部 类 一 起 使 用, 表 示 是 静 态 的 类 中 的 静 态 变 量 和 静 态 方 法 能 够 与 类 名 一 起 使 用, 不 需 要 创 建 一 个 类 的 对 象 来 访 问 该 类 的 静 态 成 员 所 以 static 修 饰 的 变 量 又 称 作 类 变 量 这 与 实 例 变 量 不 同 实 例 变 量 总 是 用 对 象 来 访 问, 因 为 它 们 的 值 在 对 象 和 对 象 之 间 有 所 不 同 下 列 示 例 展 示 了 如 何 访 问 一 个 类 的 静 态 变 量 : class StaticModifier { static int i = 10; int j; StaticModifier() { j = 20; public class Test { public static void main(string args[]) { System.out.println(" 类 变 量 i=" + StaticModifier.i); StaticModifier s = new StaticModifier(); System.out.println(" 实 例 变 量 j=" + s.j); 上 述 程 序 的 输 出 是 : 类 变 量 i=10 实 例 变 量 j=20 4.6.2 static 属 性 的 内 存 分 配 在 上 面 的 例 子 中, 无 需 创 建 类 的 对 象 即 可 访 问 静 态 变 量 i 之 所 以 会 产 生 这 样 的 结 果, 是 因 为 编 译 器 只 为 整 个 类 创 建 了 一 个 静 态 变 量 的 副 本, 因 此 它 能 够 用 类 名 进 行 访 问 也 就 是 说 : 一 个 类 中, 一 个 static 变 量 只 会 有 一 个 内 存 空 间, 虽 然 有 多 个 类 实 例, 但 这 些 类 实 例 中 的 这 个 static 变 量 会 共 享 同 一 个 内 存 空 间 示 例 如 下 : public class Test { 第 101 页

public static void main(string[] args) { UserModel um1 = new UserModel(); um.username = " 张 三 "; um.country = "china"; UserModel um2 = new UserModel(); um2.username = " 李 四 "; um2.country = " 中 国 "; System.out.println("um1.userName==" + um1.username + " um1.country==" + um1.country ); System.out.println("um2.userName==" + um2.username + " um2.country==" + um2.country ); class UserModel { public static String country public String username; 运 行 结 果 : um1.username== 张 三 um1.country== 中 国 um2.username== 李 四 um2.country== 中 国 为 什 么 会 是 一 样 的 值 呢? 就 是 因 为 多 个 UserModel 实 例 中 的 静 态 变 量 country 是 共 享 同 一 内 存 空 间,um1.country 和 um2.country 其 实 指 向 的 都 是 同 一 个 内 存 空 间, 所 以 就 得 到 上 面 的 结 果 了 在 对 象 um2 创 建 前 的 运 行 后 内 存 分 配 示 意 图 如 下 : um1 china 张 三 country username 在 对 象 um2 创 建 后 的 运 行 后 内 存 分 配 示 意 图 如 下 : um1 um2 中 国 张 三 李 四 country username username 要 想 看 看 是 不 是 static 导 致 这 样 的 结 果, 你 可 以 尝 试 去 掉 country 前 面 的 static, 然 后 再 试 一 试, 看 看 结 果, 应 该 如 下 : um1.username== 张 三 um1.country==china um2.username== 李 四 um2.country== 中 国 还 有 一 点 也 很 重 要 :static 的 变 量 是 在 类 装 载 的 时 候 就 会 被 初 始 化 也 就 是 说, 只 要 类 被 装 载, 不 管 你 是 否 使 用 了 这 个 static 变 量, 它 都 会 被 初 始 化 小 结 一 下 : 类 变 量 (class variables) 用 关 键 字 static 修 饰, 在 类 加 载 的 时 候, 分 配 第 102 页

类 变 量 的 内 存, 以 后 再 生 成 类 的 实 例 对 象 时, 将 共 享 这 块 内 存 ( 类 变 量 ), 任 何 一 个 对 象 对 类 变 量 的 修 改, 都 会 影 响 其 它 对 象 外 部 有 两 种 访 问 方 式 : 通 过 对 象 来 访 问 或 通 过 类 名 来 访 问 4.6.3 static 的 基 本 规 则 有 关 静 态 变 量 或 方 法 的 一 些 要 点 如 下 : 在 同 一 个 类 中, 静 态 方 法 只 能 访 问 静 态 属 性 或 方 法, 静 态 方 法 不 能 够 直 接 调 用 非 静 态 属 性 或 方 法 ; 如 果 访 问 控 制 权 限 允 许, 静 态 属 性 和 静 态 方 法 可 以 使 用 类 名 加. 方 式 调 用 ; 也 可 以 使 用 实 例 加. 方 式 调 用 ; 静 态 方 法 中 不 存 在 当 前 对 象, 因 而 不 能 使 用 this, 当 然 也 不 能 使 用 super; 静 态 方 法 不 能 被 非 静 态 方 法 覆 盖 ; 构 造 方 法 不 允 许 声 明 为 static 的 ; 局 部 变 量 不 能 使 用 static 修 饰 ; static 方 法 可 以 用 类 名 来 访 问, 如 : public class GeneralFunction { public static int addup(int x, int y) { return x + y; public class UseGeneral { public void method() { int a = 9; int b = 10; int c = GeneralFunction.addUp(a, b); System.out.println("addUp() gives " + c); 因 为 static 方 法 不 需 它 所 属 的 类 的 任 何 实 例 就 会 被 调 用, 因 此 没 有 this 值 结 果 是, static 方 法 不 能 访 问 与 它 本 身 的 参 数 以 及 static 变 量 之 外 的 任 何 变 量, 访 问 非 静 态 变 量 的 尝 试 会 引 起 编 译 错 误 注 : 非 静 态 变 量 只 限 于 实 例, 并 只 能 通 过 实 例 引 用 被 访 问 4.6.4 静 态 初 始 器 静 态 块 静 态 初 始 器 (Static Initializer) 是 一 个 存 在 与 类 中 方 法 外 面 的 静 态 块 静 态 初 始 器 仅 仅 在 类 装 载 的 时 候 ( 第 一 次 使 用 类 的 时 候 ) 执 行 一 次 静 态 初 始 器 的 功 能 是 : 往 往 用 来 初 始 化 静 态 的 类 属 性 示 例 : class Count { public static int counter; static {// 只 运 行 一 次 第 103 页

counter = 123; System.out.println("Now in static block."); public void test() { System.out.println("test method==" + counter); public class Test { public static void main(string args[]) { System.out.println("counter=" + Count.counter); new Count().test(); 运 行 结 果 是 : Now in static block. counter=123 test method==123 4.6.5 静 态 import( 选 修 ) 当 我 们 要 获 取 一 个 随 机 数 时, 写 法 是 : public class Test { public static void main(string[] args) { double randomnum = Math.random(); System.out.println("the randomnum==" + randomnum); 从 JDK5.0 开 始 可 以 写 为 : import static java.lang.math.random; public class Test { public static void main(string[] args) { double randomnum = random(); System.out.println("the randomnum==" + randomnum); 静 态 引 用 使 我 们 可 以 象 调 用 本 地 方 法 一 样 调 用 一 个 引 入 的 方 法, 当 我 们 需 要 引 入 同 一 个 类 的 多 个 方 法 时, 只 需 写 为 import static java.lang.math.* 即 可 这 样 的 引 用 方 式 对 于 枚 举 也 同 样 有 效 4.7 final 在 Java 中 声 明 类 属 性 和 方 法 时, 可 使 用 关 键 字 final 来 修 饰 final 所 标 记 的 成 分 具 有 终 态 的 特 征, 表 示 最 终 的 意 思 其 具 体 规 定 如 下 : 第 104 页

final 标 记 的 类 不 能 被 继 承 final 标 记 的 方 法 不 能 被 子 类 重 写 final 标 记 的 成 员 变 量 必 须 在 声 明 的 同 时 赋 值, 如 果 在 声 明 的 时 候 没 有 赋 值, 那 么 只 有 一 次 赋 值 的 机 会, 而 且 只 能 在 构 造 方 法 中 显 式 赋 值, 然 后 才 能 使 用 final 标 记 的 局 部 变 量 ( 成 员 变 量 或 局 部 变 量 ) 即 成 为 常 量, 只 能 赋 值 一 次 被 误 用, final 一 般 用 于 标 记 那 些 通 用 性 的 功 能 实 现 方 式 或 取 值 不 能 随 意 被 改 变 的 成 分, 以 避 免 例 如 实 现 数 学 三 角 方 法 幂 运 算 等 功 能 的 方 法, 以 及 数 学 常 量 π=3.141593 e=2.71828 等 事 实 上, 为 确 保 这 终 态 性, 提 供 了 上 述 方 法 和 常 量 的 java.lang.math 类 也 已 被 定 义 为 final 的 需 要 注 意 的 是, 如 果 将 引 用 类 型 ( 即, 任 何 类 的 类 型 ) 的 变 量 标 记 为 final, 那 么 该 变 量 不 能 指 向 任 何 其 它 对 象 但 可 以 改 0 变 对 象 的 内 容, 因 为 只 有 引 用 本 身 是 final 的 如 果 变 量 被 标 记 为 final, 其 结 果 是 使 它 成 为 常 数 想 改 变 final 变 量 的 值 会 导 致 一 个 编 译 错 误 下 面 是 一 个 正 确 定 义 final 变 量 的 例 子 : public final int MAX_ARRAY_SIZE = 25; 例 final 关 键 字 程 序 :Test.java public final class Test { public static final int TOTAL_NUMBER = 5; public int id; public Test() { id = ++TOTAL_NUMBER;// 非 法, 对 final 变 量 TOTAL_NUMBER 进 行 二 次 赋 值 了 // 因 为 ++TOTAL_NUMBER 相 当 于 :TOTAL_NUMBER=TOTAL_NUMBER+1 public static void main(string[] args) { final Test t = new Test(); final int i = 10; final int j; j = 20; j = 30; // 非 法, 对 final 变 量 进 行 二 次 赋 值 Java 编 程 语 言 允 许 关 键 字 final 被 应 用 到 类 上 ( 放 在 class 关 键 字 前 面 ) 如 果 这 样 做 了, 类 便 不 能 被 再 派 生 出 子 类 比 如, 类 Java.lang.String 就 是 一 个 final 类 这 样 做 是 出 于 安 全 原 因, 因 为 它 保 证, 如 果 方 法 有 字 符 串 的 引 用, 它 肯 定 就 是 类 String 的 字 符 串, 而 不 是 某 个 其 它 类 的 字 符 串, 这 个 类 是 String 的 被 修 改 过 的 子 类, 因 为 String 可 能 被 恶 意 窜 改 过 方 法 也 可 以 被 标 记 为 final 被 标 记 为 final 的 方 法 不 能 被 覆 盖 这 是 由 于 安 全 原 因 如 果 方 法 具 有 不 能 被 改 变 的 实 现, 而 且 对 于 对 象 的 一 致 状 态 是 关 键 的, 那 么 就 要 使 方 法 成 为 第 105 页

final 被 声 明 为 final 的 方 法 有 时 被 用 于 优 化 编 译 器 能 产 生 直 接 对 方 法 调 用 的 代 码, 而 不 是 通 常 的 涉 及 运 行 时 查 找 的 虚 拟 方 法 调 用 被 标 记 为 static 或 private 的 方 法 被 自 动 地 final, 因 为 动 态 联 编 在 上 述 两 种 情 况 下 都 不 能 应 用 思 考 题 : 使 用 final 修 饰 的 变 量 是 最 终 的 不 可 修 改, 如 果 变 量 指 向 引 用 数 据 类 型, 请 问 是 变 量 的 引 用 不 可 以 修 改, 还 是 引 用 的 对 象 不 可 以 修 改 4.8 再 谈 Java 内 存 分 配 Java 程 序 运 行 时 的 内 存 结 构 分 成 : 方 法 区 栈 内 存 堆 内 存 本 地 方 法 栈 几 种 栈 和 堆 都 是 数 据 结 构 的 知 识, 如 果 不 清 楚, 没 有 关 系, 就 当 成 一 个 不 同 的 名 字 就 好 了, 下 面 的 讲 解 不 需 要 用 到 它 们 具 体 的 知 识 4.8.1 方 法 区 方 法 区 存 放 装 载 的 类 数 据 信 息 包 括 : (1) 基 本 信 息 : 每 个 类 的 全 限 定 名 每 个 类 的 直 接 超 类 的 全 限 定 名 ( 可 约 束 类 型 转 换 ) 该 类 是 类 还 是 接 口 该 类 型 的 访 问 修 饰 符 直 接 超 接 口 的 全 限 定 名 的 有 序 列 表 (2) 每 个 已 装 载 类 的 详 细 信 息 : 运 行 时 常 量 池 : 存 放 该 类 型 所 用 的 一 切 常 量 ( 直 接 常 量 和 对 其 它 类 型 字 段 方 法 的 符 号 引 用 ), 它 们 以 数 组 形 式 通 过 索 引 被 访 问, 是 外 部 调 用 与 类 联 系 及 类 型 对 象 化 的 桥 梁 它 是 类 文 件 ( 字 节 码 ) 常 量 池 的 运 行 时 表 示 字 段 信 息 : 类 中 声 明 的 每 一 个 字 段 的 信 息 ( 名, 类 型, 修 饰 符 ) 方 法 信 息 : 类 中 声 明 的 每 一 个 方 法 的 信 息 ( 名, 返 回 类 型, 参 数 类 型, 修 饰 符, 方 法 的 字 节 码 和 异 常 表 ) 静 态 变 量 : 到 类 classloader 的 引 用 : 即 到 该 类 的 类 装 载 器 的 引 用 到 类 class 的 引 用 : 虚 拟 机 为 每 一 个 被 装 载 的 类 型 创 建 一 个 class 实 例, 用 来 代 表 这 个 被 装 载 的 类 4.8.2 栈 内 存 Java 栈 内 存 以 帧 的 形 式 存 放 本 地 方 法 的 调 用 状 态 ( 包 括 方 法 调 用 的 参 数, 局 部 变 量, 中 间 结 果 等 ) 每 调 用 一 个 方 法 就 将 对 应 该 方 法 的 方 法 帧 压 入 Java 栈, 成 为 当 前 方 法 帧 当 调 用 结 束 ( 返 回 ) 时, 就 弹 出 该 帧 编 译 器 将 源 代 码 编 译 成 字 节 码 (.class) 时, 就 已 经 将 各 种 类 型 的 方 法 的 局 部 变 量, 操 作 数 第 106 页

栈 大 小 确 定 并 放 在 字 节 码 中, 随 着 类 一 并 装 载 入 方 法 区 当 调 用 方 法 时, 通 过 访 问 方 法 区 中 的 类 的 信 息, 得 到 局 部 变 量 以 及 操 作 数 栈 的 大 小 也 就 是 说 : 在 方 法 中 定 义 的 一 些 基 本 类 型 的 变 量 和 对 象 的 引 用 变 量 都 在 方 法 的 栈 内 存 中 分 配 当 在 一 段 代 码 块 定 义 一 个 变 量 时,Java 就 在 栈 中 为 这 个 变 量 分 配 内 存 空 间, 当 超 过 变 量 的 作 用 域 后,Java 会 自 动 释 放 掉 为 该 变 量 所 分 配 的 内 存 空 间, 该 内 存 空 间 可 以 立 即 被 另 作 它 用 栈 内 存 的 构 成 : Java 栈 内 存 由 局 部 变 量 区 操 作 数 栈 帧 数 据 区 组 成 (1) 局 部 变 量 区 为 一 个 以 字 为 单 位 的 数 组, 每 个 数 组 元 素 对 应 一 个 局 部 变 量 的 值 调 用 方 法 时, 将 方 法 的 局 部 变 量 组 成 一 个 数 组, 通 过 索 引 来 访 问 若 为 非 静 态 方 法, 则 加 入 一 个 隐 含 的 引 用 参 数 this, 该 参 数 指 向 调 用 这 个 方 法 的 对 象 而 静 态 方 法 则 没 有 this 参 数 因 此, 对 象 无 法 调 用 静 态 方 法 (2) 操 作 数 栈 也 是 一 个 数 组, 但 是 通 过 栈 操 作 来 访 问 所 谓 操 作 数 是 那 些 被 指 令 操 作 的 数 据 当 需 要 对 参 数 操 作 时 如 a=b+c, 就 将 即 将 被 操 作 的 参 数 压 栈, 如 将 b 和 c 压 栈, 然 后 由 操 作 指 令 将 它 们 弹 出, 并 执 行 操 作 虚 拟 机 将 操 作 数 栈 作 为 工 作 区 (3) 帧 数 据 区 处 理 常 量 池 解 析, 异 常 处 理 等 4.8.3 堆 内 存 堆 内 存 用 来 存 放 由 new 创 建 的 对 象 和 数 组 在 堆 中 分 配 的 内 存, 由 Java 虚 拟 机 的 自 动 垃 圾 回 收 器 来 管 理 在 堆 中 产 生 了 一 个 数 组 或 对 象 后, 还 可 以 在 栈 中 定 义 一 个 特 殊 的 变 量, 让 栈 中 这 个 变 量 的 取 值 等 于 数 组 或 对 象 在 堆 内 存 中 的 首 地 址, 栈 中 的 这 个 变 量 就 成 了 数 组 或 对 象 的 引 用 变 量 引 用 变 量 就 相 当 于 是 为 数 组 或 对 象 起 的 一 个 名 称, 以 后 就 可 以 在 程 序 中 使 用 栈 中 的 引 用 变 量 来 访 问 堆 中 的 数 组 或 对 象 栈 内 存 和 堆 内 存 比 较 栈 与 堆 都 是 Java 用 来 在 内 存 中 存 放 数 据 的 地 方 与 C++ 不 同,Java 自 动 管 理 栈 和 堆, 程 序 员 不 能 直 接 地 设 置 栈 或 堆 Java 的 堆 是 一 个 运 行 时 数 据 区, 对 象 从 中 分 配 空 间 堆 的 优 势 是 可 以 动 态 地 分 配 内 存 大 小, 生 存 期 也 不 必 事 先 告 诉 编 译 器, 因 为 它 是 在 运 行 时 动 态 分 配 内 存 的,Java 的 垃 圾 收 集 器 会 自 动 收 走 这 些 不 再 使 用 的 数 据 但 缺 点 是, 由 于 要 在 运 行 时 动 态 分 配 内 存, 存 取 速 度 较 慢 栈 的 优 势 是, 存 取 速 度 比 堆 要 快, 仅 次 于 寄 存 器, 栈 数 据 可 以 共 享 但 缺 点 是, 存 在 栈 中 的 数 据 大 小 与 生 存 期 必 须 是 确 定 的, 缺 乏 灵 活 性 栈 中 主 要 存 放 一 些 基 本 类 型 的 变 量 ( int, short, long, byte, float, double, boolean, char) 和 对 象 句 柄 栈 有 一 个 很 重 要 的 特 殊 性, 就 是 存 在 栈 中 的 数 据 可 以 共 享 假 设 我 们 同 时 定 义 : int a = 3; int b = 3; 第 107 页

编 译 器 先 处 理 int a=3; 首 先 它 会 在 栈 中 创 建 一 个 变 量 为 a 的 引 用, 然 后 查 找 栈 中 是 否 有 3 这 个 值, 如 果 没 找 到, 就 将 3 存 放 进 来, 然 后 将 a 指 向 3 接 着 处 理 int b=3; 在 创 建 完 b 的 引 用 变 量 后, 因 为 在 栈 中 已 经 有 3 这 个 值, 便 将 b 直 接 指 向 3 这 样, 就 出 现 了 a 与 b 同 时 均 指 向 3 的 情 况 内 存 示 意 图 如 下 : 变 量 a 3 变 量 b 这 时, 如 果 再 令 b=4; 那 么 编 译 器 会 重 新 搜 索 栈 中 是 否 有 4 值, 如 果 没 有, 则 将 4 存 放 进 来, 并 令 a 指 向 4; 如 果 已 经 有 了, 则 直 接 将 a 指 向 这 个 地 址 因 此 a 值 的 改 变 不 会 影 响 到 b 的 值 要 注 意 这 种 数 据 的 共 享 与 两 个 对 象 的 引 用 同 时 指 向 一 个 对 象 的 这 种 共 享 是 不 同 的, 因 为 这 种 情 况 a 的 修 改 并 不 会 影 响 到 b, 它 是 由 编 译 器 完 成 的, 它 有 利 于 节 省 空 间 此 时 的 内 存 分 配 示 意 图 如 下 : 变 量 a 3 变 量 b 4 而 一 个 对 象 引 用 变 量 修 改 了 这 个 对 象 的 内 部 状 态, 会 影 响 到 另 一 个 对 象 引 用 变 量 4.8.4 本 地 方 法 栈 内 存 当 一 个 线 程 调 用 本 地 方 法 时, 它 就 不 再 受 到 虚 拟 机 关 于 结 构 和 安 全 限 制 方 面 的 约 束, 它 既 可 以 访 问 虚 拟 机 的 运 行 期 数 据 区, 也 可 以 使 用 本 地 处 理 器 以 及 任 何 类 型 的 栈 例 如, 本 地 栈 是 一 个 C 语 言 的 栈, 那 么 当 C 程 序 调 用 C 函 数 时, 函 数 的 参 数 以 某 种 顺 序 被 压 入 栈, 结 果 则 返 回 给 调 用 函 数 在 实 现 Java 虚 拟 机 时, 本 地 方 法 接 口 使 用 的 是 C 语 言 的 模 型 栈, 那 么 它 的 本 地 方 法 栈 的 调 度 与 使 用 则 完 全 与 C 语 言 的 栈 相 同 Java 通 过 Java 本 地 接 口 JNI(Java Native Interface) 来 调 用 其 它 语 言 编 写 的 程 序, 在 Java 里 面 用 native 修 饰 符 来 描 述 一 个 方 法 是 本 地 方 法 这 个 了 解 一 下 就 好 了, 在 我 们 的 课 程 中 不 会 涉 及 到 4.8.5 String 的 内 存 分 配 String 是 一 个 特 殊 的 包 装 类 数 据 可 以 用 : String str = new String("abc"); String str = "abc"; 两 种 的 形 式 来 创 建, 第 一 种 是 用 new() 来 新 建 对 象 的, 它 会 在 存 放 于 堆 中 每 调 用 一 次 就 会 创 建 一 个 新 的 对 象 而 第 二 种 是 先 在 栈 中 创 建 一 个 对 String 类 的 对 象 引 用 变 量 str, 然 后 查 找 栈 中 有 没 有 存 放 "abc", 如 果 没 有, 则 将 "abc" 存 放 进 栈, 并 令 str 指 向 "abc", 如 果 已 第 108 页

经 有 "abc" 则 直 接 令 str 指 向 "abc" 比 较 类 里 面 的 数 值 是 否 相 等 时, 用 equals() 方 法 ; 当 测 试 两 个 包 装 类 的 引 用 是 否 指 向 同 一 个 对 象 时, 用 = =, 下 面 用 例 子 说 明 上 面 的 理 论 String str1 = "abc"; String str2 = "abc"; System.out.println(str1==str2); //true 可 以 看 出 str1 和 str2 是 指 向 同 一 个 对 象 的 变 量 str1 "abc" 变 量 str2 String str1 = new String ("abc"); String str2 = new String ("abc"); System.out.println(str1==str2); // false 用 new 的 方 式 是 生 成 不 同 的 对 象 每 一 次 生 成 一 个 变 量 str1 变 量 str2 "abc" "abc" 因 此 用 第 一 种 方 式 创 建 多 个 "abc" 字 符 串, 在 内 存 中 其 实 只 存 在 一 个 对 象 而 已 这 种 写 法 有 利 于 节 省 内 存 空 间 同 时 它 可 以 在 一 定 程 度 上 提 高 程 序 的 运 行 速 度, 因 为 JVM 会 自 动 根 据 栈 中 数 据 的 实 际 情 况 来 决 定 是 否 有 必 要 创 建 新 对 象 而 对 于 String str = new String("abc"); 的 代 码, 则 一 概 在 堆 中 创 建 新 对 象, 而 不 管 其 字 符 串 值 是 否 相 等, 是 否 有 必 要 创 建 新 对 象, 从 而 加 重 了 程 序 的 负 担 另 一 方 面, 要 注 意 : 我 们 在 使 用 诸 如 String str = "abc"; 的 格 式 时, 总 是 想 当 然 地 认 为, 创 建 了 String 类 的 对 象 str 担 心 陷 阱! 对 象 可 能 并 没 有 被 创 建! 而 可 能 只 是 指 向 一 个 先 前 已 经 创 建 的 对 象 只 有 通 过 new() 方 法 才 能 保 证 每 次 都 创 建 一 个 新 的 对 象 由 于 String 类 的 值 不 可 变 性 (immutable), 当 String 变 量 需 要 经 常 变 换 其 值 时, 应 该 考 虑 使 用 StringBuffer 或 StringBuilder 类, 以 提 高 程 序 效 率 第 109 页

4.9 学 习 目 标 1. OOP( 面 向 对 象 ) 语 言 的 三 大 特 征 是? 2. 理 解 什 么 是 封 装, 封 装 的 好 处 3. 理 解 什 么 是 类 的 继 承, 继 承 的 好 处 4. 理 解 is-a 关 系 5. 理 解 父 子 类 的 初 始 化 顺 序 6. 理 解 类 的 单 继 承 性 7. 理 解 构 造 方 法 不 能 被 继 承 8. super 关 键 字 的 用 法, 为 什 么 使 用 super? 9. 什 么 是 方 法 的 覆 盖? 什 么 情 况 下 出 现? 10. 方 法 覆 盖 的 规 则? 11. 什 么 是 重 载? 什 么 情 况 下 出 现? 12. 简 述 重 载 的 规 则 13. 如 何 调 用 父 类 的 构 造 函 数? 如 何 调 用 自 己 的 构 造 函 数? 14. 如 何 确 定 在 多 态 的 调 用 中, 究 竟 是 调 用 的 那 个 方 法? 15. Instanceof 运 算 符 的 用 法 16. static 修 饰 符 的 功 能 是? 可 以 用 在 什 么 地 方? 怎 么 访 问? 17. static 的 基 本 规 则 18. final 修 饰 符 的 功 能 是? 可 以 用 在 什 么 地 方? 19. final 的 基 本 规 则 20. java 中 什 么 数 据 存 储 在 堆 内 存, 什 么 数 据 存 储 在 栈 内 存 21. 堆 内 存 有 什 么 特 点, 栈 内 存 有 什 么 特 点 第 110 页

4.10 练 习 1. 创 建 一 个 构 造 方 法 重 载 的 类, 并 用 另 一 个 类 调 用 2. 创 建 Rodent( 啮 齿 动 物 ):Mouse( 老 鼠 ),Gerbil( 鼹 鼠 ),Hamster( 大 颊 鼠 ) 等 的 一 个 继 承 分 级 结 构 在 基 础 类 中, 提 供 适 用 于 所 有 Rodent 的 方 法, 并 在 衍 生 类 中 覆 盖 它 们, 从 而 根 据 不 同 类 型 的 Rodent 采 取 不 同 的 行 动 创 建 一 个 Rodent 数 组, 在 其 中 填 充 不 同 类 型 的 Rodent, 然 后 调 用 自 己 的 基 础 类 方 法, 看 看 会 有 什 么 情 况 发 生 3. 编 写 MyPoint 的 一 个 子 类 MyXYZ, 表 示 三 维 坐 标 点, 重 写 tostring 方 法 用 来 显 示 这 个 对 象 的 x y z 的 值, 如 显 示 (1,2,3), 最 后 用 main 方 法 测 试 4. 当 你 试 图 编 译 和 执 行 下 面 的 程 序 时 会 发 生 什 么? class Mystery { String s; public static void main(string[] args) { Mystery m = new Mystery(); m.go(); void Mystery() { s = "constructor"; void go() { System.out.println(s); 选 择 下 面 的 正 确 答 案 : A. 编 译 不 通 过 B. 编 译 通 过 但 运 行 时 产 生 异 常 C. 代 码 运 行 但 屏 幕 上 看 不 到 任 何 东 西 D. 代 码 运 行, 屏 幕 上 看 到 constructor E. 代 码 运 行, 屏 幕 上 看 到 null 5. 当 编 译 和 运 行 下 列 程 序 段 时, 会 发 生 什 么? class Person { class Woman extends Person { class Man extends Person { 第 111 页

public class Test { public static void main(string argv[]) { Man m = new Man(); Woman w = (Woman) new Man(); A. 通 过 编 译 和 并 正 常 运 行 B. 编 译 时 出 现 例 外 C. 编 译 通 过, 运 行 时 出 现 例 外 D. 编 译 不 通 过 6. 对 于 下 列 代 码 : 1 class Person { 2 public void printvalue(int i, int j) {... 3 public void printvalue(int i){... 4 5 public class Teacher extends Person { 6 public void printvalue() {... 7 public void printvalue(int i) {... 8 public static void main(string args[]){ 9 Person t = new Teacher(); 10 t.printvalue(10); 11 12 第 10 行 语 句 将 调 用 哪 行 语 句? A. line 2 B. line 3 C. line 6 D. line 7 7. 下 列 代 码 运 行 结 果 是 什 么? public class Bool { static boolean b; public static void main(string[] args) { int x = 0; if (b) { x = 1; else if (b == false) { x = 2; else if (b) { x = 3; else { x = 4; System.out.println("x= " + x); 第 112 页

8. 完 成 此 段 代 码 可 以 单 独 添 加 哪 些 选 项? 1. public class Test { 2. 3. public static void main(string[] args) { 4. 5. System.out.println("c=" + c); 6. 7. A. 在 第 2 行 加 上 语 句 static char c; B. 在 第 2 行 加 上 语 句 char c; C. 在 第 4 行 加 上 语 句 static char c; D. 在 第 4 行 加 上 语 句 char c= f ; 9. 下 列 代 码 运 行 结 果 是 什 么? public class A { public static void main(stirng[] args) { int m = 2; int p = 1; int t = 0; for (; p < 5; p++) { if (t++ > m) { m = p + t; System.out.println("t equals" + t); A. 2 B. 4 C. 6 D. 7 10. 设 计 个 Circle 类, 其 属 性 为 圆 心 点 ( 类 型 为 前 面 设 计 的 类 MyPoint) 和 半 径, 并 为 此 类 编 写 以 下 三 个 方 法 : 一 是 计 算 圆 面 积 的 calarea() 方 法 ; 二 是 计 算 周 长 的 callength(); 三 是 boolean incircle(mypoint mp) 方 法, 功 能 是 测 试 作 为 参 数 的 某 个 点 是 否 在 当 前 对 象 圆 内 ( 圆 内, 包 括 圆 上 返 回 true; 在 圆 外, 返 回 false 第 113 页

5 数 组 和 枚 举 5.1 数 组 的 声 明 和 创 建 5.1.1 数 组 的 声 明 数 组 是 由 相 同 类 型 的 若 干 项 数 据 组 成 的 一 个 数 据 集 合, 数 组 中 的 每 个 数 据 称 为 元 素 也 就 是 说 数 组 是 用 来 集 合 相 同 类 型 的 对 象, 可 以 是 原 始 数 据 类 型 或 引 用 数 据 类 型 数 组 声 明 实 际 是 创 建 一 个 引 用, 通 过 代 表 引 用 的 这 个 名 字 来 引 用 数 组 数 组 声 明 格 式 如 下 : 数 据 类 型 标 识 符 [] 示 例 : char s[]; // 声 明 一 个 数 据 类 型 为 字 符 型 的 数 组 s Point arr[]; // 声 明 一 个 数 据 类 型 为 Point 的 数 组 arr 在 Java 编 程 语 言 中, 数 组 是 一 个 对 象, 声 明 不 能 创 建 对 象 本 身, 而 创 建 的 是 一 个 引 用, 该 引 用 可 被 用 来 引 用 数 组 数 组 元 素 使 用 的 实 际 内 存 可 由 new 语 句 或 数 组 初 始 化 软 件 动 态 分 配 在 后 面, 你 将 看 到 如 何 创 建 和 初 始 化 实 际 数 组 上 述 这 种 将 方 括 号 置 于 变 量 名 之 后 的 声 明 数 组 的 格 式, 是 用 于 C C++ 和 Java 编 程 语 言 的 标 准 格 式 这 种 格 式 会 使 声 明 的 格 式 复 杂 难 懂, 因 而,Java 编 程 语 言 允 许 一 种 替 代 的 格 式, 该 格 式 中 的 方 括 号 位 于 变 量 名 的 左 边 : char[] s; Point[] arr; 这 样 的 结 果 是, 你 可 以 认 为 类 型 部 分 在 左, 而 变 量 名 在 右 上 述 两 种 格 式 并 存, 你 可 选 择 一 种 你 习 惯 的 方 式 声 明 不 指 出 数 组 的 实 际 大 小 注 意 ---- 当 数 组 声 明 的 方 括 号 在 左 边 时, 该 方 括 号 可 应 用 于 所 有 位 于 其 右 的 变 量 5.1.2 创 建 数 组 数 据 对 象 和 其 他 Java 对 象 一 样, 使 用 关 键 字 new 创 建 创 建 的 时 候 要 指 明 数 组 的 长 度 s = new char [20]; p = new Point [100]; 第 一 行 创 建 了 一 个 20 个 char 类 型 元 素 的 数 组, 在 堆 区 为 数 组 分 配 内 存 空 间, 每 个 元 素 都 是 char 类 型 的, 占 2 个 字 节, 因 此 整 个 数 组 对 象 再 内 存 中 占 用 40 个 字 节 为 每 个 元 素 赋 予 其 数 据 类 型 的 默 认 值, 即 '\u0000' 返 回 数 组 对 象 的 引 用 赋 值 给 变 量 s 第 二 行 创 建 了 一 个 100 个 类 型 Point 的 变 量, 然 而, 它 并 不 是 创 建 100 个 Point 对 象 ; 创 第 114 页

建 100 个 对 象 的 工 作 必 须 分 别 完 成 如 下 : p[0] = new Point(); p[1] = new Point(); 用 来 指 示 单 个 数 组 元 素 的 下 标 必 须 总 是 从 0 开 始, 并 保 持 在 合 法 范 围 之 内 -- 大 于 0 或 等 于 0 并 小 于 数 组 长 度 任 何 访 问 在 上 述 界 限 之 外 的 数 组 元 素 的 企 图 都 会 引 起 运 行 时 出 错 数 组 的 下 标 也 称 为 数 组 的 索 引, 必 须 是 整 数 或 者 整 数 表 达 式, 如 下 : int i[] = new int[(9-2) * 3];// 这 是 合 法 的 其 实, 声 明 和 创 建 可 以 定 义 到 一 行, 而 不 用 分 开 写 5.1.3 数 组 的 初 始 化 当 创 建 一 个 数 组 时, 每 个 元 素 都 被 自 动 使 用 默 认 值 进 行 初 始 化 在 上 述 char 数 组 s 的 例 子 中, 每 个 值 都 被 初 始 化 为 0 (\u0000-null) 字 符 ; 在 数 组 p 的 例 子 中, 每 个 值 都 被 初 始 化 为 null, 表 明 它 还 未 引 用 一 个 Point 对 象 在 经 过 赋 值 p[0]=new Point() 之 后, 数 组 的 第 一 个 元 素 引 用 为 实 际 Point 对 象 注 意 -- 所 有 变 量 的 初 始 化 ( 包 括 数 组 元 素 ) 是 保 证 系 统 安 全 的 基 础, 变 量 绝 不 能 在 未 初 始 化 状 态 使 用 Java 编 程 语 言 允 许 使 用 下 列 形 式 快 速 创 建 数 组, 直 接 定 义 并 初 始 化 : String names[] = { "Georgianna", "Jen", "Simon" ; 其 结 果 与 下 列 代 码 等 同 : String names[]; names = new String[3]; names[0]="georgianna"; names[1]="jen"; names[2]="simon"; 这 速 记 法 可 用 在 任 何 元 素 类 型 例 如 : Myclass array[] = { new Myclass(), new Myclass(), new Myclass() ; 适 当 的 类 类 型 的 常 数 值 也 可 被 使 用 : import java.awt.color; Color palette [] ={ Color.blue, Color.red, Color.white ; 第 115 页

5.1.4 数 组 的 内 存 分 配 数 组 一 旦 被 创 建, 在 内 存 里 面 占 用 连 续 的 内 存 地 址 度 数 组 还 具 有 一 个 非 常 重 要 的 特 点 数 组 的 静 态 性 : 数 组 一 旦 被 创 建, 就 不 能 更 改 数 组 的 长 比 如, 定 义 数 组 如 下 : Point[] p = new Point [3]; 其 中 p 是 数 组 名, 数 组 长 度 是 3, 数 组 在 被 创 建 的 时 候, 内 存 示 意 图 如 下 : p 0x1fb8ee3 p[0] null p[1] null p[2] null 为 数 组 初 始 化 : p[0] = new Point() ; p[1] = new Point() ; p[2] = new Point() ; 内 存 示 意 图 如 下 : p 0x1fb8ee3 p[0] 0x1fb8d32 Point p[1] 0x1fb8ef3 Point p[2] 0x1fb8145 Point 5.2 数 组 元 素 的 访 问 5.2.1 使 用 length 属 性 在 Java 编 程 语 言 中, 所 有 数 组 的 下 标 都 从 0 开 始 一 个 数 组 中 元 素 的 数 量 被 作 为 具 有 length 属 性 的 部 分 数 组 对 象 而 存 储 ; 这 个 值 被 用 来 检 查 所 有 运 行 时 访 问 的 界 限 如 果 发 生 了 一 个 越 出 界 限 的 访 问, 那 么 运 行 时 的 报 错 也 就 出 现 了 使 用 length 属 性 的 例 子 如 下 : int[] list =new int [10]; for(int i=0;i<list.length;i++){ System.out.println( list[i] ); 使 用 length 属 性 使 得 程 序 的 维 护 变 得 更 简 单 第 116 页

所 有 元 素 的 访 问 就 通 过 数 组 的 下 标 来 访 问, 如 上 例 的 list[i], 随 着 i 的 值 发 生 变 化, 就 依 次 访 问 list[0] list[1] list[2] 如 果 想 要 给 某 个 数 组 元 素 赋 值, 如 下 方 式 : list[0]=5; list[1]=6; 示 例 : 假 如 定 义 一 个 数 组 : int c [] = new int[5]; // 进 行 赋 值 的 语 句 对 数 组 进 行 赋 值 后, 内 存 示 意 图 如 下 : c C[0] 35 C[1] 46 C[2] 57 C[3] 21 C[5] 135 然 后 就 可 以 根 据 数 组 名 [ 下 标 ] 来 取 值 了 如 : int a = c[3]; 结 果 就 是 : 从 数 组 中 取 出 下 标 为 3 的 元 素 的 值 21, 然 后 赋 值 给 a 5.2.2 更 优 化 的 for 循 环 语 句 在 访 问 数 组 的 时 候, 经 常 使 用 for 循 环 语 句 从 JDK5.0 开 始, 提 供 了 一 个 更 好 的 for 循 环 语 句 的 写 法, 示 例 如 下 : public class Test { public static void main(string args[]) { int a[] = new int[3]; // 旧 的 写 法, 赋 值 for (int i = 0; i < a.length; i++) { a[i] = i; // 新 的 写 法, 取 值 for (int i : a) { System.out.println(i); 显 然 JDK5.0 版 本 的 写 法 比 以 前 是 大 大 简 化 了 第 117 页

5.3 多 维 数 组 5.3.1 多 维 数 组 的 基 础 知 识 Java 编 程 语 言 没 有 象 其 它 语 言 那 样 提 供 多 维 数 组 因 为 一 个 数 组 可 被 声 明 为 具 有 任 何 基 础 类 型, 所 以 你 可 以 创 建 数 组 的 数 组 ( 和 数 组 的 数 组 的 数 组, 等 等 ) 一 个 二 维 数 组 如 下 例 所 示 : int twodim[][] = new int[4][]; twodim[0] = new int[5]; twodim[1] = new int[5]; 首 次 调 用 new 而 创 建 的 对 象 是 一 个 数 组, 它 包 含 4 个 元 素, 每 个 元 素 对 类 型 array of int 的 元 素 都 是 一 个 null 引 用 并 且 必 须 将 数 组 的 每 个 点 分 别 初 始 化 因 为 这 种 对 每 个 元 素 的 分 别 初 始 化, 所 以 有 可 能 创 建 非 矩 形 数 组 的 数 组 也 就 是 说, twodim 的 元 素 可 按 如 下 方 式 初 始 化 : twodim[0] = new int [2]; twodim[1] = new int [4]; twodim[2] = new int [6]; twodim[3] = new int [8]; 由 于 此 种 初 始 化 的 方 法 烦 琐 乏 味, 而 且 矩 形 数 组 的 数 组 是 最 通 用 的 形 式, 因 而 产 生 了 一 种 速 记 方 法 来 创 建 二 维 数 组 例 如 : int twodim[][] = new int [3][4]; 可 被 用 来 创 建 一 个 每 个 数 组 有 4 个 整 数 类 型 的 3 个 数 组 的 数 组 可 以 理 解 成 为 如 下 表 格 所 示 : twodim[0][0] twodim[0][1] twodim[0][2] twodim[0][3] twodim[1][0] twodim[1][1] twodim[1][2] twodim[1][3] twodim[2][0] twodim[2][1] twodim[2][2] twodim[2][3] 第 一 个 方 括 号 中 的 数 字 表 示 行, 第 二 个 方 括 号 中 的 数 字 表 示 列, 注 意 都 是 从 0 开 始 的 尽 管 声 明 的 格 式 允 许 方 括 号 在 变 量 名 左 边 或 者 右 边, 但 此 种 灵 活 性 不 适 用 于 数 组 句 法 的 其 它 方 面 例 如 : new int [][4] 是 非 法 的 5.3.2 示 例 class FillArray { public static void main(string args[]) { int[][] matrix = new int[4][5]; // 二 维 数 组 的 声 明 和 创 建 for (int row = 0; row < 4; row++) { for (int col = 0; col < 5; col++) { 第 118 页

matrix[row][col] = row + col; // 二 维 数 组 的 访 问, 为 元 素 赋 值 当 然 也 可 以 直 接 定 义 并 赋 值, 如 下 : double[][] c = { { 1.0, 2.0, 3.0, 4.0, { 0.0, 1.0, 0.0, 0.0, { 0.0, 0.0, 1.0, 0.0 ; 从 上 面 可 以 看 得 很 清 楚, 二 维 数 组 其 实 就 是 一 维 的 一 维 数 组 5.3.3 多 维 数 组 的 本 质 N 维 数 组 就 是 一 维 的 N-1 维 数 组, 比 如 : 三 维 数 组 就 是 一 维 的 二 维 数 组 三 维 以 至 多 维 数 组 都 是 一 个 思 路, 一 维 数 组 二 维 数 组 三 维 数 组 的 实 例 : class Fill3DArray { public static void main(string args[]) { int[][][] M = new int[4][5][3]; for (int row = 0; row < 4; row++) { for (int col = 0; col < 5; col++) { for (int ver = 0; ver < 3; ver++) { M[row][col][ver] = row + col + ver; 5.4 数 组 的 复 制 组 : 数 组 一 旦 创 建 后, 其 大 小 不 可 调 整 然 而, 你 可 使 用 相 同 的 引 用 变 量 来 引 用 一 个 全 新 的 数 int myarray []= new int [6]; myarray = new int [10]; 在 这 种 情 况 下, 第 一 个 数 组 被 有 效 地 丢 失, 除 非 对 它 的 其 它 引 用 保 留 在 其 它 地 方 Java 编 程 语 言 在 arraycopy() 例 如,araycopy 可 作 如 下 使 用 : System 类 中 提 供 了 一 种 特 殊 方 法 拷 贝 数 组, 该 方 法 被 称 作 // 原 始 数 组 第 119 页

int myarray[] = { 1, 2, 3, 4, 5, 6 ; // 新 的 数 组, 比 原 始 数 组 大 int hold[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ; // 把 原 始 数 组 的 值 拷 贝 到 新 的 数 组 System.arraycopy(myArray, 0, hold, 0, myarray.length); 拷 贝 完 成 后, 数 组 hold 有 如 下 内 容 :1,2,3,4,5,6,4,3,2,1 不 改 变 注 意 在 处 理 对 象 数 组 时,System.arraycopy() 拷 贝 的 是 引 用, 而 不 是 对 象 对 象 本 身 5.5 数 组 的 排 序 5.5.1 基 本 的 排 序 算 法 5.5.1.1 冒 泡 排 序 对 几 个 无 序 的 数 字 进 行 排 序, 比 较 常 用 的 方 法 是 冒 泡 排 序 法 冒 泡 法 排 序 是 一 个 比 较 简 单 的 排 序 方 法, 在 待 排 序 的 数 列 基 本 有 序 的 情 况 下 排 序 速 度 较 快 基 本 思 路 : 对 未 排 序 的 各 元 素 从 头 到 尾 依 次 比 较 相 邻 的 两 个 元 素 是 否 逆 序 ( 与 欲 排 顺 序 相 反 ), 若 逆 序 就 交 换 这 两 元 素, 经 过 第 一 轮 比 较 排 序 后 便 可 把 最 大 ( 或 最 小 ) 的 元 素 排 好, 然 后 再 用 同 样 的 方 法 把 剩 下 的 元 素 逐 个 进 行 比 较, 就 得 到 了 你 所 要 的 顺 序 可 以 看 出 如 果 有 N 个 元 素, 那 么 一 共 要 进 行 N-1 轮 比 较, 第 I 轮 要 进 行 N-I 次 比 较 ( 如 : 有 5 个 元 素, 则 要 进 行 5-1 轮 比 较 第 3 轮 则 要 进 行 5-3 次 比 较 ) 示 例 如 下 : public class Test3 { public static void main(string[] args) { // 需 要 排 序 的 数 组, 目 前 是 按 照 升 序 排 列 的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // 冒 泡 排 序 for (int i = 0; i < a.length-1; i++) { for (int j = 0; j < a.length-1; j++) { // 判 断 相 邻 的 两 个 元 素 是 否 逆 序 if (a[j] > a[j+1]) { int temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; 第 120 页

// 检 测 一 下 排 序 的 结 果 for (int i : a) { System.out.println("i=" + i); 运 行 结 果 : i=1 i=2 i=3 i=4 i=5 如 果 你 想 要 按 照 降 序 排 列, 很 简 单, 只 需 把 :if(a[j] > a[j+1]) 改 成 :if(a[j] < a[j+1]) 就 可 以 了 5.5.1.2 选 择 排 序 基 本 思 路 : 从 所 有 元 素 中 选 择 一 个 最 小 元 素 a[i] 放 在 a[0]( 即 让 最 小 元 素 a[i] 与 a[0] 交 换 ), 作 为 第 一 轮 ; 第 二 轮 是 从 a[1] 开 始 到 最 后 的 各 个 元 素 中 选 择 一 个 最 小 元 素, 放 在 a[1] 中 ; 依 次 类 推 n 个 数 要 进 行 (n-1) 轮 比 较 的 次 数 与 冒 泡 法 一 样 多, 但 是 在 每 一 轮 中 只 进 行 一 次 交 换, 比 冒 泡 法 的 交 换 次 数 少, 相 对 于 冒 泡 法 效 率 高 示 例 如 下 : public class Test { public static void main(string[] args) { // 需 要 排 序 的 数 组, 目 前 是 按 照 升 序 排 列 的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // 选 择 法 排 序 int temp; for (int i = 0; i < a.length; i++) { int lowindex = i; // 找 出 最 小 的 一 个 的 索 引 for (int j = i + 1; j < a.length; j++) { if (a[j] < a[lowindex]) { lowindex = j; // 交 换 temp = a[i]; a[i] = a[lowindex]; a[lowindex] = temp; // 检 测 一 下 排 序 的 结 果 for (int i : a) { 第 121 页

System.out.println("i=" + i); 运 行 结 果 : i=1 i=2 i=3 i=4 i=5 如 果 你 想 要 按 照 降 序 排 列, 很 简 单, 只 需 要 把 :if (a[j] <a[lowindex]) 这 句 话 修 改 成 : if (a[j] > a[lowindex]) 就 可 以 了 5.5.1.3 插 入 法 排 序 基 本 思 路 : 每 拿 到 一 个 元 素, 都 要 将 这 个 元 素 与 所 有 它 之 前 的 元 素 遍 历 比 较 一 遍, 让 符 合 排 序 顺 序 的 元 素 挨 个 移 动 到 当 前 范 围 内 它 最 应 该 出 现 的 位 置 举 个 例 子 来 说, 就 用 前 面 的 数 组, 我 们 要 对 一 个 有 5 个 元 素 的 数 组 进 行 升 序 排 列, 假 设 第 一 个 元 素 的 值 被 假 定 为 已 排 好 序 了, 那 么 我 们 就 将 第 2 个 元 素 与 数 组 中 的 部 分 进 行 比 较, 如 果 第 2 个 元 素 的 值 较 小, 则 将 它 插 入 到 第 1 个 元 素 的 前 面, 现 在 就 有 两 个 元 素 排 好 序 了, 我 们 再 将 没 有 排 序 的 元 素 与 排 好 序 的 元 素 列 表 进 行 比 较, 同 样, 如 果 小 于 第 一 个 元 素, 就 将 它 插 入 到 第 一 个 元 素 前 面, 但 是, 如 果 大 于 第 一 个 元 素 的 话, 我 们 就 将 它 再 与 第 2 个 元 素 的 值 进 行 比 较, 小 于 的 话 就 排 在 第 2 个 元 素 前 面, 大 于 的 话, 就 排 在 第 2 个 元 素 的 后 面 以 此 类 推, 直 到 最 后 一 个 元 素 排 好 序 示 例 如 下 : public class Test { public static void main(string[] args) { // 需 要 排 序 的 数 组, 目 前 是 按 照 升 序 排 列 的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // 插 入 法 排 序 int temp; for (int i = 1; i < a.length; i++) { // i=1 开 始, 因 为 第 一 个 元 素 认 为 是 已 经 排 好 序 了 的 for (int j = i; (j > 0) && (a[j] < a[j - 1]); j--) { // 交 换 temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; 第 122 页

// 检 测 一 下 排 序 的 结 果 for (int i : a) { System.out.println("i=" + i); 运 行 结 果 : i=1 i=2 i=3 i=4 i=5 如 果 你 想 要 按 照 降 序 排 列, 很 简 单, 只 需 要 把 :if (a[j] <a[lowindex]) 这 句 话 修 改 成 : if (a[j] > a[lowindex]) 就 可 以 了 5.5.1.4 希 尔 (Shell) 法 排 序 从 前 面 介 绍 的 冒 泡 排 序 法, 选 择 排 序 法, 插 入 排 序 法 可 以 发 现, 如 果 数 据 已 经 大 致 排 好 序 的 时 候, 其 交 换 数 据 位 置 的 动 作 将 会 减 少 例 如 在 插 入 排 序 法 过 程 中, 如 果 某 一 整 数 d[i] 不 是 较 小 时, 则 其 往 前 比 较 和 交 换 的 次 数 会 更 少 如 何 用 简 单 的 方 式 让 某 些 数 据 有 一 定 的 大 小 次 序 呢? Donald Shell(Shell 排 序 的 创 始 人 ) 提 出 了 希 尔 法 排 序 基 本 思 路 : 先 将 数 据 按 照 固 定 的 间 隔 分 组, 例 如 每 隔 4 个 分 成 一 组, 然 后 排 序 各 分 组 的 数 据, 形 成 以 分 组 来 看 数 据 已 经 排 序, 从 全 部 数 据 来 看, 较 小 值 已 经 在 前 面, 较 大 值 已 经 在 后 面 将 初 步 处 理 了 的 分 组 再 用 插 入 排 序 来 排 序, 那 么 数 据 交 换 和 移 动 的 次 数 会 减 少 可 以 得 到 比 插 入 排 序 法 更 高 的 效 率 示 例 如 下 : public class Test { public static void main(string[] args) { // 需 要 排 序 的 数 组, 按 照 升 序 排 列 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // shell 法 排 序 int j = 0; int temp = 0; // 分 组 for(int increment = a.length / 2; increment > 0; increment /= 2) { // 每 个 组 内 排 序 for (int i = increment; i < a.length; i++) { 第 123 页

temp = a[i]; for (j = i; j >= increment; j -= increment) { if (temp < a[j - increment]) { a[j] = a[j - increment]; else { break; a[j] = temp; // 检 测 一 下 排 序 的 结 果 for (int i2 : a) { System.out.println("i=" + i2); 运 行 结 果 : i=1 i=2 i=3 i=4 i=5 如 果 你 想 要 按 照 降 序 排 列, 很 简 单, 只 需 要 把 :if (temp < a[j - increment]) 这 句 话 修 改 成 :if (temp > a[j - increment]) 就 可 以 了 5.5.2 数 组 排 序 事 实 上, 数 组 的 排 序 不 用 那 么 麻 烦, 上 面 只 是 想 让 大 家 对 一 些 基 本 的 排 序 算 法 有 所 了 解 而 已 在 java.util.arrays 类 中 有 一 个 静 态 方 法 sort, 可 以 用 这 个 类 的 sort 方 法 来 对 数 组 进 行 排 序 示 例 如 下 : public class Test { public static void main(string[] args) { // 需 要 排 序 的 数 组, 目 前 是 按 照 升 序 排 列 的 int a[] = new int[5]; a[0] = 3; a[1] = 4; a[2] = 1; a[3] = 5; a[4] = 2; // 数 组 排 序 java.util.arrays.sort(a); // 检 测 一 下 排 序 的 结 果 for (int i2 : a) { System.out.println("i=" + i2); 第 124 页

注 意 : 现 在 的 sort 方 法 都 是 升 序 的, 要 想 实 现 降 序 的, 还 需 要 Comparator 的 知 识, 这 个 在 后 面 会 学 到 5.6 数 组 实 用 类 Arrays 在 java.util 包 中, 有 一 个 用 于 操 纵 数 组 的 实 用 类 Arrays 它 提 供 了 一 系 列 静 态 方 法, 帮 助 开 发 人 员 操 作 数 组 public static boolean equals( 数 组 参 数 1, 数 组 参 数 2) 比 较 两 个 数 组 参 数 是 否 相 同, 数 组 参 数 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 只 有 当 两 个 数 组 中 的 元 素 数 目 相 同, 并 且 对 应 位 置 的 元 素 也 相 同 时, 才 表 示 数 组 相 同 如 果 是 引 用 类 型 的 数 组, 比 较 的 是 引 用 类 型 的 equals 方 法 示 例 如 下 : String[] a1={"java 快 车 ","javakc","javakc"; String[] a2={"java 快 车 ","javakc","javakc"; System.out.print(Arrays.equals(a1, a2)); 运 行 结 果 :true public static void fill( 数 组, 数 据 参 数 ) 向 数 组 中 填 充 数 据 参 数, 把 数 组 中 所 有 元 素 的 值 设 置 为 该 数 据 数 组 和 数 据 参 数 的 类 型 必 须 一 致, 或 可 以 自 动 转 化, 数 组 和 元 素 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 示 例 如 下 : // 基 本 数 据 类 型 或 字 符 串 String[] arr=new String[5]; Arrays.fill(arr, "Java 快 车 "); for(string s:arr){ System.out.print(s+","); // 引 用 数 据 类 型, 使 用 了 同 一 个 引 用 A[] arr2=new A[5]; Arrays.fill(arr2, new A()); for(a a:arr2){ System.out.print(a+","); 运 行 结 果 如 下 : Java 快 车,Java 快 车,Java 快 车,Java 快 车,Java 快 车, A@5224ee,A@5224ee,A@5224ee,A@5224ee,A@5224ee, public static void fill( 数 组,int fromindex, int toindex, 数 据 参 数 ) 向 数 组 中 指 定 的 范 围 填 充 数 据 参 数, 此 范 围 包 含 fromindex, 但 不 包 含 toindex 数 组 和 数 据 参 数 的 类 型 必 须 一 致, 或 可 以 自 动 转 化, 数 组 和 元 素 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 示 例 如 下 : 第 125 页

String[] arr=new String[5]; Arrays.fill(arr,1,3,"Java 快 车 "); for(string s:arr){ System.out.print(s+","); 运 行 结 果 如 下 : null,java 快 车,Java 快 车,null,null, public static int binarysearch( 数 组, 数 据 参 数 ) 查 找 数 组 中 元 素 的 值 与 给 定 数 据 相 同 的 元 素 数 组 和 数 据 参 数 的 类 型 必 须 一 致, 或 可 以 自 动 转 化, 数 组 和 数 据 参 数 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 因 为 此 方 法 采 用 二 分 法 进 行 查 找 数 据, 所 以 当 调 用 该 方 法 时, 必 须 保 证 数 组 中 的 元 素 已 经 按 照 升 序 排 列, 这 样 才 能 得 到 正 确 的 结 果 如 果 该 数 组 包 含 此 数 据 参 数, 则 返 回 对 应 的 数 组 下 标, 否 则 返 回 一 个 负 数 示 例 如 下 : int[] arr={2,4,6,7,9,10,20; System.out.print(Arrays.binarySearch(arr, 9)); 运 行 结 果 :4 int[] arr={2,4,6,7,9,10,20; System.out.print(Arrays.binarySearch(arr, 8)); 运 行 结 果 :-6 public static int binarysearch( 数 组,int fromindex,int toindex, 数 据 参 数 ) 在 数 组 中 指 定 的 范 围 查 找 元 素 的 值 与 给 定 数 据 相 同 的 元 素 其 他 说 明 如 上 示 例 如 下 : double[] arr={2,4,6,7,9,10,20; System.out.print(Arrays.binarySearch(arr,1,5,10)); 运 行 结 果 :-6 public static void sort( 数 组 ) 把 数 组 中 的 数 组 按 升 序 排 列 数 组 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 public static void copyof( 数 组,int newlength) 赋 值 指 定 的 数 组, 截 取 下 标 0( 包 括 ) 至 newlength( 不 包 括 ) 范 围 示 例 如 下 : int[] arr={2,4,6,7,9,10,20; int[] arr2=arrays.copyof(arr, 4); for(int i:arr2){ System.out.print(i+","); 运 行 结 果 :2,4,6,7, public static 数 组 copyofrange( 数 组,int from,int to) 将 数 组 的 指 定 范 围 复 制 到 一 个 新 数 组 数 组 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 第 126 页

示 例 如 下 : int[] arr={2,4,6,7,9,10,20; int[] arr2=arrays.copyofrange(arr,1,5); for(int i:arr2){ System.out.print(i+","); 运 行 结 果 :4,6,7,9, public static String tostring( 数 组 ) 返 回 指 定 数 组 内 容 的 字 符 串 表 示 形 式 数 组 可 以 是 基 本 数 据 类 型, 也 可 以 是 引 用 数 据 类 型 示 例 如 下 : int[] arr={2,4,6,7,9,10,20; System.out.print(Arrays.toString(arr)); 运 行 结 果 :[2, 4, 6, 7, 9, 10, 20] 5.7 枚 举 类 型 ( 可 选 ) 5.7.1 什 么 是 枚 举 类 型 枚 举 类 型 enum 是 一 种 新 的 类 型, 在 JDK5.0 加 入, 允 许 用 常 量 来 表 示 特 定 的 数 据 片 断, 这 些 数 据 是 分 配 时 预 先 定 义 的 值 的 集 合, 而 且 全 部 都 以 类 型 安 全 的 形 式 来 表 示 在 枚 举 类 型 没 有 加 入 到 Java 前, 我 们 要 想 表 达 常 量 的 集 合, 通 常 采 用 如 下 的 方 式 : public class Test { public static final int A = 1; public static final int B = 2; public static final int C = 3; public static final int D = 4; public static final int E = 5; 那 么 我 们 在 使 用 的 时 候 就 采 用 如 下 代 码 : Test.A 或 者 Test.B 之 类 的 代 码 但 是 在 这 样 做 的 时 候, 我 们 需 要 记 住 这 类 常 量 是 Java 中 int 类 型 的 常 量, 这 意 味 着 该 方 法 可 以 接 受 任 何 int 类 型 的 值, 即 使 它 和 Test 中 定 义 的 所 有 级 别 都 不 对 应 因 此 需 要 检 测 上 界 和 下 界, 在 出 现 无 效 值 的 时 候, 可 能 还 要 包 含 一 个 IllegalArgumentException 而 且, 如 果 后 来 又 添 加 另 外 一 个 级 别 ( 例 如 TEST.F, 那 么 必 须 改 变 所 有 代 码 中 的 上 界, 才 能 接 受 这 个 新 值 换 句 话 说, 在 使 用 这 类 带 有 整 型 常 量 的 类 时, 该 解 决 方 案 也 许 可 行, 但 并 不 是 非 常 有 效 第 127 页

枚 举 就 为 处 理 上 述 问 题 提 供 了 更 好 的 方 法 把 上 面 的 例 子 改 成 用 枚 举 的 方 式 : public class Test { public enum StudentGrade { A, B, C, D, E, F ; 可 以 采 用 如 下 的 方 式 进 行 使 用 : public class Test { public enum StudentGrade { A, B, C, D, E, F ; public static void main(string[] args) { System.out.println(" 学 生 的 平 均 成 绩 为 ==" + StudentGrade.B); 上 面 的 示 例 都 相 当 简 单, 但 是 枚 举 类 型 提 供 的 东 西 远 不 止 这 些 您 可 以 逐 个 遍 历 枚 举 值, 也 可 以 在 switch 语 句 中 使 用 枚 举 值, 枚 举 是 非 常 有 价 值 的 5.7.2 遍 历 枚 举 类 型 示 例 如 下 : public class Test { public enum StudentGrade { A, B, C, D, E, F ; public static void main(string[] args) { for (StudentGrade score : StudentGrade.values()) { System.out.println(" 学 生 成 绩 取 值 可 以 为 ==" + score); 运 行 结 果 : 学 生 成 绩 取 值 可 以 为 ==A 学 生 成 绩 取 值 可 以 为 ==B 学 生 成 绩 取 值 可 以 为 ==C 学 生 成 绩 取 值 可 以 为 ==D 学 生 成 绩 取 值 可 以 为 ==E 学 生 成 绩 取 值 可 以 为 ==F values() 方 法 返 回 了 一 个 由 独 立 的 StudentGrade 实 例 构 成 的 数 组 还 有 一 个 常 用 的 方 法 :valueof(string): 功 能 是 以 字 符 串 的 形 式 返 回 某 一 个 具 体 枚 举 元 素 的 值, 示 例 如 下 : public class Test { public enum StudentGrade { 第 128 页

A, B, C, D, E, F ; public static void main(string[] args) { Test t = new Test(); StudentGrade score = StudentGrade.valueOf("A"); System.out.println(" 你 的 成 绩 是 :" + score); 运 行 结 果 : 你 的 成 绩 是 :A 5.7.3 在 switch 中 使 用 枚 举 类 型 示 例 如 下 : public class Test { public enum StudentGrade { A, B, C, D, E, F ; public static void main(string[] args) { Test t = new Test(); StudentGrade score = StudentGrade.C; switch (score) { case A: System.out.println(" 你 的 成 绩 是 优 秀 "); break; case B: System.out.println(" 你 的 成 绩 是 好 "); break; case C: System.out.println(" 你 的 成 绩 是 良 "); break; case D: System.out.println(" 你 的 成 绩 是 及 格 "); break; default: System.out.println(" 你 的 成 绩 是 不 及 格 "); break; 运 行 结 果 : 你 的 成 绩 是 良 在 这 里, 枚 举 值 被 传 递 到 switch 语 句 中, 而 每 个 case 子 句 将 处 理 一 个 特 定 的 值 该 值 在 提 供 时 没 有 枚 举 前 缀, 这 意 味 着 不 用 将 代 码 写 成 case StudentGrade.A, 只 需 将 其 写 成 case A 即 可, 编 译 器 不 会 接 受 有 前 缀 的 值 第 129 页

5.7.4 枚 举 类 型 的 特 点 从 上 面 的 示 例 中 可 以 看 出, 枚 举 类 型 大 概 有 如 下 特 点 : 类 型 安 全 紧 凑 有 效 的 枚 举 数 值 定 义 运 行 的 高 效 率 类 型 安 全 枚 举 的 申 明 创 建 了 一 个 新 的 类 型 它 不 同 于 其 它 的 已 有 类 型, 包 括 原 始 类 型 ( 整 数, 浮 点 数 等 等 ) 和 当 前 作 用 域 (Scope) 内 的 其 它 的 枚 举 类 型 当 你 对 方 法 的 参 数 进 行 赋 值 操 作 的 时 候, 整 数 类 型 和 枚 举 类 型 是 不 能 互 换 的 ( 除 非 是 你 进 行 显 式 的 类 型 转 换 ), 编 译 器 将 强 制 这 一 点 比 如 说, 用 上 面 申 明 的 枚 举 定 义 这 样 一 个 方 法 : public void foo(day); 如 果 你 用 整 数 来 调 用 这 个 函 数, 编 译 器 会 给 出 错 误 的 必 须 用 这 个 类 型 的 值 进 行 调 用 foo(4); // compilation error 比 较 前 面 写 的 例 子, 你 看 看 是 枚 举 定 义 写 得 紧 凑, 还 是 直 接 使 用 static final 紧 凑 呢 答 案 是 不 言 而 喻 的 枚 举 的 运 行 效 率 和 原 始 类 型 的 整 数 类 型 基 本 上 一 样 高 在 运 行 时 不 会 由 于 使 用 了 枚 举 而 导 致 性 能 有 所 下 降 第 130 页

5.8 学 习 目 标 1. 熟 练 使 用 一 维 数 组 的 声 明 创 建 初 始 化 访 问 2. 了 解 一 维 数 组 的 内 存 分 配, 能 画 出 内 存 分 配 图 3. 会 用 for 循 环 访 问 一 维 数 组 4. 熟 练 使 用 二 维 数 组 的 声 明 创 建 初 始 化 访 问 5. 描 述 多 维 数 组 的 本 质 :n 维 数 组 是 一 维 的 n-1 维 6. 了 解 二 维 数 组 的 内 存 分 配, 能 画 出 内 存 分 配 图 7. 会 用 嵌 套 for 循 环 访 问 二 维 数 组 8. 能 画 出 引 用 数 据 类 型 的 数 组 的 内 存 分 配 图 9. 如 何 完 成 数 组 的 复 制 10. 了 解 冒 泡 排 序 选 择 排 序 插 入 排 序 希 尔 排 序 算 法, 最 少 能 默 写 出 其 中 一 种 排 序 算 法 11. 熟 练 掌 握 Arrays 工 具 类 中 的 方 法 能 说 出 大 部 分 方 法 的 方 法 名 称 完 成 的 功 能, 甚 至 参 数 列 表 返 回 值 类 型 抛 出 的 异 常 第 131 页

5.9 练 习 1. 写 一 个 方 法, 在 方 法 内 部 定 义 一 个 一 维 的 int 数 组, 然 后 为 这 个 数 组 赋 上 初 始 值, 最 后 再 循 环 取 值 并 打 印 出 来 2. 下 面 的 数 组 定 义 那 些 是 正 确 的? A. int a[ ][ ] = new int[3,3]; B. int a[3][3] = new int[ ][ ]; C. int a[ ][ ] = new int[3][3]; D. int [ ]a[ ] = new int[3][3]; E. int [ ][ ]a = new int[3][3]; 3. 定 义 一 个 长 度 为 10 的 一 维 字 符 串 数 组, 在 每 一 个 元 素 存 放 一 个 单 词 ; 然 后 运 行 时 从 命 令 行 输 入 一 个 单 词, 程 序 判 断 数 组 是 否 包 含 有 这 个 单 词, 包 含 这 个 单 词 就 打 印 出 Yes, 不 包 含 就 打 印 出 No 4. 请 在 下 面 语 句 中 找 出 一 个 正 确 的 A. int arr1[2][3]; B. int[ ][ ] a2 = new int[2][ ]; C. int[ ][ ] arr2 = new int [ ][4]; D. int arr3[ ][4] = new int [3][4]; 5. 用 二 重 循 环 求 出 二 维 数 组 b 所 有 元 素 的 和 : int[ ][ ] b={{11,{21,22,{31,32,33 6. 编 写 一 个 方 法 实 现 将 班 级 同 学 的 名 单 存 放 在 数 组 中, 并 利 用 随 机 数 (Math.random()) 随 机 输 出 一 位 同 学 的 姓 名 7. 生 成 一 百 个 随 机 数, 放 到 数 组 中, 然 后 排 序 输 出 8. 统 计 字 符 串 中 英 文 字 母 空 格 数 字 和 其 它 字 符 的 个 数 提 示 :String 类 中 有 一 个 tochararray 方 法, 可 以 将 此 字 符 串 转 换 成 一 个 char 类 型 的 数 组, 另 外 还 需 要 用 到 asc 码 第 132 页

6 常 见 类 的 使 用 在 java 中 有 成 百 上 千 的 类, 每 个 类 又 有 很 多 不 同 的 方 法, 要 记 住 所 有 的 类 和 方 法 是 不 可 能 的 因 此, 熟 练 掌 握 如 何 查 阅 API 是 相 当 重 要 的 从 中 可 以 查 到 标 准 库 中 所 有 的 类 及 方 法 Api 文 档 是 Java SDK 的 一 部 分, 它 以 HTML 形 式 发 布 Api 的 主 页 面 有 三 个 窗 口 组 成 左 上 端 的 窗 口 列 出 了 所 有 可 以 利 用 的 包, 坐 下 端 是 所 有 可 用 的 类, 如 果 点 击 一 个 类 名, 关 于 这 个 Api 的 文 档 将 会 显 示 在 右 边 最 大 的 窗 格 关 于 类 的 声 明 属 性 构 造 方 法 成 员 方 法 及 其 他 们 的 说 明 文 字 都 在 这 个 大 窗 口 打 开 下 面 我 们 介 绍 几 个 在 Java 中 常 用 的 类 6.1 Object 类 java.lang 包 中 定 义 的 Object 类 是 所 有 Java 类 的 根 父 类, 其 中 定 义 了 一 些 实 现 和 支 持 面 向 对 象 机 制 的 重 要 方 法 任 何 Java 对 象, 如 果 没 有 父 类, 就 默 认 它 继 承 了 Object 类 因 此, 实 际 上, 以 前 的 定 义 是 下 面 的 简 略 : public class Employee extends Object public class Manager extends Employee Object 类 定 义 许 多 有 用 的 方 法, 包 括 tostring(), 它 就 是 为 什 么 Java 软 件 中 每 样 东 西 都 能 转 换 成 字 符 串 表 示 法 的 原 因 ( 即 使 这 仅 具 有 有 限 的 用 途 ) 6.1.1 equals 方 法 Object 类 定 义 的 equals 方 法 用 于 判 别 某 个 指 定 的 对 象 与 当 前 对 象 ( 调 用 equals 方 法 第 133 页

的 对 象 ) 是 否 等 价 在 Java 语 言 中 数 据 等 价 的 基 本 含 义 是 指 两 个 数 据 的 值 相 等 在 equals 和 == 进 行 比 较 的 时 候, 引 用 类 型 数 据 比 较 的 是 引 用, 即 内 存 地 址, 基 本 数 据 类 型 比 较 的 是 值 6.1.1.1 equals 方 法 与 == 运 算 符 的 关 系 equals() 方 法 只 能 比 较 引 用 类 型, == 可 以 比 较 引 用 类 型 及 基 本 类 型 ; 特 例 : 当 用 equals() 方 法 进 行 比 较 时, 对 类 File String Date 及 包 装 类 来 说, 是 比 较 类 型 及 内 容 而 不 考 虑 引 用 的 是 否 是 同 一 个 实 例 ; 用 == 进 行 比 较 时, 符 号 两 边 的 数 据 类 型 必 须 一 致 ( 可 自 动 转 换 的 数 据 类 型 除 外 ), 否 则 编 译 出 错, 而 用 equals 方 法 比 较 的 两 个 数 据 只 要 都 是 引 用 类 型 即 可 示 例 如 下 : class MyDate { private int day, month, year; public MyDate(int day, int month, int year) { this.day = day; this.month = month; this.year = year; public class Test { public static void main(string[] args) { MyDate m1 = new MyDate(8, 8, 2008); MyDate m2 = new MyDate(8, 8, 2008); if (m1 == m2) { System.out.println("m1==m2"); else { System.out.println("m1!=m2"); if (m1.equals(m2)) { System.out.println("m1 is equal to m2"); else { System.out.println("m1 is not equal to m2"); m2 = m1; if (m1 == m2) { System.out.println("m1==m2"); else { System.out.println("m1!=m2"); 第 134 页

程 序 运 行 结 果 为 : m1!=m2 m1 is not equal to m2 m==m2 小 结 一 下 : 在 引 用 类 型 的 比 较 上,Object 里 面 的 equals 方 法 默 认 的 比 较 方 式, 基 本 上 等 同 于 ==, 都 是 比 较 内 存 地 址, 只 有 那 几 个 特 殊 的 是 比 较 的 值 6.1.1.2 覆 盖 equals 方 法 对 于 程 序 员 来 说, 如 果 一 个 对 象 需 要 调 用 equals 方 法, 应 该 在 类 中 覆 盖 equals 方 法 如 果 覆 盖 了 equals 方 法, 那 么 具 体 的 比 较 就 按 照 你 的 实 现 进 行 比 较 了 一 般 来 讲 : 为 了 比 较 两 个 分 离 的 对 象 ( 也 就 是 内 存 地 址 不 同 的 两 个 对 象 ), 自 行 覆 盖 的 equals 方 法 里 面 都 是 检 查 类 型 和 值 是 否 相 同 上 面 那 几 个 特 殊 的 情 况 就 是 这 样, 比 如 String 类, 它 覆 盖 了 equals 方 法, 然 后 在 里 面 进 行 值 的 比 较 覆 盖 equals 方 法 的 一 般 步 骤 如 下 : (1) 用 == 检 查 是 否 参 数 就 是 这 个 对 象 的 引 用 (2) 判 断 要 比 较 的 对 象 是 否 为 null, 如 果 是 null, 返 回 false (3) 用 instanceof 判 断 参 数 的 类 型 是 否 正 确 (4) 把 参 数 转 换 成 合 适 的 类 型 (5) 比 较 对 象 属 性 值 是 不 是 匹 配 示 例 如 下 : 覆 盖 前 equals 和 == 比 较 的 都 是 内 存 地 址 : public class Test { public static void main(string[] args) { A a1 = new A(); a1.id = 3; A a2 = new A(); a2.id = 3; System.out.println("a1 == a2 test =" + (a1 == a2)); System.out.println("a1 equals a2 test =" + a1.equals(a2)); class A { public int id = 0; 第 135 页

运 行 结 果 是 : a1== a2 test =false a1 equals a2 test =false 覆 盖 后 equals 比 较 的 是 值,== 比 较 的 是 内 存 地 址 : public class Test { public static void main(string[] args) { Test t = new Test(); A a1 = new A(); a1.id = 3; A a2 = new A(); a2.id = 3; System.out.println("a1 == a2 test =" + (a1 == a2)); System.out.println("a1 equals a2 test =" + a1.equals(a2)); class A { public int id = 0; public boolean equals(object obj) { // 第 一 步 先 判 断 是 否 同 一 个 实 例 if (this == obj) { return true; // 第 二 步 判 断 要 比 较 的 对 象 是 否 为 null if (obj == null) { return false; // 第 三 步 判 断 是 否 同 一 个 类 型 if (obj instanceof A) { // 第 四 步 类 型 相 同, 先 转 换 成 为 同 一 个 类 型 A a = (A) obj; // 第 五 步 然 后 进 行 对 象 属 性 值 的 比 较 if (this.id == a.id) { return true; else { return false; else { // 类 型 不 同, 直 接 返 回 false return false; 说 明 : 如 果 对 象 的 属 性 又 是 一 个 引 用 类 型 的 话, 会 继 续 调 用 该 引 用 类 型 的 equals 方 法, 直 到 最 后 得 出 相 同 还 是 不 同 的 结 果 示 例 如 下 : public class Test { public static void main(string[] args) { 第 136 页

Test t = new Test(); A a1 = new A(); a1.id = 3; A a2 = new A(); a2.id = 3; System.out.println("a1 == a2 test =" + (a1 == a2)); System.out.println("a1 equals a2 test =" + a1.equals(a2)); class A { public int id = 0; public String name = "Java 快 车 "; public boolean equals(object obj) { // 第 一 步 先 判 断 是 否 同 一 个 实 例 if (this == obj) { return true; // 第 二 步 判 断 要 比 较 的 对 象 是 否 为 null if (obj == null) { return false; // 第 三 步 判 断 是 否 同 一 个 类 型 if (obj instanceof A) { // 第 四 步 类 型 相 同, 先 转 换 成 为 同 一 个 类 型 A a = (A) obj; // 第 五 步 然 后 进 行 对 象 属 性 值 的 比 较 if (this.id == a.id && this.name.equals(a.name)) { return true; else { return false; else { // 类 型 不 同, 直 接 返 回 false return false; 最 后 重 要 的 一 点 规 则 : 覆 盖 equals 方 法 应 该 连 带 覆 盖 hashcode 方 法 6.1.2 hashcode 方 法 hashcode 是 按 照 一 定 的 算 法 得 到 的 一 个 数 值, 是 对 象 的 散 列 码 值 主 要 用 来 在 集 合 ( 后 面 会 学 到 ) 中 实 现 快 速 查 找 等 操 作, 也 可 以 用 于 对 象 的 比 较 在 Java 中, 对 hashcode 的 规 定 如 下 : (1) 在 同 一 个 应 用 程 序 执 行 期 间, 对 同 一 个 对 象 调 用 hashcode(), 必 须 返 回 相 同 的 整 数 第 137 页

结 果 前 提 是 equals() 所 比 较 的 信 息 都 不 曾 被 改 动 过 至 于 同 一 个 应 用 程 序 在 不 同 执 行 期 所 得 的 调 用 结 果, 无 需 一 致 ( 2 ) 如 果 两 个 对 象 被 equals(object) 方 法 视 为 相 等, 那 么 对 这 两 个 对 象 调 用 hashcode() 必 须 获 得 相 同 的 整 数 结 果 (3) 如 果 两 个 对 象 被 equals(object) 方 法 视 为 不 相 等, 那 么 对 这 两 个 对 象 调 用 hashcode() 不 必 产 生 不 同 的 整 数 结 果 然 而 程 序 员 应 该 意 识 到, 对 不 同 对 象 产 生 不 同 的 整 数 结 果, 有 可 能 提 升 hashtable( 后 面 会 学 到, 集 合 框 架 中 的 一 个 类 ) 的 效 率 简 单 地 说 : 如 果 两 个 对 象 相 同, 那 么 它 们 的 hashcode 值 一 定 要 相 同 ; 如 果 两 个 对 象 的 hashcode 相 同, 它 们 并 不 一 定 相 同 在 Java 规 范 里 面 规 定, 覆 盖 equals 方 法 应 该 连 带 覆 盖 hashcode 方 法, 这 就 涉 及 到 一 个 如 何 实 现 hashcode 方 法 的 问 题 了 实 现 一 : 偷 懒 的 做 法 : 对 同 一 对 象 始 终 返 回 相 同 的 hashcode, 如 下 : public int hashcode() { return 1; 它 是 合 法 的, 但 是 不 好, 因 为 每 个 对 象 具 有 相 同 的 hashcode, 会 使 得 很 多 使 用 hashcode 的 类 的 运 行 效 率 大 大 降 低, 甚 至 发 生 错 误 实 现 二 : 采 用 一 定 的 算 法 来 保 证 在 高 效 Java 编 程 这 本 书 里 面, 给 大 家 介 绍 了 一 个 算 法, 现 在 eclipse 自 动 生 成 equals 方 法 和 hashcode 方 法 就 是 用 的 这 个 算 法, 下 面 介 绍 一 下 这 个 算 法 : (1) 将 一 个 非 0 常 数, 例 如 31, 储 存 于 int result 变 量 (2) 对 对 象 中 的 每 个 有 意 义 的 属 性 f( 更 确 切 的 说 是 被 equals() 所 考 虑 的 每 一 个 属 性 ) 进 行 如 下 处 理 : A. 对 这 个 属 性 计 算 出 类 型 为 int 的 hash 码 c: 如 果 属 性 是 个 boolean, 计 算 (f? 0 : 1) 如 果 属 性 是 个 byte,char,short 或 int, 计 算 (int)f 如 果 属 性 是 个 long, 计 算 (int)(f ^ (f >>> 32)) 如 果 属 性 是 个 float, 计 算 Float.floatToIntBits(f) 如 果 属 性 是 个 double, 计 算 Double.doubleToLongBits(f), 然 后 将 计 算 结 果 按 步 骤 2.A.iii 处 理 第 138 页

如 果 属 性 是 个 对 象 引 用, 而 且 class 的 equals() 通 过 递 归 调 用 equals() 的 方 式 来 比 较 这 一 属 性, 那 么 就 同 样 也 对 该 属 性 递 归 调 用 hashcode() 如 果 需 要 更 复 杂 的 比 较, 请 对 该 属 性 运 算 一 个 范 式 (canonical representation), 并 对 该 范 式 调 用 hashcode() 如 果 属 性 值 是 null, 就 返 回 0( 或 其 它 常 数 ; 返 回 0 是 传 统 做 法 ) 如 果 属 性 是 个 数 组, 请 将 每 个 元 素 视 为 独 立 属 性 也 就 是 说 对 每 一 个 有 意 义 的 元 素 施 行 上 述 规 则, 用 以 计 算 出 hash 码, 然 后 再 依 步 骤 2.B 将 这 些 数 值 组 合 起 来 B. 将 步 骤 A 计 算 出 来 的 hash 码 c 按 下 列 公 式 组 合 到 变 量 result 中 : result = 31*result + c; (3) 返 回 result 示 例 如 下 : 这 个 就 是 用 eclipse 自 动 生 成 的 import java.util.arrays; public class Test { private byte bytevalue; private char charvalue; private short shortvalue; private int intvalue; private long longvalue; private boolean booleanvalue; private float floatvalue; private double doublevalue; private String uuid; private int[] intarray = new int[3]; public int hashcode() { final int prime = 31; int result = 1; result = prime * result + (booleanvalue? 1231 : 1237); result = prime * result + charvalue; long temp; temp = Double.doubleToLongBits(doubleValue); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + Float.floatToIntBits(floatValue); result = prime * result + Arrays.hashCode(intArray); result = prime * result + intvalue; result = prime * result + (int) (longvalue ^ (longvalue >>> 32)); result = prime * result + shortvalue; result = prime * result + ((uuid == null)? 0 : uuid.hashcode()); return result; 第 139 页

6.1.3 tostring 方 法 tostring() 方 法 是 Object 类 中 定 义 的 另 一 个 重 要 方 法, 是 对 象 的 字 符 串 表 现 形 式, 其 格 式 为 : public String tostring(){ 方 法 的 返 回 值 是 String 类 型, 用 于 描 述 当 前 对 象 的 有 关 信 息 Object 类 中 实 现 的 tostring() 方 法 是 返 回 当 前 对 象 的 类 型 和 内 存 地 址 信 息, 但 在 一 些 子 类 ( 如 String, Date 等 ) 中 进 行 了 重 写, 也 可 以 根 据 需 要 在 用 户 自 定 义 类 型 中 重 写 tostring() 方 法, 以 返 回 更 适 用 的 信 息 除 显 式 调 用 对 象 的 tostring() 方 法 外, 在 进 行 String 与 其 它 类 型 数 据 的 连 接 操 作 时, 会 自 动 调 用 tostring() 方 法, 其 中 又 分 为 两 种 情 况 : (1) 引 用 类 型 数 据 直 接 调 用 其 tostring() 方 法 转 换 为 String 类 型 ; (2) 基 本 类 型 数 据 先 转 换 为 对 应 的 包 装 类 型, 再 调 用 该 包 装 类 的 tostring() 方 法 转 换 为 String 类 型 另 外, 在 System.out.println() 方 法 输 出 引 用 类 型 的 数 据 时, 也 先 自 动 调 用 了 该 对 象 的 tostring() 方 法, 然 后 再 将 返 回 的 字 符 串 输 出 示 例 如 下 : class MyDate { private int day, month, year; public MyDate(int d, int m, int y) { day = d; month = m; year = y; class YourDate { private int day, month, year; public YourDate(int d, int m, int y) { day = d; month = m; year = y; public String tostring() { return day + "-" + month + "-" + year; public class Test { public static void main(string args[]) { MyDate m = new MyDate(8, 8, 2008); System.out.println(m); 第 140 页

System.out.println(m.toString()); YourDate y = new YourDate(8, 8, 2008); System.out.println(y); 运 行 结 果 : cn.javadriver.java6.test.mydate@1fb8ee3 cn.javadriver.java6.test.mydate@1fb8ee3 8-8-2008 tostring 方 法 被 用 来 将 一 个 对 象 转 换 成 String 表 达 式 当 自 动 字 符 串 转 换 发 生 时, 它 被 用 作 编 译 程 序 的 参 照 System.out.println() 调 用 下 述 代 码 : Date now = new Date() ; System.out.println(now); // 将 被 翻 译 成 : System.out.println(now.toString()); 对 象 类 定 义 缺 省 的 tostring() 方 法, 它 返 回 类 名 称 和 它 的 引 用 的 地 址 ( 通 常 情 况 下 不 是 很 有 用 ) 许 多 类 覆 盖 tostring() 以 提 供 更 有 用 的 信 息 例 如, 所 有 的 包 装 类 覆 盖 tostring() 以 提 供 它 们 所 代 表 的 值 的 字 符 串 格 式 甚 至 没 有 字 符 串 格 式 的 类 为 了 调 试 目 的 常 常 实 现 tostring() 来 返 回 对 象 状 态 信 息 6.2 String 类 6.2.1 String 的 声 明 和 创 建 双 引 号 括 起 来 的 字 符 序 列 就 是 String 的 直 接 量 实 例 :"John" 或 "111222333" 字 符 串 赋 值, 可 以 在 声 明 时 赋 值 : String color = "blue"; color 是 String 类 型 的 引 用 "blue" 是 String 直 接 量 String 类 型 的 数 据 存 在 String 常 量 池 ( 栈 内 存 ) 中, 一 旦 定 义 值 就 不 能 改 变, 只 能 是 让 变 量 指 向 新 的 内 存 空 间 比 如 : color = "red"; 如 果 采 用 new 的 方 法 定 义 String, 那 么 是 需 要 分 配 堆 内 存 空 间 的, 如 下 : String str = new String("Hello"); 一 共 有 两 个 对 象, 在 栈 和 堆 内 存 中 各 有 一 个 对 象, 内 容 都 是 "Hello" String 的 还 有 两 个 常 用 的 构 造 方 法 : 第 141 页

String(byte[] arr) 使 用 一 个 字 节 数 组 arr 创 建 一 个 字 符 串 对 象 String(char[] arr) 使 用 一 个 字 符 数 组 arr 创 建 一 个 字 符 串 对 象 char[] arr={'h','e','l','l','o'; String str = new String(arr); // 相 当 于 String str = new String("Hello"); String(char[] arr,int startindex,int count) 提 取 字 符 数 组 a 中 的 一 部 分 字 符 创 建 一 个 字 符 串 对 象, 参 数 startindex 和 count 分 别 指 定 在 a 中 提 取 字 符 的 起 始 位 置 和 从 该 位 置 开 始 截 取 的 字 符 个 数, 例 如 : char[] arr={'h','e','l','l','o'; String str = new String(arr,1,3); // 相 当 于 String str = new String("ell"); 6.2.2 String 的 常 用 方 法 6.2.2.1 得 到 字 符 串 的 长 度 public int length() 返 回 String 的 长 度, 是 按 照 char 返 回 的 长 度 与 数 组 不 同 之 处 : String 类 不 含 有 length 成 员 域 ( 属 性 ) String str = "java 快 车 www.javakc.com"; System.out.println(str.length());//20 6.2.2.2 比 较 字 符 串 对 于 字 符 串, 使 用 == 比 较 的 是 内 存 地 址, 一 般 不 使 用 == 比 较 字 符 串 public boolean equals(object s) 比 较 两 个 String 对 象 的 实 体 是 否 相 等, 这 个 是 区 分 大 小 写 的 实 际 上 就 是 依 次 比 较 其 所 包 含 的 字 符 的 数 值 大 小 String s1= new String("java 快 车 "); String s2= new String("java 快 车 "); System.out.println(s1.equals(s2));//true public boolean equalsignorecase(string s) 比 较 两 个 String 对 象 的 值 是 否 相 等, 忽 略 大 小 写 第 142 页

String s1= new String("java 快 车 "); String s2= new String("JAVA 快 车 "); System.out.println(s1.equalsIgnoreCase(s2));//true public int compareto(string s) 比 较 两 个 字 符 串 的 大 小 返 回 0 表 示 相 等, 返 回 大 于 0 的 数 表 示 前 面 的 字 符 串 大 于 后 面 的 字 符 串, 返 回 小 于 0 表 示 前 面 的 字 符 串 小 于 后 面 的 字 符 串, 区 分 大 小 写 的 如 下 : public class Test { public static void main(string[] args) { int x="abc".compareto("abc"); System.out.println(x);//0 x="bbc".compareto("abc"); System.out.println(x);//1 int x="abc".compareto("bbc"); System.out.println(x);//-1 int x="cbc".compareto("abc"); System.out.println(x);//2 运 行 结 果 : the str 小 于 str2 public int comparetoignorecase(string s) 忽 略 大 小 写, 比 较 两 个 字 符 串 的 大 小 返 回 0 表 示 相 等, 返 回 大 于 0 的 数 表 示 前 面 的 字 符 串 大 于 后 面 的 字 符 串, 返 回 小 于 0 表 示 前 面 的 字 符 串 小 于 后 面 的 字 符 串 如 下 : public class Test { public static void main(string[] args) { int x="abc".comparetoignorecase("abc"); System.out.println(x);//0 运 行 结 果 :the str 等 于 str2 public boolean startswith(stirng prefix) 测 试 此 字 符 串 是 否 以 指 定 的 前 缀 开 始 第 143 页

public class Test { public static void main(string[] args) { String str = " 这 里 是 Java 快 车 "; String str2 = "Java"; System.out.println(str.startsWith(str2)); 运 行 结 果 :false public boolean startswith(string prefix,int toffset) 测 试 此 字 符 串 从 指 定 索 引 开 始 的 子 字 符 串 是 否 以 指 定 前 缀 开 始 public class Test { public static void main(string[] args) { String str = " 这 里 是 Java 快 车 "; String str2 = "Java"; System.out.println(str.startsWith(str2, 3)); 运 行 结 果 :true public boolean endswith(string suffix) 测 试 此 字 符 串 是 否 以 指 定 的 后 缀 结 束 public class Test { public static void main(string[] args) { String str = " 这 里 是 Java 快 车 "; String str2 = " 快 车 "; System.out.println(str.endsWith(str2)); 运 行 结 果 :true 6.2.2.3 字 符 串 检 索 public char charat(int index) 获 得 字 符 串 指 定 位 置 的 字 符 String s="javakc"; // 取 得 字 符 串 s 中 下 标 为 2 的 字 符 char c=s.charat(2); System.out.println(c);// 输 出 'v' 第 144 页

// 取 得 字 符 串 s 中 下 标 为 6 的 字 符 char c2=s.charat(6); System.out.println(c2);// 抛 出 StringIndexOutOfBoundsException 异 常 public int indexof(int ch) 返 回 指 定 字 符 ch 在 此 字 符 串 中 第 一 次 出 现 处 的 索 引 String name="cooltools"; System.out.println(name.indexOf('T'));//4 public int indexof(string str) 返 回 第 一 次 找 到 字 符 串 str 时 的 索 引, 如 果 没 有 找 到, 则 返 回 -1 实 例 : String name="cooltools"; System.out.println(name.indexOf("oo"));//1 System.out.println(name.indexOf("kc"));//-1 public int indexof(int ch,int fromindex) 从 指 定 的 索 引 开 始 搜 索, 返 回 在 此 字 符 串 中 第 一 次 出 现 指 定 字 符 处 的 索 引, 如 果 没 有 找 到, 则 返 回 -1 String name="cooltools"; System.out.println(name.indxOf('l',5));//7 public int indexof(string str,int fromindex) 指 定 的 索 引 开 始 搜 索, 返 回 在 此 字 符 串 中 第 一 次 出 现 指 定 字 符 串 处 的 索 引, 如 果 没 有 找 到, 则 返 回 -1 String name="cooltools"; System.out.println(name.indexOf("oo",3));//5 public int lastindexof(string str) 返 回 指 定 子 字 符 串 在 此 字 符 串 中 最 右 边 出 现 处 的 索 引 laseindexof 有 四 中 重 载 方 法, 用 法 和 indexof 相 似 6.2.2.4 截 取 字 符 串 public String substring(int beginindex) 返 回 新 的 字 符 串, 它 是 当 前 字 符 串 的 子 串 该 子 串 从 指 定 的 位 置 开 始, 并 一 直 到 当 前 字 符 串 结 束 为 止 第 145 页

public String substring(int beginindex,int endindex) 返 回 新 的 字 符 串, 它 是 当 前 字 符 串 的 子 串 该 子 串 从 指 定 的 位 置 (beginindex ) 开 始, 到 指 定 的 位 置 (endindex - 1) 结 束 例 如 : "unhappy".substring(2); // 返 回 "happy" "Harbison".substring(3); // 返 回 "bison" "emptiness".substring(9); // 返 回 ""( 空 串 ) "emptiness".substring(10); // 返 回 StringIndexOutOfBoundsException "hamburger".substring(4,8); // 返 回 "urge" "smiles".substring(1,5); // 返 回 "mile" 6.2.2.5 替 换 public String trim() 返 回 新 字 符 串, 截 去 了 源 字 符 串 最 前 面 和 最 后 面 的 的 空 白 符 ; 如 果 字 符 串 没 有 被 改 变, 则 返 回 源 字 符 串 的 引 用 String s=" java kc "; // 截 去 字 符 串 两 边 的 空 格 String s2=s.trim(); System.out.println(s2.length());//7 public String replace(char oldchar,char newchar) public String replace(charsequence target, CharSequence replacement) 返 回 一 个 新 的 字 符 串, 它 是 将 字 符 串 中 的 所 有 oldchar 替 换 成 newchar 源 字 符 串 没 有 发 生 变 化 如 果 该 字 符 串 不 含 oldchar, 则 返 回 源 字 符 串 的 引 用 实 例 : "mesquite in your cellar".replace('e','o');// 返 回 "mosquito in your collar" "JonL".replace('q','x'); // 结 果 返 回 "JonL" ( 没 有 发 生 变 化 ) 示 例 将 字 符 串 中 所 有 空 格 删 除 : String s=" java kc "; // 将 全 部 空 格 替 换 成 空 字 符 串, 即 将 所 有 空 格 删 除 String s2=s.replace(" ", ""); System.out.println(s2);// 输 出 javakc public String replaceall(string regex, String replacement) 使 用 给 定 的 replacement 替 换 此 字 符 串 中 所 有 匹 配 给 定 的 正 则 表 达 式 的 子 字 符 串 源 字 符 串 没 有 发 生 变 化 第 146 页

如 果 该 字 符 串 不 含 regex, 则 返 回 源 字 符 串 的 引 用 String s="javakc35javakc36javakc37"; // 将 数 字 全 部 换 成 * 号 String s2=s.replaceall("\\d","*");// \\d 在 正 则 表 达 式 中 表 示 数 字 System.out.println(s2);// 输 出 javakc**javakc**javakc** public String touppercase( ) 返 回 对 应 的 新 字 符 串, 所 有 小 写 字 母 都 变 为 大 写 的, 其 它 的 不 变 如 果 没 有 字 符 被 修 改, 则 返 回 字 符 串 的 引 用 String s="javakc"; // 小 写 转 换 成 大 写 String s2=s.touppercase(); System.out.println(s2);// 输 出 JAVAKC public String tolowercase() 返 回 对 应 的 新 字 符 串, 所 有 大 写 字 母 都 变 为 小 写 的, 其 它 的 不 变 如 果 没 有 字 符 被 修 改, 则 返 回 字 符 串 的 引 用 String s="javakc"; // 大 写 转 换 成 小 写 String s2=s.tolowercase(); System.out.println(s2);// 输 出 javakc 6.2.2.6 字 符 串 分 解 成 数 组 public byte[] getbytes() 组 中 使 用 平 台 的 默 认 字 符 集 将 此 String 编 码 为 byte 序 列, 并 将 结 果 存 储 到 一 个 新 的 byte 数 String s="javakc 快 车 "; // 将 字 符 串 转 换 成 字 节 数 组 byte[] a=s.getbytes(); // 输 出 [106, 97, 118, 97, 75, 67, -65, -20, -77, -75] System.out.println(Arrays.toString(a)); // 将 字 节 数 组 转 换 成 字 符 串 String s2=new String(a); System.out.println(s2);// 输 出 javakc 快 车 对 于 字 符 串 中 的 汉 字, 是 按 照 char 来 计 算 的, 一 个 中 文 汉 字 占 两 个 字 节, 也 就 是 说, 通 过 length() 得 到 的 是 字 符 串 char 的 长 度, 而 不 是 字 节 数, 利 用 这 个 特 点, 就 可 以 进 行 中 文 判 断 了 例 如 : 如 何 判 断 一 个 字 符 串 里 面 有 没 有 中 文 呢? 如 果 字 符 串 对 应 的 byte[] 和 char[] 的 长 第 147 页

度 是 不 一 样 的, 那 就 说 明 包 含 中 文, 还 可 以 顺 带 计 算 出 有 几 个 汉 字 public class Test { public static void main(string[] args) { String str = " 欢 迎 来 到 Java 快 车 "; int charlen = str.length(); int bytelen = str.getbytes().length; if (bytelen > charlen) { int chinesenum = bytelen - charlen; System.out.println("str 包 含 汉 字, 汉 字 共 " + chinesenum + " 个 "); else { System.out.println("str 没 有 包 含 汉 字 "); 运 行 结 果 是 :str 包 含 汉 字, 汉 字 共 6 个 public void getchars(int srcbegin,intsrcend, char[] dst,int dstbegin) 拷 贝 字 符 串 的 部 分 字 符 序 列 到 指 定 的 字 符 数 组 的 指 定 位 置 ; 要 复 制 的 第 一 个 字 符 位 于 索 引 srcbegin 处 ; 要 复 制 的 最 后 一 个 字 符 位 于 索 引 srcend-1 处 ( 因 此 要 复 制 的 字 符 总 数 是 srcend-srcbegin) 要 复 制 到 dst 子 数 组 的 字 符 从 索 引 dstbegin 处 开 始, 并 结 束 于 索 引 char[] arr={'1','2','3','4','5','6'; String s= "collection"; s.getchars(4, 7, arr, 2); for(char c:arr){ System.out.print(c+","); 执 行 结 果 :1,2,e,c,t,6, public char[] tochararray() 将 此 字 符 串 转 换 为 一 个 新 的 字 符 数 组 String s="java 快 车 "; // 将 字 符 串 转 换 成 字 符 数 组 char[] b=s.tochararray(); System.out.println(Arrays.toString(b));// 输 出 [j, a, v, a, 快, 车 ] // 将 字 符 数 组 转 换 成 字 符 串 String s2=new String(b); System.out.println(s2);// 输 出 java 快 车 第 148 页

public String[] split(string regex) 根 据 给 定 正 则 表 达 式 的 匹 配 拆 分 此 字 符 串, 得 到 拆 分 好 的 字 符 串 数 组, 示 例 如 下 : public class Test { public static void main(string[] args) { String str = " 这 里, 是 Java, 快 车 "; String temps[] = str.split(",");// 按 照 "," 对 字 符 串 进 行 拆 分 for (int i = 0; i < temps.length; i++) { System.out.println("tempS[" + i + "]===" + temps[i]); 运 行 结 果 : temps[0]=== 这 里 temps[1]=== 是 Java temps[2]=== 快 车 注 意 : 因 为. 和 都 是 转 义 字 符, 必 须 得 加 \\ (1) 如 果 用. 作 为 分 隔 的 话, 必 须 是 如 下 写 法 :String.split("\\."), 这 样 才 能 正 确 的 分 隔 开, 不 能 用 String.split("."); public class Test { public static void main(string[] args) { String str = " 这 里. 是 Java. 快 车 "; String temps[] = str.split("\\.");// 按 照 "." 对 字 符 串 进 行 拆 分 for (int i = 0; i < temps.length; i++) { System.out.println("tempS[" + i + "]===" + temps[i]); (2) 如 果 用 作 为 分 隔 的 话, 必 须 是 如 下 写 法 :String.split("\\ "), 这 样 才 能 正 确 的 分 隔 开, 不 能 用 String.split(" "); public class Test { public static void main(string[] args) { String str = " 这 里 是 Java 快 车 "; String temps[] = str.split("\\ ");// 按 照 " " 对 字 符 串 进 行 拆 分 for (int i = 0; i < temps.length; i++) { System.out.println("tempS[" + i + "]===" + temps[i]); 6.2.2.7 展 示 字 符 串 public String concat(string str) 拼 接 两 个 字 符 串, 并 返 回 一 个 新 字 符 串 源 字 符 串 不 会 被 修 改 s1.concat( s2 ) 返 回 字 符 串 s1 和 s2 拼 接 的 结 果 第 149 页

String s1 = "javakc"; String s2 = "37"; s1 = s1.concat(s2); // 等 同 于 s1 = s1 + s2; public static String valueof( 参 数 列 表 ) 将 参 数 的 值 转 化 成 相 应 的 字 符 串 // 将 数 字 转 换 成 字 符 串 String s=string.valueof(37); // 也 可 以 这 样 转 成 字 符 串 String s2=37+""; public static String valueof(char[] data) 返 回 new String(data); char[] a={'j','a','v','a','k','c','3','7'; String s=string.valueof(a); System.out.println(s);// 输 出 javakc37 public static String valueof(char[] data, int offset,int count) 返 回 new String(data,offset,count); char[] a={'j','a','v','a','k','c','3','7'; String s=string.valueof(a,4,4); System.out.println(s);// 输 出 kc37 public String tostring( ) 由 于 源 对 象 就 是 字 符 串 了, 所 以 返 回 字 符 串 本 身 其 它 引 用 类 型 也 可 以 通 过 重 写 方 法 tostring, 生 成 相 应 的 字 符 串 ( 详 见 Object 的 tostring 方 法 ) 6.3 正 则 表 达 式 和 相 关 的 String 方 法 完 整 的 正 则 表 达 式 语 法 是 比 较 复 杂 的, 这 里 只 是 简 单 地 入 个 门, 更 多 的 正 则 表 达 式 请 参 考 相 应 的 书 籍 或 者 文 章 不 过 没 有 什 么 大 的 必 要, 常 见 的 正 则 表 达 式 基 本 都 是 写 好 了 的, 拿 过 来 用 就 可 以 了 第 150 页

6.3.1 什 么 是 正 则 表 达 式 在 编 写 处 理 字 符 串 的 程 序 时, 经 常 会 有 查 找 符 合 某 些 复 杂 规 则 的 字 符 串 的 需 要, 正 则 表 达 式 就 是 用 于 描 述 这 些 规 则 的 工 具 换 句 话 说, 正 则 表 达 式 就 是 记 录 文 本 规 则 的 代 码 回 忆 一 下 在 Windows 下 进 行 文 件 查 找, 查 找 的 通 配 符 也 就 是 * 和? 如 果 你 想 查 找 某 个 目 录 下 的 所 有 的 Word 文 档 的 话, 你 会 搜 索 *.doc 在 这 里,* 会 被 解 释 成 任 意 的 字 符 串 和 通 配 符 类 似, 正 则 表 达 式 也 是 用 来 进 行 文 本 匹 配 的 工 具, 只 不 过 比 起 通 配 符, 它 能 更 精 确 地 描 述 你 的 需 求 当 然, 代 价 就 是 更 复 杂 比 如 你 可 以 编 写 一 个 正 则 表 达 式, 用 来 查 找 所 有 以 0 开 头, 后 面 跟 着 2-3 个 数 字, 然 后 是 一 个 连 字 号 -, 最 后 是 7 或 8 位 数 字 的 字 符 串 ( 像 010-62972039 或 0311-8115213) 简 言 之 正 则 表 达 式 是 用 于 进 行 文 本 匹 配 的 工 具, 也 是 一 个 匹 配 的 表 达 式 6.3.2 正 则 表 达 式 基 础 入 门 学 习 正 则 表 达 式 的 最 好 方 法 是 从 例 子 开 始, 理 解 例 子 之 后 再 自 己 对 例 子 进 行 修 改, 实 验 下 面 给 出 了 不 少 简 单 的 例 子, 并 对 它 们 作 了 详 细 的 说 明 假 设 你 在 一 篇 英 文 小 说 里 查 找 hi, 你 可 以 使 用 正 则 表 达 式 hi 这 是 最 简 单 的 正 则 表 达 式 了, 它 可 以 精 确 匹 配 这 样 的 字 符 串 : 由 两 个 字 符 组 成, 前 一 个 字 符 是 h, 后 一 个 是 i 通 常, 处 理 正 则 表 达 式 的 工 具 会 提 供 一 个 忽 略 大 小 写 的 选 项, 如 果 选 中 了 这 个 选 项, 它 可 以 匹 配 hi,hi,hi,hi 这 四 种 情 况 中 的 任 意 一 种 不 幸 的 是, 很 多 单 词 里 包 含 hi 这 两 个 连 续 的 字 符, 比 如 him,history,high 等 等 用 hi 来 查 找 的 话, 这 里 边 的 hi 也 会 被 找 出 来 如 果 要 精 确 地 查 找 hi 这 个 单 词 的 话, 我 们 应 该 使 用 \bhi\b \b 是 正 则 表 达 式 规 定 的 一 个 特 殊 代 码 ( 某 些 人 叫 它 元 字 符,meta character), 代 表 着 单 词 的 开 头 或 结 尾, 也 就 是 单 词 的 分 界 处 虽 然 通 常 英 文 的 单 词 是 由 空 格 或 标 点 符 号 或 换 行 来 分 隔 的, 但 是 \b 并 不 匹 配 这 些 单 词 分 隔 符 中 的 任 何 一 个, 它 只 匹 配 一 个 位 置 假 如 你 要 找 的 是 hi 后 面 不 远 处 跟 着 一 个 Lucy, 你 应 该 用 \bhi\b.*\blucy\b. 是 另 一 个 元 字 符, 匹 配 除 了 换 行 符 以 外 的 任 意 字 符 * 同 样 是 元 字 符, 不 过 它 代 表 的 不 是 字 符, 也 不 是 位 置, 而 是 数 量 它 指 定 * 前 边 的 内 容 可 以 连 续 重 复 出 现 任 意 次 以 使 整 个 表 达 式 得 到 匹 配 因 此,.* 连 在 一 起 就 意 味 着 任 意 数 量 的 不 包 含 换 行 符 现 在 \bhi\b.*\blucy\b 的 意 思 就 很 明 显 了 : 先 是 一 个 单 词 hi, 然 后 是 任 意 个 任 意 字 符 ( 但 不 能 是 换 行 符 ), 最 后 是 Lucy 这 个 单 词 例 子 : 如 果 同 时 使 用 其 它 的 一 些 元 字 符, 我 们 就 能 构 造 出 功 能 更 强 大 的 正 则 表 达 式 比 如 下 面 这 个 0\d\d-\d\d\d\d\d\d\d\d 匹 配 这 样 的 字 符 串 : 以 0 开 头, 然 后 是 两 个 数 字, 然 后 是 一 个 连 字 号 -, 最 后 是 8 个 数 字 ( 也 就 是 中 国 的 电 话 号 码 当 然, 这 个 例 子 只 能 匹 配 区 号 为 3 位 的 情 形 ) 第 151 页

这 里 的 \d 是 一 个 新 的 元 字 符, 匹 配 任 意 的 数 字 (0, 或 1, 或 2, 或 ) - 不 是 元 字 符, 只 匹 配 它 本 身 连 字 号 为 了 避 免 那 么 多 烦 人 的 重 复, 我 们 也 可 以 这 样 写 这 个 表 达 式 :0\d{2-\d{8 这 里 \d 后 面 的 {2 和 {8 的 意 思 是 前 面 \d 必 须 连 续 重 复 匹 配 2 次 和 8 次 6.3.3 在 Java 中 运 行 正 则 表 达 式 在 Java 中 的 String 类 中 有 好 几 个 方 法 都 跟 正 则 表 达 式 有 关, 最 典 型 的 就 是 public boolean matches(string regex) 判 断 此 字 符 是 否 匹 配 给 定 的 正 则 表 达 式 使 用 这 个 方 法 来 测 试 和 运 行 上 面 学 到 的 正 则 表 达 式, 示 例 如 下 : public class Test { public static void main(string[] args) { String str = "010-62972039"; System.out.println("str 是 一 个 正 确 的 电 话 号 码? 答 案 是 :" + str.matches("0\\d{2-\\d{8")); 运 行 结 果 :str 是 一 个 正 确 的 电 话 号 码? 答 案 是 :true 注 意 : 由 于 在 Java 里 面 \ 需 要 转 义, 应 该 变 成 \\ 在 Java 中, 有 专 门 进 行 正 则 表 达 式 的 类, 在 java.util.regex 包 里 面 6.3.3.1 java.util.regex.pattern 类 Pattern 类 是 正 则 表 达 式 的 编 译 表 示 形 式 指 定 为 字 符 串 的 正 则 表 达 式 必 须 首 先 被 编 译 为 此 类 的 实 例 然 后, 可 将 得 到 的 模 式 用 于 创 建 Matcher 对 象, 依 照 正 则 表 达 式, 该 对 象 可 以 与 任 意 字 符 序 列 匹 配 执 行 匹 配 所 涉 及 的 所 有 状 态 都 驻 留 在 匹 配 器 中, 所 以 多 个 匹 配 器 可 以 共 享 同 一 模 式 常 见 方 法 如 下 : static Pattern compile(string expression) static Pattern compile(string expression, int flags): 编 译 正 则 表 达 式 字 符 串 到 pattern 对 象 用 以 匹 配 的 快 速 处 理 参 数 : expression 正 则 表 达 式 flags 下 列 标 志 中 的 一 个 或 多 个 : CASE_INSENSITIVE,UNICODE_CASE,MULTILINE,UNIX_LINES,DOTALL,and 第 152 页

CANON_EQ Matcher matcher(charsequence input) 返 回 一 个 matcher 对 象, 它 可 以 用 来 在 一 个 输 入 中 定 位 模 式 匹 配 String[] split(charsequence input) String[] split(charsequence input, int limit) 将 输 入 字 符 串 分 离 成 记 号, 并 由 pattern 来 指 定 分 隔 符 的 形 式 返 回 记 号 数 组 分 隔 符 并 不 是 记 号 的 一 部 分 参 数 : input 分 离 成 记 号 的 字 符 串 limit 生 成 的 最 大 字 符 串 数 6.3.3.2 java.util.regex.matcher 类 Mathcer 类 通 过 解 释 Pattern 对 字 符 序 列 执 行 匹 配 操 作 的 引 擎 常 见 方 法 如 下 : boolean matches(): 返 回 输 入 是 否 与 模 式 匹 配 boolean lookingat(): 如 果 输 入 的 起 始 匹 配 模 式 则 返 回 True boolean find() boolean find(int start): 尝 试 查 找 下 一 个 匹 配, 并 在 找 到 匹 配 时 返 回 True 参 数 : start 开 始 搜 索 的 索 引 int start(): 返 回 当 前 匹 配 的 起 始 位 置 位 置 int end(): 返 回 当 前 匹 配 的 结 尾 后 位 置 String group(): 返 回 当 前 匹 配 int groupcount(): 返 回 输 入 模 式 中 的 分 组 数 int start(int groupindex) int end(int groupindex) 返 回 一 个 给 定 分 组 当 前 匹 配 中 的 起 始 位 置 和 结 尾 后 位 置 参 数 : groupindex 分 组 索 引 ( 从 1 开 始 ),0 表 示 整 个 匹 配 第 153 页

String group(int groupindex): 返 回 匹 配 一 个 给 定 分 组 的 字 符 串 参 数 : groupindex 分 组 索 引 ( 从 1 开 始 ),0 表 示 整 个 匹 配 String replaceall(string replacement) String replacefirst(string replacement) 返 回 从 matcher 输 入 得 到 的 字 符 串, 但 已 经 用 替 换 表 达 式 替 换 所 有 或 第 一 个 匹 配 参 数 : replacement 替 换 字 符 串 Matcher reset() Matcher reset(charsequence input) 复 位 mather 状 态 6.3.3.3 Java 中 操 作 正 则 表 达 式 示 例 public class Test { public static void main(string[] args) { String str = "010-62972039"; Pattern p = Pattern.compile("0\\d{2-\\d{8"); Matcher m = p.matcher(str); boolean flag = m.matches(); System.out.println("str 是 一 个 正 确 的 电 话 号 码? 答 案 是 :" + flag); 运 行 结 果 :str 是 一 个 正 确 的 电 话 号 码? 答 案 是 :true 6.3.4 元 字 符 现 在 你 已 经 知 道 几 个 很 有 用 的 元 字 符 了, 如 \b. *, 还 有 \d. 当 然 还 有 更 多 的 元 字 符 可 用, 比 如 \s 匹 配 任 意 的 空 白 符, 包 括 空 格, 制 表 符 (Tab), 换 行 符, 中 文 全 角 空 格 等 \w 匹 配 字 母 或 数 字 或 下 划 线 等 常 用 的 元 字 符 代 码 说 明. 匹 配 除 换 行 符 以 外 的 任 意 字 符 \w 匹 配 字 符 或 数 字 或 下 划 线 \s 匹 配 任 意 的 空 白 符 \d 匹 配 数 字 \b 匹 配 字 符 串 的 开 始 或 结 束 ^ 匹 配 字 符 串 的 开 始 $ 匹 配 字 符 串 的 结 束 第 154 页

下 面 来 试 试 更 多 的 例 子 : 例 1:\ba\w*\b 匹 配 以 字 母 a 开 头 的 单 词 先 是 某 个 单 词 开 始 处 (\b), 然 后 是 字 母 a, 然 后 是 任 意 数 量 的 字 母 或 数 字 (\w*), 最 后 是 单 词 结 束 处 (\b)( 好 吧, 现 在 我 们 说 说 正 则 表 达 式 里 的 单 词 是 什 么 意 思 吧 : 就 是 几 个 连 续 的 \w 不 错, 这 与 学 习 英 文 时 要 背 的 成 千 上 万 个 同 名 的 东 西 的 确 关 系 不 大 ) 例 2:\d+ 匹 配 1 个 或 更 多 连 续 的 数 字 这 里 的 + 是 和 * 类 似 的 元 字 符, 不 同 的 是 * 匹 配 重 复 任 意 次 ( 可 能 是 0 次 ), 而 + 则 匹 配 重 复 1 次 或 更 多 次 例 3:\b\w{6\b 匹 配 刚 好 6 个 字 母 / 数 字 的 单 词 例 4:^\d{5,12$ 匹 配 必 须 为 5 位 到 12 位 数 字 的 字 符 串 元 字 符 ^( 和 数 字 6 在 同 一 个 键 位 上 的 符 号 ) 以 及 $ 和 \b 有 点 类 似, 都 匹 配 一 个 位 置 ^ 匹 配 你 要 用 来 查 找 的 字 符 串 的 开 头,$ 匹 配 结 尾 这 两 个 代 码 在 验 证 输 入 的 内 容 时 非 常 有 用, 比 如 一 个 网 站 如 果 要 求 你 填 写 的 QQ 号 时, 可 以 使 用 这 里 的 {5,12 和 前 面 介 绍 过 的 {2 是 类 似 的, 只 不 过 {2 匹 配 只 能 不 多 不 少 重 复 2 次, {5,12 则 是 重 复 的 次 数 不 能 少 于 5 次, 不 能 多 于 12 次, 否 则 都 不 匹 配 因 为 使 用 了 ^ 和 $, 所 以 输 入 的 整 个 字 符 串 都 要 用 来 和 \d{5,12 来 匹 配, 也 就 是 说 整 个 输 入 必 须 是 5 到 12 个 数 字, 因 此 如 果 输 入 的 QQ 号 能 匹 配 这 个 正 则 表 达 式 的 话, 那 就 符 合 要 求 了 6.3.5 重 复 已 经 看 过 了 前 面 的 *,+,{2,{5,12 这 几 个 匹 配 重 复 的 方 式 了 下 面 是 正 则 表 达 式 中 所 有 的 限 定 符 ( 指 定 数 量 的 代 码, 例 如 *,{5,12 等 ): 常 用 的 限 定 符 代 码 / 语 法 说 明 * 重 复 零 次 或 多 次 + 重 复 一 次 或 多 次? 重 复 零 次 或 一 次 {n 重 复 n 次 {n, 重 复 n 次 或 更 多 次 {n,m 重 复 n 次 到 m 次 下 面 是 一 些 使 用 重 复 的 例 子 : Windows\d+ 匹 配 Windows 后 面 跟 1 个 或 更 多 数 字 第 155 页

13\d{9 匹 配 13 后 面 跟 9 个 数 字 ( 中 国 的 手 机 号 ) 6.3.6 字 符 类 要 想 查 找 数 字, 字 母 或 数 字, 空 白 是 很 简 单 的, 因 为 已 经 有 了 对 应 这 些 字 符 集 合 的 元 字 符, 但 是 如 果 你 想 匹 配 没 有 预 定 义 元 字 符 的 字 符 集 合 ( 比 如 元 音 字 母 a,e,i,o,u), 应 该 怎 么 办? 很 简 单, 你 只 需 要 在 中 括 号 里 列 出 它 们 就 行 了, 像 [aeiou] 就 匹 配 任 何 一 个 英 文 元 音 字 母, [.?!] 匹 配 标 点 符 号 (. 或? 或!)( 英 文 语 句 通 常 只 以 这 三 个 标 点 结 束 ) 我 们 也 可 以 轻 松 地 指 定 一 个 字 符 范 围, 像 [0-9] 代 表 的 含 意 与 \d 就 是 完 全 一 致 的 : 一 位 数 字, 同 理 [a-z0-9a-z_] 也 完 全 等 同 于 \w( 如 果 只 考 虑 英 文 的 话 ) 6.3.7 常 见 正 则 表 达 式 (1) 检 测 是 否 Email 地 址 ^([\\w-\\.]+)@((\\[[0-9]{1,3\\.[0-9]{1,3\\.[0-9]{1,3\\.) (([\\w- ]+\\.)+))([a-za-z]{2,4 [0-9]{1,3)(\\]?)$ (2) 判 断 输 入 的 字 符 串 只 包 含 汉 字 ^[\u4e00-\u9fa5]+$ (3) 匹 配 3 位 或 4 位 区 号 的 电 话 号 码, 其 中 区 号 可 以 用 小 括 号 括 起 来, 也 可 以 不 用, 区 号 与 本 地 号 间 可 以 用 连 字 号 或 空 格 间 隔, 也 可 以 没 有 间 隔 ^\\(0\\d{2\\)[-]?\\d{8$ ^0\\d{2[-]?\\d{8$ ^\\(0\\d{3\\)[-]?\\d {7$ ^0\\d{3[-]?\\d{7$ (4) 判 断 输 入 的 字 符 串 是 否 是 一 个 合 法 的 手 机 号, 这 个 不 完 全, 只 是 13 开 头 的 ^1[3,5,8]\\d{9$ (5) 判 断 输 入 的 字 符 串 只 包 含 数 字, 可 以 匹 配 整 数 和 浮 点 数 ^-?\\d+$ ^(-?\\d+)(\\.\\d+)?$ (6) 匹 配 非 负 整 数, 最 多 9 位 数 ^\\d [1-9]+\\d{2,9$ (7) 判 断 输 入 的 字 符 串 只 包 含 英 文 字 母 ^[A-Za-z]+$ (8) 判 断 输 入 的 字 符 串 是 否 只 包 含 数 字 和 英 文 字 母 ^[A-Za-z0-9]+$ 好 了, 学 到 这 里 对 基 本 的 正 则 表 达 式 就 有 了 基 本 的 认 识, 下 面 来 看 看 String 里 面 跟 正 则 表 达 式 有 关 的 几 个 方 法 的 使 用 第 156 页

6.4 StringBuffer 类 和 StringBuilder 类 前 面 学 到 过 String 类 有 一 个 重 要 的 特 点, 那 就 是 String 的 值 是 不 可 变 的, 这 就 导 致 每 次 对 String 的 操 作 都 会 生 成 新 的 String 对 象, 不 仅 效 率 低 下, 而 且 大 量 浪 费 有 限 的 内 存 空 间 那 么 对 于 经 常 要 改 变 值 的 字 符 串 应 该 怎 样 操 作 呢? 答 案 就 是 使 用 StringBuffer 和 StringBuilder 类, 这 两 个 类 功 能 基 本 相 似, 区 别 主 要 在 于 StringBuffer 类 的 方 法 是 多 线 程 安 全 的 ( 多 线 程 的 课 程 在 后 面 会 学 习 到 ), 而 StringBuilder 不 是 线 程 安 全 的, 相 比 而 言 StringBuilder 类 会 略 微 快 一 点 6.4.1 StringBuffer 类 String 字 符 串 (String) 对 象 一 旦 创 建, 其 内 容 不 能 再 被 修 改 (read-only) StringBuffer StringBuffer 对 象 的 内 容 是 可 以 被 修 改 的 除 了 字 符 的 长 度 之 外, 还 有 容 量 的 概 念 通 过 动 态 改 变 容 量 的 大 小, 加 速 字 符 管 理 6.4.1.1 StringBuffer 的 构 造 方 法 StringBuffer buf1 = new StringBuffer(); 创 建 空 的 StringBuffer 对 象, 初 始 容 量 为 16 字 符 StringBuffer buf2 = new StringBuffer( 容 量 ); 创 建 空 的 StringBuffer 对 象, 指 定 容 量 大 小 StringBuffer buf3 = new StringBuffer( mystring ); 创 建 含 有 相 应 字 符 序 列 的 StringBuffer 对 象, 容 量 为 mystring.length() +16 6.4.1.2 StringBuffer 的 常 用 方 法 public int length() 返 回 StringBuffer 的 长 度 public int capacity() 返 回 StringBuffer 的 容 量 public void setlength(int newlength) 第 157 页

增 加 或 减 小 StringBuffer 的 长 度 public char charat(int index) 返 回 StringBuffer 对 象 中 指 定 位 置 的 字 符 public void setcharat(int index, char ch) 设 置 StringBuffer 对 象 中 指 定 位 置 的 字 符 public void getchars(int srcbegin, int srcend,char[] dst, int dstbegin) 将 StringBuffer 对 象 中 指 定 的 字 符 子 序 列, 拷 贝 到 指 定 的 字 符 数 组 (dst) public void reverse() 将 StringBuffer 对 象 中 的 字 符 序 列 按 逆 序 方 式 排 列, 可 用 作 字 符 串 倒 序 public StringBuffer append( ) 允 许 数 值 类 型 的 值 添 加 到 StringBuffer 对 象 中 public StringBuffer insert( ) 允 许 将 各 种 数 据 插 到 StringBuffer 对 象 的 指 定 位 置 public StringBuffer delete(int start, int end) public StringBuffer deletecharat(int index) 允 许 删 除 StringBuffer 对 象 中 的 指 定 字 符 其 中 最 常 用 的 恐 怕 就 要 算 append 方 法 和 tostring 方 法 了, 如 下 示 例 : public class Test { public static void main(string[] args) { StringBuffer buffer = new StringBuffer(); buffer.append(" 这 里 "); buffer.append(" 是 "); buffer.append("java"); buffer.append(" 快 车 "); System.out.println("buffer==" + buffer.tostring()); 运 行 结 果 :buffer== 这 里 是 Java 快 车 6.4.2 StringBuilder 类 StringBuilder 类 是 一 个 可 变 的 字 符 序 列 此 类 提 供 一 个 与 StringBuffer 兼 容 的 API, 但 不 保 证 同 步 该 类 被 设 计 用 作 StringBuffer 的 一 个 简 易 替 换, 用 在 字 符 串 缓 冲 区 被 单 个 线 程 使 用 的 时 候 ( 这 种 情 况 很 普 遍 ) 如 果 可 能, 建 议 优 先 采 用 该 类, 因 为 在 大 多 数 实 现 中, 它 比 StringBuffer 要 快 它 的 功 能 基 本 等 同 于 StringBuffer 类, 就 不 再 赘 述 了 public class Test { 第 158 页

public static void main(string[] args) { StringBuilder builder = new StringBuilder(); builder.append(" 这 里 "); builder.append(" 是 "); builder.append("java"); builder.append(" 快 车 "); System.out.println("buffer==" + builder.tostring()); 运 行 结 果 :builder== 这 里 是 Java 快 车 6.5 Math 类 Java 中 的 数 学 (Math) 类 是 final 类, 不 可 继 承 其 中 包 含 一 组 静 态 方 法 和 两 个 常 数 6.5.1 常 数 PI :double, 圆 周 率 E :double, 自 然 对 数 6.5.2 方 法 6.5.2.1 截 取 注 意 方 法 的 返 回 类 型 public static double ceil(double d) 返 回 不 小 于 d 的 最 小 整 数 double d=math.ceil(8.7); System.out.println(d);// 输 出 9.0 double d2=math.ceil(-8.7); System.out.println(d2); // 输 出 -8.0 public static double floor(double d) 返 回 不 大 于 d 的 最 大 整 数 double d=math.floor(8.7); System.out.println(d);// 输 出 8.0 double d2=math.floor(-8.7); System.out.println(d2); // 输 出 -9.0 第 159 页

public static int round(float f) 返 回 四 舍 五 入 后 的 整 数 int n=math.round(8.7f); System.out.println(n);// 输 出 9 int m=math.round(-8.7f); System.out.println(m);// 输 出 -9 public static long round(double d) 返 回 四 舍 五 入 后 的 整 数 long lon=math.round(8.7); System.out.println(lon);// 输 出 9 long lon2=math.round(-8.7); System.out.println(lon2);// 输 出 -9 6.5.2.2 变 换 public static double abs(double d) 返 回 绝 对 值 int i=math.abs(10); System.out.println(i);// 输 出 10 int j=math.abs(-10); System.out.println(j);// 输 出 10 public static double min(double d1, double d2) 返 回 两 个 值 中 较 小 的 值 int i=math.min(10,20); System.out.println(i);// 输 出 10 double d=math.min(3.5,6.7); System.out.println(d);// 输 出 3.5 public static double max(double d1, double d2) 返 回 两 个 值 中 较 大 的 值 int i=math.max(10,20); System.out.println(i);// 输 出 20 double d=math.max(3.5,6.7); System.out.println(d);// 输 6.7 第 160 页

6.5.2.3 对 数 public static double log(double d) 自 然 对 数 public static double exp(double d) E 的 指 数 6.5.2.4 其 它 public static double sqrt(double d) 返 回 平 方 根 double d=math.sqrt(4); System.out.println(d);// 输 出 2.0 double d2=math.sqrt(5); System.out.println(d2);// 输 出 2.23606797749979 public static double random() 返 回 随 机 数 double d=math.random(); System.out.println(d);// 输 出 0.3079168104754698 double d2=math.random(); System.out.println(d2);// 输 出 0.5299188765985596 还 有 三 角 函 数 的 运 算 等, 请 参 考 JDK 文 档 示 例 如 下 : 问 题 : 请 问 有 101 条 记 录, 按 照 每 组 10 条 记 录 进 行 分 组, 应 该 分 多 少 组? public class Test { public static void main(string[] args) { int records = 101;// 共 有 101 条 记 录 final int GROUP_NUM = 10;// 每 组 10 条 int groups = (int) Math.ceil(1.0 * records / GROUP_NUM); // 注 意 这 里 的 1.0, 目 的 是 要 把 类 型 变 成 double 型 的, 而 不 是 int, 结 果 还 是 int, 就 错 了 System.out.println(" 应 该 分 的 组 数 为 =" + groups); 运 行 结 果 : 应 该 分 的 组 数 为 11 第 161 页

6.6 日 期 操 作 的 类 6.6.1 Date 类 java.util 包 里 面 的 Date 类, 是 Java 里 面 进 行 日 期 操 作 常 用 类 Date 类 用 来 表 示 特 定 的 瞬 间, 精 确 到 毫 秒 6.6.1.1 初 始 化 Date Date 的 构 造 方 法 : public Date( ) 分 配 Date 对 象 并 初 始 化 此 对 象, 以 表 示 分 配 它 的 时 候 的 当 前 时 间 ( 精 确 到 毫 秒 ) 使 用 Date 类 得 到 当 前 的 时 间 public Date(long date) 分 配 Date 对 象 并 初 始 化 此 对 象, 以 表 示 自 从 标 准 基 准 时 间 ( 称 为 历 元 (epoch), 即 1970 年 1 月 1 日 00:00:00 格 林 威 治 时 间 ) 以 来 的 指 定 毫 秒 数 6.6.1.2 常 用 方 法 public boolean after(date when) 测 试 此 日 期 是 否 在 指 定 日 期 之 后 public boolean before(date when) 测 试 此 日 期 是 否 在 指 定 日 期 之 前 方 法 :gettime() 返 回 自 1970 年 1 月 1 日 00:00:00 GMT 以 来 此 Date 对 象 表 示 的 毫 秒 数 6.6.1.3 示 例 简 单 的 性 能 测 试 监 控 一 段 代 码 运 行 所 需 要 的 时 间 public class Test { public static void main(string args[]) { long d1 = new Date().getTime();// 得 到 此 时 的 时 间 int sum = 0; for (int i = 1; i <= 1000000; i++) {// 一 百 万 次 sum += i; System.out.println(" 从 1 加 到 1000000 的 和 =" + sum); long d2 = new Date().getTime();// 得 到 此 时 的 时 间 System.out.println(" 从 1 加 到 1000000 所 耗 费 的 时 间 是 =" + (d2 - d1) + " 毫 秒 "); 第 162 页

运 行 结 果 : 从 1 加 到 1000000 的 和 =1784293664 从 1 加 到 1000000 所 耗 费 的 时 间 是 =20 毫 秒 6.6.2 DateFormat 类 和 SimpleDateFormat 类 Date 对 象 表 示 时 间 的 默 认 顺 序 是 星 期 月 日 小 时 秒 年, 例 如 Wed May 12 14:33:11 CST 2009 我 们 可 能 希 望 按 照 某 种 习 惯 来 输 出 时 间, 比 如 时 间 的 顺 序 : 年 月 星 期 日 可 以 使 用 java.text 包 中 的 DateFormat 类, 是 日 期 / 时 间 格 式 化 子 类 的 抽 象 类, 它 以 与 语 言 无 关 的 方 式 格 式 化 并 解 析 日 期 或 时 间 日 期 / 时 间 格 式 化 子 类 ( 如 SimpleDateFormat) 允 许 进 行 格 式 化 ( 也 就 是 日 期 转 换 成 文 本 ) 解 析 ( 文 本 转 换 成 日 期 ) 和 标 准 化 由 于 DateFormat 是 个 抽 象 类,SimpleDateFormat 类 是 它 的 子 类, 所 以 下 面 就 主 要 按 照 SimpleDateFormat 类 来 讲 解 6.6.2.1 如 何 初 始 化 这 里 只 讲 述 最 常 用 到 的 构 造 方 法, 更 多 的 请 参 看 JDK 文 档 构 造 方 法 :SimpleDateFormat(String pattern) 用 给 定 的 模 式 和 默 认 语 言 环 境 的 日 期 格 式 符 号 构 造 SimpleDateFormat SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 6.6.2.2 日 期 和 时 间 模 式 日 期 和 时 间 格 式 由 日 期 和 时 间 模 式 字 符 串 指 定 在 日 期 和 时 间 模 式 字 符 串 中, 未 加 引 号 的 字 母 'A' 到 'Z' 和 'a' 到 'z' 被 解 释 为 模 式 字 母, 用 来 表 示 日 期 或 时 间 字 符 串 元 素 文 本 可 以 使 用 单 引 号 (') 引 起 来, 以 免 进 行 解 释 "''" 表 示 单 引 号 所 有 其 他 字 符 均 不 解 释 ; 只 是 在 格 式 化 时 将 它 们 简 单 复 制 到 输 出 字 符 串, 或 者 在 解 析 时 与 输 入 字 符 串 进 行 匹 配 定 义 了 以 下 模 式 字 母 ( 所 有 其 他 字 符 'A' 到 'Z' 和 'a' 到 'z' 都 被 保 留 ): 字 母 日 期 或 时 间 元 素 表 示 示 例 G Era 标 志 符 Text AD y 年 Year 1996; 96 M 年 中 的 月 份 Month July; Jul; 07 w 年 中 的 周 数 Number 27 W 月 份 中 的 周 数 Number 2 D 年 中 的 天 数 Number 189 d 月 份 中 的 天 数 Number 10 F 月 份 中 的 星 期 Number 2 第 163 页

E 星 期 中 的 天 数 Text Tuesday; Tue a Am/pm 标 记 Text PM H 一 天 中 的 小 时 数 (0-23) Number 0 k 一 天 中 的 小 时 数 (1-24) Number 24 K am/pm 中 的 小 时 数 (0-11) Number 0 h am/pm 中 的 小 时 数 (1-12) Number 12 m 小 时 中 的 分 钟 数 Number 30 s 分 钟 中 的 秒 数 Number 55 S 毫 秒 数 Number 978 z 时 区 General time zone PST; GMT-08:00 Z 时 区 RFC 822 time zone -0800 6.6.2.3 常 用 方 法 public Date parse(string source) 从 给 定 字 符 串 的 开 始 解 析 文 本, 以 生 成 一 个 日 期 public String format(date date) 将 一 个 Date 格 式 化 为 日 期 / 时 间 字 符 串 这 里 只 讲 述 最 常 用 的 方 法, 更 多 的 方 法 请 参 看 JDK 文 档 6.6.2.4 示 例 import java.util.*; import java.text.*; public class Test { public static void main(string args[]) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); Date d = new Date(); // 把 当 前 时 间 转 换 成 为 我 们 熟 悉 的 时 间 表 达 格 式 String str = df.format(d); System.out.println(" 当 前 时 间 是 :" + str); // 然 后 再 把 字 符 串 格 式 的 日 期 转 换 成 为 一 个 Date 类 try { Date d2 = df.parse("2012-07-27 08:08:08 888"); System.out.println(" 伦 敦 奥 运 会 开 幕 时 间 是 :" + d2.gettime()); catch (ParseException e) { e.printstacktrace(); 运 行 结 果 : 当 前 时 间 是 :2009-05-17 18:52:13 437 伦 敦 奥 运 会 开 幕 时 间 是 :1343347688888 也 可 以 采 用 System 类 的 静 态 方 法 public long currenttimemillis() 获 取 系 统 当 前 第 164 页

时 间 的 毫 秒 数 6.6.2.5 说 明 虽 然 JDK 文 档 上 说 Date 的 毫 秒 值, 是 相 对 于 格 林 威 治 时 间 1970 年 1 月 1 号 的 0 点, 但 实 际 测 试, 这 个 Date 是 跟 时 区 相 关 的, 也 就 是 说 在 中 国 测 试 这 个 基 准 值 应 该 是 1970 年 1 月 1 日 的 8 点, 不 过 这 个 不 影 响 我 们 的 处 理, 因 为 只 要 是 同 一 个 基 准 时 间 就 可 以 了, 而 不 用 关 心 具 体 是 多 少, 见 下 面 的 示 例 : public class Test { public static void main(string args[]) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); Date d = new Date(0L);// 把 时 间 设 为 0, 表 示 到 基 准 时 间 // 然 后 转 换 成 为 字 符 串 看 看 是 什 么 时 候 String str = df.format(d); System.out.println(" 基 准 时 间 是 :" + str); 运 行 结 果 : 基 准 时 间 是 :1970-01-01 08:00:00 000 6.6.3 Calendar 类 java.util 包 中 的 Calendar 类 是 Java 里 面 另 外 一 个 常 用 的 日 期 处 理 的 类 Calendar 类 是 一 个 抽 象 类, 它 为 特 定 瞬 间 与 一 组 诸 如 YEAR MONTH DAY_OF_MONTH HOUR 等 日 历 字 段 之 间 的 转 换 提 供 了 一 些 方 法, 并 为 操 作 日 历 字 段 ( 例 如 获 得 下 星 期 的 日 期 ) 提 供 了 一 些 方 法 6.6.3.1 初 始 化 Calendar 类 是 通 过 一 个 静 态 方 法 getinstance() 来 获 取 Calendar 实 例 返 回 的 Calendar 基 于 当 前 时 间, 使 用 了 默 认 时 区 和 默 认 语 言 环 境 如 下 : Calendar c = Calendar.getInstance(); 6.6.3.2 使 用 Calendar 对 日 期 进 行 部 分 析 取 Calendar 类 一 个 重 要 的 功 能 就 是 能 够 从 日 期 里 面 按 照 要 求 析 取 出 数 据, 如 : 年 月 日 星 期 等 等 public int get(int field) 返 回 给 定 日 历 字 段 的 值, 例 如 年 份 月 份 小 时 星 期 等 信 息, 参 数 field 的 有 效 值 由 第 165 页

Calendar 得 静 态 常 量 指 定 示 例 如 下 : public class Test { public static void main(string args[]) { Calendar c = Calendar.getInstance(); int year = c.get(calendar.year); int month = c.get(calendar.month);// 注 意 :month 特 殊, 是 从 0 开 始 的, 也 就 是 0 表 示 1 月 int day = c.get(calendar.day_of_month); System.out.println(" 现 在 是 " + year + " 年 " + (month + 1) + " 月 " + day + " 日 "); 运 行 结 果 : 现 在 是 2009 年 5 月 17 日 6.6.3.3 使 用 Calendar 进 行 日 期 运 算 这 是 Calendar 另 外 一 个 常 用 的 功 能, 也 就 是 对 日 期 进 行 加 加 减 减 的 运 算 public void add(int field,int amount) 根 据 日 历 的 规 则, 为 给 定 的 日 历 字 段 添 加 或 减 去 指 定 的 时 间 量 示 例 如 下 : public class Test { public static void main(string args[]) { Calendar c = Calendar.getInstance(); c.add(calendar.date, 12);// 当 前 日 期 加 12 天, 如 果 是 -12 表 示 当 前 日 期 减 去 12 天 int year = c.get(calendar.year); // 注 意 :month 特 殊, 是 从 0 开 始 的, 也 就 是 0 表 示 1 月 int month = c.get(calendar.month); int day = c.get(calendar.day_of_month); System.out.println(" 在 当 前 日 期 加 12 天 是 " + year + " 年 " + (month + 1) + " 月 " + day+ " 日 "); 运 行 结 果 : 在 当 前 日 期 加 12 天 是 2009 年 5 月 29 日 第 166 页

6.6.3.4 为 Calendar 设 置 初 始 值 public void settime(date date) 使 用 给 定 的 Date 设 置 此 Calendar 的 当 前 时 间 public void settimeinmillis(long millis) 用 给 定 的 long 值 设 置 此 Calendar 的 当 前 时 间 值 public class Test { public static void main(string args[]) { Calendar c = Calendar.getInstance(); c.settimeinmillis(1234567890123l); int year = c.get(calendar.year); // 注 意 :month 特 殊, 是 从 0 开 始 的, 也 就 是 0 表 示 1 月 int month = c.get(calendar.month); int day = c.get(calendar.day_of_month); System.out.println(" 设 置 的 时 间 是 " + year + " 年 " + (month + 1) + " 月 " + day+ " 日 "); 运 行 结 果 : 设 置 的 时 间 是 2009 年 2 月 14 日 6.7 包 装 类 虽 然 Java 语 言 是 典 型 的 面 向 对 象 编 程 语 言, 但 其 中 的 8 种 基 本 数 据 类 型 并 不 支 持 面 向 对 象 的 编 程 机 制, 基 本 类 型 的 数 据 不 具 备 对 象 的 特 性 ---- 不 携 带 属 性 没 有 方 法 可 调 用 沿 用 它 们 只 是 为 了 迎 合 人 类 根 深 蒂 固 的 习 惯, 并 的 确 能 简 单 有 效 地 进 行 常 规 数 据 处 理 这 种 借 助 于 非 面 向 对 象 技 术 的 做 法 有 时 也 会 带 来 不 便, 比 如 引 用 类 型 数 据 均 继 承 了 Object 类 的 特 性, 要 转 换 为 String 类 型 ( 经 常 有 这 种 需 要 ) 时 只 要 简 单 调 用 Object 类 中 定 义 的 tostring() 即 可, 而 基 本 数 据 类 型 转 换 为 String 类 型 则 要 麻 烦 得 多 为 解 决 此 类 问 题, Java 语 言 引 入 了 封 装 类 的 概 念, 在 JDK 中 针 对 各 种 基 本 数 据 类 型 分 别 定 义 相 应 的 引 用 类 型, 并 称 之 为 包 装 类 (Wrapper Classes) 下 表 描 述 了 基 本 数 据 类 型 及 对 应 的 包 装 类 基 本 数 据 类 型 byte short int long char float double 对 应 的 包 装 类 Byte Short Integer Long Character Float Double 第 167 页

boolean Boolean 每 个 包 装 类 的 对 象 可 以 封 装 一 个 相 应 的 基 本 类 型 的 数 据, 并 提 供 了 其 它 一 些 有 用 的 功 能 包 装 类 对 象 一 经 创 建, 其 内 容 ( 所 封 装 的 基 本 类 型 数 据 值 ) 不 可 改 变 例, 包 装 类 用 法 程 序 :Wrapper.java public class Wrapper { public static void main(string args[]) { int i = 500; Integer t = new Integer(i); int j = t.intvalue(); // j = 500 String s = t.tostring(); // s = "500" System.out.println(t); Integer t1 = new Integer(500); System.out.println(t.equals(t1)); 例 : 程 序 运 行 结 果 为 : 500 true 包 装 类 一 个 常 用 的 功 能 就 是 把 字 符 串 类 型 的 数 据 造 型 成 为 对 应 的 基 本 数 据 类 型, 如 下 示 String str = "123"; int a = Integer.parseInt(str); 6.8 System 类 6.8.1 命 令 行 参 数 当 Java 程 序 启 动 时, 可 以 添 加 0 或 多 个 命 令 行 参 数 (Command-line Arguments) 不 管 使 用 双 引 号 与 否 都 作 为 字 符 串 自 动 保 存 到 main 函 数 的 参 数 中 参 数 之 间 用 空 格 分 隔 public class Test { public static void main(string args[]) { System.out.println(args.length); for (int i = 0; i < args.length; i++) { System.out.println(args[i]); 第 168 页

本 段 代 码 可 以 使 用 下 面 语 句 测 试 :java Test 这 里 是 Java 快 车 运 行 结 果 : 4 这 里 是 Java 快 车 6.8.2 控 制 台 输 入 输 出 许 多 应 用 程 序 要 与 用 户 进 行 文 本 I/O( 输 入 / 输 出 ) 交 互, 标 准 输 入 是 键 盘 ; 标 准 输 出 是 终 端 窗 口 Java SDK 支 持 控 制 台 I/O 使 用 三 个 java.lang.system 类 中 定 义 的 变 量 : System.out 是 一 个 PrintStream 对 象, 初 始 引 用 启 动 Java 的 终 端 窗 口 System.in 是 一 个 InputStream 对 象, 初 始 指 向 用 户 键 盘 System.err 是 一 个 PrintStream 对 象, 初 始 引 用 启 动 Java 的 终 端 窗 口 这 三 个 对 象 都 可 以 重 新 定 向 ( 如 文 件 ):System.setOut\setIn\setErr 往 标 准 输 出 写 东 西 使 用 PrintStream 对 象 的 println 或 print 方 法 print 方 法 输 出 参 数 ; 但 println 方 法 输 出 参 数 并 追 加 一 个 换 行 符 println 或 print 方 法 都 对 原 始 类 型 进 行 重 载, 同 时 还 重 载 了 char[] 和 Object, String 参 数 是 Object 时, 调 用 参 数 的 tostring 方 法 输 出 例 子 : public class Test { public static void main(string args[]) { char c[] = { 'a', 'b', 'c' ; System.out.println(c); 运 行 结 果 :abc 输 入 例 子 : public class Test { public static void main(string args[]) { String s = ""; InputStreamReader ir = new InputStreamReader(System.in); BufferedReader in = new BufferedReader(ir); System.out.println("Ctrl+z to exit"); 第 169 页

try { s = in.readline(); while (s!= null) { System.out.println("Read:" + s); s = in.readline(); in.close(); catch (IOException e) { e.printstacktrace(); 运 行 的 时 候 从 控 制 台 输 入 数 据, 然 后 回 车, 就 看 到 输 出 了 读 入 的 数 据 因 为 涉 及 到 后 面 要 学 习 的 I/O 的 知 识, 所 以 这 里 先 简 单 了 解 一 下 也 可 以 使 用 Scanner 类,Scanner 类 用 来 扫 描 控 制 台 的 输 入 数 据 控 制 台 会 一 直 等 待 输 入, 直 到 敲 回 车 键 结 束, 把 所 输 入 的 内 容 传 给 Scanner, 作 为 扫 描 对 象 如 果 要 获 取 输 入 的 内 容, 则 只 需 要 调 用 Scanner 的 nextline() 方 法 即 可, 或 者 next nextint nextdouble 方 法 等 import java.util.scanner; public class Test { public static void main(string[] args) { Scanner sc = new Scanner(System.in); while(true){ String s=sc.next(); System.out.println(s); 6.8.3 格 式 化 输 出 printf 从 JDK5.0 开 始,Java 里 面 提 供 了 C 风 格 的 格 式 化 输 出 方 法 printf, 比 如 输 出 一 个 加 法 算 式,JDK5.0 版 本 以 前 的 写 法 是 : public class Test { public static void main(string[] args) { int x = 5; int y = 7; int nsum = x + y; System.out.println(x + " + " + y + " = " + nsum); 运 行 结 果 :5 + 7 = 12 而 在 JDK5.0 以 后 版 本 中 可 以 写 为 : 第 170 页

public class Test { public static void main(string[] args) { int x = 5; int y = 7; int nsum = x + y; System.out.printf("%d + %d = %d\n", x, y, nsum); 以 上 两 种 写 法 的 输 出 结 构 是 一 样 的, 即 5 + 7 = 12 这 种 改 变 不 仅 仅 是 形 式 上 的,printf 还 可 以 提 供 更 为 灵 活 强 大 的 输 出 功 能, 比 如 限 定 按 照 两 位 整 数 的 形 式 输 出, 可 以 写 为 : public class Test { public static void main(string[] args) { int x = 5; int y = 7; int nsum = x + y; System.out.printf("%02d + %02d = %02d\n", x, y, nsum); 运 行 输 出 结 果 将 是 05 + 07 = 12 其 实 这 个 功 能 在 Java 里 面 并 没 有 什 么 大 用, 具 体 的 printf 格 式 化 字 符 串 格 式 请 参 见 JDK 文 档 中 的 具 体 说 明 第 171 页

6.9 学 习 目 标 1. 学 会 使 用 JDK API 文 档 2. 掌 握 Object 类 中 的 equals hashcode tostring 方 法 的 作 用, 以 及 相 互 的 关 系 3. 掌 握 如 何 重 写 Object 类 中 的 equals hashcode tostring 方 法 4. equals 方 法 和 == 的 功 能 和 区 别 5. 至 少 掌 握 String 类 的 4 中 构 造 方 法 6. 理 解 String 类 的 存 储 结 构 7. 熟 练 掌 握 String 类 中 的 方 法 能 说 出 大 部 分 方 法 的 方 法 名 称 完 成 的 功 能, 甚 至 参 数 列 表 返 回 值 类 型 8. 了 解 正 则 表 达 式 完 成 的 功 能 9. 在 Java 中 使 用 正 则 表 达 式 完 成 验 证 功 能 10. 描 述 正 则 表 达 式 中 有 哪 些 元 字 符 11. 如 何 在 正 则 表 达 式 中 表 示 重 复 12. 如 何 在 正 则 表 达 式 中 表 示 字 符 类 13. 为 什 么 要 用 StringBuffer?(String 有 什 么 缺 点 ) 14. 描 述 StringBuffer 的 容 量 和 长 度 15. StringBuffer 为 我 们 提 供 了 哪 些 String 没 有 的 方 法 16. StringBuffer 和 StringBuilder 的 区 别 17. 描 述 Math 类 中 常 用 的 方 法 18. 掌 握 课 上 画 的 关 于 日 期 的 图, 注 意 相 互 之 间 的 转 换 19. 8 个 基 本 数 据 类 型 对 应 8 个 包 装 类, 说 出 两 者 的 不 同 之 处 20. 理 解 自 动 包 装 和 解 包 21. 掌 握 如 何 通 过 System.in 创 建 扫 描 仪 Scanner, 如 何 使 用 Scanner 第 172 页

6.10 练 习 1. 设 计 一 个 员 工 类 Employee, 具 有 员 工 编 号 姓 名 性 别 住 址 出 生 日 期 属 性, 覆 盖 Object 的 equals 和 tostring 方 法 在 测 试 类 中, 分 别 创 建 两 个 员 工 对 象, 比 较 是 否 相 等, 并 打 印 员 工 信 息 2. 将 字 符 串 12-007, 张 三, 男, 上 海 浦 东 新 区 15 号,1983-2-6 中 的 信 息 抽 取 出 来, 封 装 到 第 一 题 中 创 建 的 员 工 对 象 中 3. 有 11 个 人 一 起 喝 啤 酒, 每 个 人 喝 3 瓶, 每 个 酒 箱 内 有 6 瓶 啤 酒, 问 要 买 几 箱 啤 酒?( 用 java 程 序 解 答 ) 4. 编 写 一 个 程 序, 输 入 字 符 串, 通 过 substring 方 法, 将 字 符 串 逆 序 输 出 5. 下 列 代 码 编 译 并 运 行 的 结 果 是 : public class Test { public static void main(string[] args) { double num = 7.4; int a = (int) Math.abs(num + 0.5); int b = (int) Math.ceil(num + 0.5); int c = (int) Math.floor(num + 0.5); int d = (int) Math.round(num + 0.5); int e = (int) Math.round(num - 0.5); int f = (int) Math.floor(num - 0.5); int g = (int) Math.ceil(num - 0.5); int h = (int) Math.abs(num - 0.5); System.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); 6. 在 控 制 台 输 入 字 符 串, 用 正 则 表 达 式 验 证 是 否 只 包 含 数 字 和 英 文 字 母 7. ( 按 不 同 格 式 打 印 日 期 ) 在 上 午 信 函 中, 日 期 可 以 几 种 不 同 的 格 式 打 印, 两 种 比 较 常 用 的 格 式 如 下 :09/21/2012 和 July 21,1013 编 写 一 个 程 序, 读 取 第 一 种 日 期 格 式 的 日 期, 并 以 第 二 种 日 期 格 式 返 回 8. 编 写 一 个 程 序, 用 随 机 数 生 成 语 句 该 程 序 应 用 4 个 String 类 型 的 数 组, 它 们 分 别 是 article,noun,verb,preposition 该 程 序 按 下 列 顺 序 从 4 个 数 组 中 随 机 选 取 一 个 元 素 生 成 一 个 语 句 :article,noun,verb,preposition,article,noun 当 选 取 每 个 单 词 时, 应 该 特 别 注 意 上 述 单 词 组 成 的 数 组 是 否 足 够 大 要 求 : 单 词 之 间 用 空 格 分 开, 输 出 最 后 的 语 句 时, 应 以 大 写 字 母 开 头, 以 圆 点 结 尾 每 次 点 击 回 车 生 成 下 第 173 页

一 条 语 句 语 句 填 充 如 下 :article 数 组 包 含 冠 词 :the,a,one,some,any noun 数 组 包 含 名 词 boy,girl,doy,town,cat verb 数 组 包 含 动 词 drove,jumped,ran,walked,skipped preposition 数 组 应 包 含 介 词 to,from,over,under,on 9. 计 算 当 前 时 间 距 明 年 春 节 还 有 多 少 天 多 少 小 时 多 少 分 钟 多 少 秒 10. 将 26 个 英 文 字 母 用 逗 号 分 隔, 组 成 字 符 串 打 印 出 来 考 虑 效 率 问 题, 使 用 StringBuffer 或 者 StringBuilder 11. 设 计 一 个 银 行 帐 户 类, 具 有 户 名, 帐 号, 密 码, 余 额 等 属 性, 在 控 制 台 模 拟 登 录 退 出 存 款 取 款 等 方 法, 并 对 此 类 进 行 测 试 12. 编 写 程 序, 测 试 计 算 1~50 的 阶 乘 的 和 所 耗 费 的 毫 秒 级 时 间 阶 乘 : 例 如 5 的 阶 乘 等 于 5*4*3*2*1 13. 找 出 1~1000 之 间 的 全 部 同 构 数 注 : 如 果 一 个 数 出 现 在 其 平 方 数 的 右 端, 则 称 此 数 为 同 构 数 如 :1 在 1*1=1 的 右 端, 5 在 5*5=25 的 右 端,25 在 25*25=625 的 右 端 等 等 第 174 页

7 抽 象 类 和 接 口 7.1 抽 象 类 7.1.1 什 么 是 抽 象 类 有 时 在 开 发 中, 要 创 建 一 个 体 现 某 些 基 本 行 为 的 类, 并 为 该 类 声 明 方 法, 但 不 能 在 该 类 中 实 现 该 行 为, 而 是 在 子 类 中 实 现 该 方 法 这 种 只 给 出 方 法 定 义 而 不 具 体 实 现 的 方 法 被 称 为 抽 象 方 法, 抽 象 方 法 是 没 有 方 法 体 的, 在 代 码 的 表 达 上 就 是 没 有 { 怎 么 表 示 一 个 方 法 是 抽 象 的 呢? 使 用 abstract 修 饰 符 来 表 达 抽 象 abstract 修 饰 符 可 以 与 类 和 方 法 一 起 使 用 被 修 饰 的 类 不 能 被 实 例 化, 被 修 饰 的 方 法 必 须 在 包 含 此 方 法 的 类 的 子 类 中 被 实 现 抽 象 类 简 单 地 说 : 使 用 abstract 修 饰 的 类 就 是 抽 象 类 示 例 如 下 : public abstract class Test {// 抽 象 类 定 义 public abstract void doitbyhand();// 抽 象 方 法 定 义 7.1.2 抽 象 类 的 使 用 例 如, 考 虑 一 个 Drawing 类 该 类 包 含 用 于 各 种 绘 图 设 备 的 方 法, 但 这 些 必 须 以 独 立 平 台 的 方 法 实 现 它 不 可 能 去 访 问 机 器 的 录 像 硬 件 而 且 还 必 须 是 独 立 于 平 台 的 其 意 图 是 绘 图 类 定 义 哪 种 方 法 应 该 存 在, 但 实 际 上, 由 特 殊 的 从 属 于 平 台 子 类 去 实 现 这 个 行 为 正 如 Drawing 类 这 样 的 类, 它 声 明 方 法 的 存 在 而 不 是 实 现, 以 及 带 有 对 已 知 行 为 的 方 法 的 实 现, 这 样 的 类 通 常 被 称 做 抽 象 类 通 过 用 关 键 字 abstract 进 行 标 记 声 明 一 个 抽 象 类 被 声 明 但 没 有 实 现 的 方 法 ( 即, 这 些 没 有 程 序 体 或 {), 也 必 须 标 记 为 抽 象 public abstract class Drawing { public abstract void drawdot(int x, int y); public void drawline(int x1, int y1, int x2, int y2) { // draw using the drawdot() method repeatedly. 抽 象 类 不 能 直 接 使 用, 必 须 用 子 类 去 实 现 抽 象 类, 然 后 使 用 其 子 类 的 实 例 然 而 可 以 创 建 一 个 变 量, 其 类 型 是 一 个 抽 象 类, 并 让 它 指 向 具 体 子 类 的 一 个 实 例, 也 就 是 可 以 使 用 抽 象 类 来 充 当 形 参, 实 际 实 现 类 作 为 实 参, 也 就 是 多 态 的 应 用 第 175 页

不 能 有 抽 象 构 造 方 法 或 抽 象 静 态 方 法 abstract 类 的 子 类 为 它 们 父 类 中 的 所 有 抽 象 方 法 提 供 实 现, 否 则 它 们 也 是 抽 象 类 public class MachineDrawing extends Drawing { public void drawdot(int machx, int machy) { // 画 点 Drawing d = new MachineDrawing(); 在 下 列 情 况 下, 一 个 类 将 成 为 抽 象 类 : (1) 当 一 个 类 的 一 个 或 多 个 方 法 是 抽 象 方 法 时 ; (2) 当 类 是 一 个 抽 象 类 的 子 类, 并 且 不 能 为 任 何 抽 象 方 法 提 供 任 何 实 现 细 节 或 方 法 主 体 时 ; (3) 当 一 个 类 实 现 一 个 接 口, 并 且 不 能 为 任 何 抽 象 方 法 提 供 实 现 细 节 或 方 法 主 体 时 ; 注 意 : (1) 这 里 说 的 是 这 些 情 况 下 一 个 类 将 成 为 抽 象 类, 没 有 说 抽 象 类 一 定 会 有 这 些 情 况 (2) 一 个 典 型 的 错 误 : 抽 象 类 一 定 包 含 抽 象 方 法 但 是 反 过 来 说 包 含 抽 象 方 法 的 类 一 定 是 抽 象 类 就 是 正 确 的 (3) 事 实 上, 抽 象 类 可 以 是 一 个 完 全 正 常 实 现 的 类 7.2 接 口 的 基 本 概 念 接 口 可 以 说 是 Java 程 序 设 计 中 最 重 要 的 概 念 之 一 了, 面 向 接 口 编 程 是 面 向 对 象 世 界 的 共 识, 所 以 深 刻 理 解 并 熟 练 应 用 接 口 是 每 一 个 学 习 Java 编 程 人 员 的 重 要 任 务 7.2.1 接 口 概 念 Java 可 以 创 建 一 种 称 作 接 口 (interface) 的 类, 在 这 个 类 中, 所 有 的 成 员 方 法 都 是 抽 象 的, 也 就 是 说 它 们 都 只 有 定 义 而 没 有 具 体 实 现, 接 口 是 抽 象 方 法 和 常 量 值 的 定 义 的 集 合 从 本 质 上 讲, 接 口 是 一 种 特 殊 的 抽 象 类, 用 interface, 可 以 指 定 一 个 类 必 须 做 什 么, 而 不 是 规 定 它 如 何 去 做 定 义 接 口 的 语 法 格 式 如 下 : 访 问 修 饰 符 interface 接 口 名 称 { 抽 象 属 性 集 抽 象 方 法 集 现 实 中 也 有 很 多 接 口 的 实 例, 比 如 说 串 口 电 脑 硬 盘,Serial ATA 委 员 会 指 定 了 Serial ATA 2.0 规 范, 这 种 规 范 就 是 接 口 Serial ATA 委 员 会 不 负 责 生 产 硬 盘, 只 是 指 定 通 用 的 规 范 希 捷 日 立 三 星 等 生 产 厂 家 会 按 照 规 范 生 产 符 合 接 口 的 硬 盘, 这 些 硬 盘 就 可 以 实 第 176 页

现 通 用 化, 如 果 正 在 用 一 块 160G 日 立 的 串 口 硬 盘, 现 在 要 升 级 了, 可 以 购 买 一 块 320G 的 希 捷 串 口 硬 盘, 安 装 上 去 就 可 以 继 续 使 用 了 在 Java 中 可 以 模 拟 Serial ATA 委 员 会 定 义 以 下 串 口 硬 盘 接 口 // 串 行 硬 盘 接 口 public interface SataHdd{ // 连 接 线 的 数 量 public static final int CONNECT_LINE=4; // 写 数 据 public void writedata(string data); // 读 数 据 public String readdata(); 目 前 看 来 接 口 和 抽 象 类 差 不 多 确 实 如 此, 接 口 本 就 是 从 抽 象 类 中 演 化 而 来 的, 因 而 除 特 别 规 定, 接 口 享 有 和 类 同 样 的 待 遇 比 如, 源 程 序 中 可 以 定 义 多 个 类 或 接 口, 但 最 多 只 能 有 一 个 public 的 类 或 接 口, 如 果 有 则 源 文 件 必 须 取 和 public 的 类 和 接 口 相 同 的 名 字 和 类 的 继 承 格 式 一 样, 接 口 之 间 也 可 以 继 承, 子 接 口 可 以 继 承 父 接 口 中 的 常 量 和 抽 象 方 法 并 添 加 新 的 抽 象 方 法 等 但 接 口 有 其 自 身 的 一 些 特 性, 归 纳 如 下 : 接 口 中 声 明 的 成 员 变 量 默 认 都 是 public static final 的, 必 须 显 示 的 初 始 化 因 而 在 常 量 声 明 时 可 以 省 略 这 些 修 饰 符 接 口 中 只 能 定 义 抽 象 方 法, 这 些 方 法 默 认 为 public abstract 的, 因 而 在 声 明 方 法 时 可 以 省 略 这 些 修 饰 符 试 图 在 接 口 中 定 义 实 例 变 量 非 抽 象 的 实 例 方 法 及 静 态 方 法, 都 是 非 法 的 public interface SataHdd{ // 连 接 线 的 数 量 public int connectline;// 编 译 出 错,connectLine 是 静 态 常 量, 必 须 显 式 初 始 化 // 写 数 据 protected void writedata(string data); // 编 译 出 错, 必 须 是 public 类 型 // 读 数 据 public static String readdata(){ // 编 译 出 错, 接 口 中 不 能 包 含 静 态 方 法 return " 数 据 "; // 编 译 出 错, 接 口 中 只 能 包 含 抽 象 方 法, 接 口 中 没 有 构 造 方 法, 不 能 被 实 例 化 继 承 一 个 接 口 不 实 现 另 一 个 接 口, 但 可 以 继 承 多 个 其 他 接 口 接 口 的 多 继 承 特 点 弥 补 了 类 的 单 // 串 行 硬 盘 接 口 public interface SataHdd extends A,B{ // 连 接 线 的 数 量 第 177 页

public static final int CONNECT_LINE = 4; // 写 数 据 public void writedata(string data); // 读 数 据 public String readdata(); interface A{ public void a(); interface B{ public void b(); 7.2.2 为 什 么 使 用 接 口 两 个 类 中 的 两 个 类 似 的 功 能, 调 用 它 们 的 类 动 态 地 决 定 一 种 实 现, 那 它 们 提 供 一 个 抽 象 父 类, 子 类 分 别 实 现 父 类 所 定 义 的 方 法 问 题 的 出 现 :Java 是 一 种 单 继 承 的 语 言, 一 般 情 况 下, 哪 个 具 体 类 可 能 已 经 有 了 一 个 父 类, 解 决 是 给 它 的 父 类 加 父 类, 或 者 给 它 父 类 的 父 类 加 父 类, 只 到 移 动 到 类 等 级 结 构 的 最 顶 端 这 样 一 来, 对 一 个 具 体 类 的 可 插 入 性 的 设 计, 就 变 成 了 对 整 个 等 级 结 构 中 所 有 类 的 修 改 接 口 是 可 插 入 性 的 保 证 在 一 个 等 级 结 构 中 的 任 何 一 个 类 都 可 以 实 现 一 个 接 口, 这 个 接 口 会 影 响 到 此 类 的 所 有 子 类, 但 不 会 影 响 到 此 类 的 任 何 父 类 此 类 将 不 得 不 实 现 这 个 接 口 所 规 定 的 方 法, 而 其 子 类 可 以 从 此 类 自 动 继 承 这 些 方 法, 当 然 也 可 以 选 择 置 换 掉 所 有 的 这 些 方 法, 或 者 其 中 的 某 一 些 方 法, 这 时 候, 这 些 子 类 具 有 了 可 插 入 性 ( 并 且 可 以 用 这 个 接 口 类 型 装 载, 传 递 实 现 了 他 的 所 有 子 类 ) 我 们 关 心 的 不 是 哪 一 个 具 体 的 类, 而 是 这 个 类 是 否 实 现 了 我 们 需 要 的 接 口 接 口 提 供 了 关 联 以 及 方 法 调 用 上 的 可 插 入 性, 软 件 系 统 的 规 模 越 大, 生 命 周 期 越 长, 接 口 使 得 软 件 系 统 的 灵 活 性 和 可 扩 展 性, 可 插 入 性 方 面 得 到 保 证 接 口 把 方 法 的 特 征 和 方 法 的 实 现 分 割 开 来 这 种 分 割 体 现 在 接 口 常 常 代 表 一 个 角 色, 它 包 装 与 该 角 色 相 关 的 操 作 和 属 性, 而 实 现 这 个 接 口 的 类 便 是 扮 演 这 个 角 色 的 演 员 一 个 角 色 由 不 同 的 演 员 来 演, 而 不 同 的 演 员 之 间 除 了 扮 演 一 个 共 同 的 角 色 之 外, 并 不 要 求 其 它 的 共 同 之 处 对 于 下 述 情 况, 接 口 是 有 用 的 : (1) 声 明 方 法, 期 望 一 个 或 更 多 的 类 来 实 现 该 方 法 (2) 揭 示 一 个 对 象 的 编 程 接 口, 而 不 揭 示 类 的 实 际 程 序 体 ( 当 将 类 的 一 个 包 输 送 到 其 它 开 发 程 序 中 时 它 是 非 常 有 用 的 ) (3) 捕 获 无 关 类 之 间 的 相 似 性, 而 不 强 迫 类 关 系 第 178 页

(4) 可 以 作 为 参 数 被 传 递 到 在 其 它 对 象 上 调 用 的 方 法 中 面 向 对 象 程 序 设 计 讲 究 提 高 内 聚, 降 低 耦 合, 那 么 不 同 的 程 序 模 块 怎 么 相 互 访 问 呢, 就 是 通 过 接 口, 也 就 是 接 口 是 各 部 分 对 外 的 统 一 外 观 接 口 在 Java 程 序 设 计 中 体 现 的 思 想 就 是 隔 离, 因 为 接 口 只 是 描 述 一 个 统 一 的 行 为, 所 以 开 发 人 员 在 面 向 接 口 编 程 时 并 不 关 心 具 体 的 实 现 由 以 上 讲 到 的 接 口 的 作 用 和 基 本 思 想 可 以 看 到, 接 口 在 面 向 对 象 的 Java 程 序 设 计 中 占 有 举 足 轻 重 的 地 位 事 实 上 在 设 计 阶 段 最 重 要 的 任 务 之 一 就 是 设 计 出 各 部 分 的 接 口, 然 后 通 过 接 口 的 组 合, 形 成 程 序 的 基 本 框 架 结 构 7.3 接 口 作 为 类 型 使 用 7.3.1 接 口 的 使 用 接 口 的 使 用 与 类 的 使 用 有 些 不 同 在 需 要 使 用 类 的 地 方, 会 直 接 使 用 new 关 键 字 来 构 建 一 个 类 的 实 例 进 行 应 用 : ClassA a =new ClassA(); 这 是 正 确 的 但 接 口 不 可 以 这 样 用, 因 为 接 口 不 能 直 接 使 用 new 关 键 字 来 构 建 实 例 SataHdd sh = new SataHdd(); 这 是 错 误 的, 接 口 在 使 用 的 时 候 要 实 例 化 相 应 的 实 现 类 实 现 类 的 格 式 如 下 : 访 问 修 饰 符 修 饰 符 class 类 名 extends 父 类 implements 多 个 接 口 { 实 现 方 法 说 明 : 接 口 必 须 通 过 类 来 实 现 它 的 抽 象 方 法, 类 实 现 接 口 的 关 键 字 为 implements 如 果 一 个 类 不 能 实 现 该 接 口 的 所 有 抽 象 方 法, 那 么 这 个 类 必 须 被 定 义 为 抽 象 方 法 例 不 允 许 创 建 接 口 的 实 例, 但 允 许 定 义 接 口 类 型 的 引 用 变 量, 该 变 量 指 向 了 实 现 接 口 的 类 的 实 一 个 类 只 能 继 承 一 个 父 类, 但 却 可 以 实 现 多 个 接 口 // 希 捷 硬 盘 public class SeagateHdd implements SataHdd,A{ public String readdata() { // 希 捷 硬 盘 读 取 数 据 第 179 页

return " 数 据 "; public void writedata(string data) { // 希 捷 硬 盘 写 入 数 据 // 三 星 硬 盘 public class SamsungHdd implements SataHdd{ public String readdata() { // 三 星 硬 盘 读 取 数 据 return " 数 据 "; public void writedata(string data) { // 三 星 硬 盘 写 入 数 据 // 某 劣 质 硬 盘, 不 能 写 数 据 public abstract class XXHdd implements SataHdd{ public String readdata() { // 硬 盘 读 取 数 据 return " 数 据 "; public class Client{ public static void main(string[] args) { SataHdd sh1=new SeagateHdd(); // 初 始 化 希 捷 硬 盘 SataHdd sh2=new SamsungHdd(); // 初 始 化 三 星 硬 盘 7.3.2 接 口 作 为 类 型 使 用 接 口 作 为 引 用 类 型 来 使 用, 任 何 实 现 该 接 口 的 类 的 实 例 都 可 以 存 储 在 该 接 口 类 型 的 变 量 中, 通 过 这 些 变 量 可 以 访 问 类 中 所 实 现 的 接 口 中 的 方 法,Java 运 行 时 系 统 会 动 态 地 确 定 应 该 使 用 哪 个 类 中 的 方 法, 实 际 上 是 调 用 相 应 的 实 现 类 的 方 法 示 例 如 下 : public class Test { public void test1(a a) { a.dosth(); public static void main(string[] args) { Test t = new Test(); A a = new B(); t.test1(a); 第 180 页

public interface A { public int dosth(); public class B implements A { public int dosth() { System.out.println("now in B"); return 123; 运 行 结 果 :now in B 大 家 看 到 接 口 可 以 作 为 一 个 类 型 来 使 用, 把 接 口 作 为 方 法 的 参 数 和 返 回 类 型 7.4 接 口 和 抽 象 类 的 选 择 由 于 从 某 种 角 度 讲, 接 口 是 一 种 特 殊 的 抽 象 类, 它 们 的 渊 源 颇 深, 有 很 大 的 相 似 之 处, 所 以 在 选 择 使 用 谁 的 问 题 上 很 容 易 迷 糊 我 们 首 先 分 析 它 们 具 有 的 相 同 点 都 代 表 类 树 形 结 构 的 抽 象 层 在 使 用 引 用 变 量 时, 尽 量 使 用 类 结 构 的 抽 象 层, 使 方 法 的 定 义 和 实 现 分 离, 这 样 做 对 于 代 码 有 松 散 耦 合 的 好 处 都 不 能 被 实 例 化 都 能 包 含 抽 象 方 法 抽 象 方 法 用 来 描 述 系 统 提 供 哪 些 功 能, 而 不 必 关 心 具 体 的 实 现 抽 象 类 和 接 口 的 主 要 区 别 : 抽 象 类 可 以 为 部 分 方 法 提 供 实 现, 避 免 了 在 子 类 中 重 复 实 现 这 些 方 法, 提 高 了 代 码 的 可 重 用 性, 这 是 抽 象 类 的 优 势 ; 而 接 口 中 只 能 包 含 抽 象 方 法, 不 能 包 含 任 何 实 现 public abstract class A{ public abstract void method1(); public void method2(){ //A method2 public class B extends A{ public void method1(){ //B method1 public class C extends A{ public void method1(){ //C method1 第 181 页

抽 象 类 A 有 两 个 子 类 B C, 由 于 A 中 有 方 法 method2 的 实 现, 子 类 B C 中 不 需 要 重 写 method2 方 法, 我 们 就 说 A 为 子 类 提 供 了 公 共 的 功 能, 或 A 约 束 了 子 类 的 行 为 method2 就 是 代 码 可 重 用 的 例 子 A 并 没 有 定 义 method1 的 实 现, 也 就 是 说 B C 可 以 根 据 自 己 的 特 点 实 现 method1 方 法, 这 又 体 现 了 松 散 耦 合 的 特 性 再 换 成 接 口 看 看 : public interface A{ public void method1(); public void method2(); public class B implements A{ public void method1(){ //B method1 public void method2(){ //B method2 public class C implements A{ public void method1(){ //C method1 public void method2(){ //C method2 接 口 A 无 法 为 实 现 类 B C 提 供 公 共 的 功 能, 也 就 是 说 A 无 法 约 束 B C 的 行 为 B C 可 以 自 由 地 发 挥 自 己 的 特 点 现 实 method1 和 method2 方 法, 接 口 A 毫 无 掌 控 能 力 一 个 类 只 能 继 承 一 个 直 接 的 父 类 ( 可 能 是 抽 象 类 ), 但 一 个 类 可 以 实 现 多 个 接 口, 这 个 就 是 接 口 的 优 势 interface A{ public void method2(); interface B{ public void method1(); class C implements A,B{ public void method1(){ //C method1 public void method2(){ //C method2 // 可 以 如 此 灵 活 的 使 用 C, 并 且 C 还 有 机 会 进 行 扩 展, 实 现 其 他 接 口 A a=new C(); 第 182 页

B b=new C(); abstract class A{ public abstract void method1(); abstract class B extends A{ public abstract void method2(); class C extends B{ public void method1(){ //C method1 public void method2() { //C method2 对 于 C 类, 将 没 有 机 会 继 承 其 他 父 类 了 综 上 所 述, 接 口 和 抽 象 类 各 有 优 缺 点, 在 接 口 和 抽 象 类 的 选 择 上, 必 须 遵 守 这 样 一 个 原 则 : 行 为 模 型 应 该 总 是 通 过 接 口 而 不 是 抽 象 类 定 义 所 以 通 常 是 : (1) 优 先 选 用 接 口, 尽 量 少 用 抽 象 类 选 择 抽 象 类 的 时 候 通 常 是 如 下 情 况 : (2) 需 要 定 义 子 类 的 行 为, 又 要 为 子 类 提 供 共 性 的 功 能 第 183 页

7.5 学 习 目 标 1. 什 么 是 抽 象 方 法? 什 么 是 抽 象 类? 2. 在 Java 中 如 何 表 示 抽 象 类 和 抽 象 方 法 3. 抽 象 方 法 和 抽 象 类 的 关 系? 4. 抽 象 类 中 是 否 有 属 性, 抽 象 类 中 是 否 有 构 造 方 法 5. 如 何 使 用 抽 象 类 6. 什 么 是 接 口? 接 口 的 定 义 规 则? 7. 接 口 的 作 用? 为 什 么 使 用 接 口? 8. 举 例 说 明 如 何 把 接 口 当 作 类 型 使 用 9. 如 何 选 择 接 口 和 抽 象 类? 为 什 么? 7.6 练 习 1. 定 义 一 个 接 口 交 通 工 具, 说 明 交 通 工 具 可 以 移 动 实 现 交 通 工 具 而 产 生 汽 车 飞 机 轮 船, 并 定 义 类 来 实 现 其 移 动 的 方 法 2. 定 义 一 个 类 来 使 用 上 面 的 接 口 第 184 页

8 异 常 8.1 异 常 的 定 义 8.1.1 异 常 基 础 知 识 在 Java 编 程 语 言 中, 异 常 是 指 当 程 序 出 错 时 创 建 的 一 种 特 殊 的 运 行 时 错 误 对 象 注 意 这 个 错 误 不 是 编 译 时 的 语 法 错 误 Java 创 建 异 常 对 象 后, 就 发 送 给 Java 程 序, 即 抛 出 异 常 (throwing an exception) 程 序 捕 捉 到 这 个 异 常 后, 可 以 编 写 相 应 的 异 常 处 理 代 码 进 行 处 理, 而 不 是 让 程 序 中 断 使 用 异 常 处 理 可 以 提 高 程 序 的 健 壮 性, 有 助 于 调 试 和 后 期 维 护 在 程 序 执 行 中, 任 何 中 断 正 常 程 序 流 程 的 异 常 条 件 就 是 错 误 或 异 常 例 如, 发 生 下 列 情 况 时, 会 出 现 异 常 : - 想 打 开 的 文 件 不 存 在 - 网 络 连 接 中 断 - 受 控 操 作 数 超 出 预 定 范 围 - 正 在 装 载 的 类 文 件 丢 失 在 Java 编 程 语 言 中, 错 误 类 定 义 被 认 为 是 不 能 恢 复 的 严 重 错 误 条 件 在 大 多 数 情 况 下, 当 遇 到 这 样 的 错 误 时, 建 议 让 程 序 中 断 Java 编 程 语 言 实 现 异 常 处 理 来 帮 助 建 立 弹 性 代 码 在 程 序 中 发 生 错 误 时, 发 现 错 误 的 方 法 能 抛 出 一 个 异 常 到 其 调 用 程 序, 发 出 已 经 发 生 问 题 的 信 号 然 后, 调 用 方 法 捕 获 抛 出 的 异 常, 在 可 能 时, 再 恢 复 回 来 这 个 方 案 给 程 序 员 一 个 写 处 理 程 序 的 选 择, 来 处 理 异 常 通 过 浏 览 API, 可 以 了 解 方 法 抛 出 的 是 什 么 样 的 异 常 8.1.2 异 常 实 例 在 学 习 在 程 序 中 处 理 异 常 之 前, 看 一 看 如 果 不 处 理 异 常, 会 有 什 么 情 况 发 生 下 面 的 小 程 序 包 括 一 个 故 意 导 致 被 零 除 错 误 的 表 达 式 class Exc0 { public static void main(string args[]) { int d = 0; int a = 42 / d; 第 185 页

当 Java 运 行 时 系 统 检 查 到 被 零 除 的 情 况, 它 构 造 一 个 新 的 异 常 对 象 然 后 引 发 该 异 常 这 导 致 Exc0 的 执 行 停 止, 因 为 一 旦 一 个 异 常 被 引 发, 它 必 须 被 一 个 异 常 处 理 程 序 捕 获 并 且 被 立 即 处 理 该 例 中, 没 有 提 供 任 何 异 常 处 理 程 序, 所 以 异 常 被 Java 运 行 时 系 统 的 默 认 处 理 程 序 捕 获 任 何 不 是 被 你 程 序 捕 获 的 异 常 最 终 都 会 被 该 默 认 处 理 程 序 处 理 默 认 处 理 程 序 显 示 一 个 描 述 异 常 的 字 符 串, 打 印 异 常 发 生 处 的 堆 栈 轨 迹 并 且 终 止 程 序 下 面 是 由 标 准 javajdk 运 行 时 解 释 器 执 行 该 程 序 所 产 生 的 输 出 : java.lang.arithmeticexception: / by zero at Exc0.main(Exc0.java:4) 类 名 Exc0, 方 法 名 main, 文 件 名 Exc0.java 和 行 数 4 被 包 括 在 一 个 堆 栈 使 用 轨 迹 中, 用 于 提 示 异 常 所 发 生 的 位 置, 显 示 导 致 错 误 产 生 的 方 法 调 用 序 列 引 发 的 异 常 类 型 是 Exception 的 一 个 名 为 ArithmeticException 的 子 类, 该 子 类 更 明 确 的 描 述 了 何 种 类 型 的 错 误 方 法 Java 提 供 多 个 内 置 的 与 可 能 产 生 的 不 同 种 类 运 行 时 错 误 相 匹 配 的 异 常 类 型 下 面 是 前 面 程 序 的 另 一 个 版 本, 它 介 绍 了 相 同 的 错 误, 但 是 错 误 是 在 main() 方 法 之 外 的 另 一 个 方 法 中 产 生 的 : class Exc1 { static void subroutine() { int d = 0; int a = 10 / d; public static void main(string args[]) { Exc1.subroutine(); 默 认 异 常 处 理 器 的 堆 栈 轨 迹 结 果 表 明 了 整 个 调 用 栈 是 怎 样 显 示 的 : java.lang.arithmeticexception: / by zero at Exc1.subroutine(Exc1.java:4) at Exc1.main(Exc1.java:7) 栈 底 是 main 的 第 7 行, 该 行 调 用 了 subroutine() 方 法 该 方 法 在 第 4 行 导 致 了 异 常 调 用 堆 栈 对 于 调 试 来 说 是 很 重 要 的, 因 为 它 查 明 了 导 致 错 误 的 精 确 的 步 骤 8.2 异 常 的 处 理 Java 提 供 了 一 种 异 常 处 理 模 型, 它 使 您 能 检 查 异 常 并 进 行 相 应 的 处 理 它 实 现 的 是 异 常 处 理 的 抓 抛 模 型 使 用 此 模 型, 您 只 需 要 注 意 有 必 要 加 以 处 理 的 异 常 情 况 Java 提 供 的 这 种 异 常 处 理 模 型, 代 替 了 用 返 回 值 或 参 数 机 制 从 方 法 返 回 异 常 码 的 手 段 异 常 处 理 的 抓 抛 方 法 有 两 大 优 点 : (1) 异 常 情 况 能 仅 在 有 必 要 之 处 加 以 处 理, 防 止 程 序 自 动 终 止, 而 不 在 其 发 生 处 和 需 要 进 行 处 理 处 之 间 的 每 一 级 上 均 进 行 处 理 第 186 页

(2) 能 够 编 写 统 一 的 可 重 用 的 异 常 处 理 代 码 应 该 区 别 对 待 程 序 中 的 正 常 控 制 流 和 异 常 处 理 流 当 然, 异 常 处 理 流 也 是 程 序 中 的 控 制 流 当 异 常 发 生 时, 抛 出 一 个 异 常 异 常 伴 随 调 用 链, 直 到 它 们 被 捕 获 或 程 序 退 出 为 止 下 面 是 Java 语 言 中 的 异 常 处 理 块 的 模 型 : try { // 放 置 可 能 出 现 异 常 的 代 码 catch (Exception1 el) { // 如 果 try 块 抛 出 异 常 对 象 的 类 型 为 Exceptionl, 那 么 就 在 这 里 进 行 处 理 catch (Exception2 e2) { // 如 果 try 块 抛 出 异 常 对 象 的 类 型 为 Exception2, 那 么 就 在 这 里 进 行 处 理 catch (ExceptionN en) { // 如 果 try 块 抛 出 异 常 对 象 的 类 型 为 ExceptionN, 那 么 就 在 这 里 进 行 处 理 finally { // 不 管 是 否 有 异 常 发 生, 始 终 执 行 这 个 代 码 块 在 未 提 供 适 当 异 常 处 理 机 制 的 程 序 中, 无 论 何 时 发 生 异 常, 程 序 均 会 异 常 中 断, 而 之 前 分 配 的 所 有 资 源 则 保 持 其 状 态 不 变 这 会 导 致 资 源 遗 漏 要 避 免 这 一 情 况, 在 适 当 的 异 常 处 理 机 制 中, 我 们 可 以 将 以 前 由 系 统 分 配 的 所 有 资 源 返 还 给 系 统 所 以, 当 异 常 可 能 发 生 时, 要 牢 记 必 须 对 每 一 异 常 分 别 进 行 处 理 例 如 我 们 处 理 文 件 I/O, 在 打 开 文 件 时 发 生 IOException, 程 序 异 常 中 断 而 没 有 机 会 关 闭 该 文 件, 这 可 能 会 毁 坏 文 件 而 且 分 配 给 该 文 件 的 操 作 系 统 资 源 可 能 未 返 还 给 系 统 8.2.1 try-catch try 块 由 一 组 可 执 行 语 句 组 成, 在 执 行 它 们 时 可 能 会 抛 出 异 常 catch 块, 是 用 来 捕 获 并 处 理 try 中 抛 出 的 异 常 的 代 码 块 catch 块 不 能 单 独 存 在, 可 以 有 多 个 catch 块, 以 捕 获 不 同 类 型 的 异 常 try 不 可 以 跟 随 在 catch 块 之 后 class Exc0 { public static void main(string args[]) { try { int d = 0; int a = 1 / d; System.out.println("This will not be printed"); catch (ArithmeticException e) { System.out.println("Division by zero"); System.out.println("After catch statement"); 第 187 页

程 序 将 会 发 生 异 常 而 中 断, 异 常 可 在 catch 块 中 被 捕 获, 输 出 如 下 : Division by zero After catch statement 在 try 块 中 对 println() 的 调 用 是 不 会 执 行 的 一 旦 异 常 被 引 发, 程 序 控 制 由 try 块 转 到 catch 块 执 行 永 远 不 会 从 catch 块 返 回 到 try 块 因 此, 第 6 行 将 不 会 被 执 行 一 旦 执 行 了 catch 语 句, 程 序 控 制 从 整 个 try/catch 机 制 的 下 面 一 行 ( 第 10 行 ) 继 续 一 个 try 和 它 的 catch 语 句 形 成 了 一 个 单 元 catch 子 句 的 范 围 限 制 于 try 语 句 前 面 所 定 义 的 语 句 一 个 catch 语 句 不 能 捕 获 另 一 个 try 声 明 所 引 发 的 异 常 ( 除 非 是 嵌 套 的 try 语 句 情 况 ) 被 try 保 护 的 语 句 声 明 必 须 在 一 个 大 括 号 之 内 ( 也 就 是 说, 它 们 必 须 在 一 个 块 中 ) 不 能 单 独 使 用 try 构 造 catch 子 句 的 目 的 是 解 决 异 常 情 况 并 且 像 错 误 没 有 发 生 一 样 继 续 运 行 例 如, 下 面 的 程 序 中, 每 一 个 for 循 环 的 反 复 得 到 两 个 随 机 整 数 这 两 个 整 数 分 别 被 对 方 除, 结 果 用 来 除 1000 最 后 的 结 果 存 在 a 中 如 果 一 个 除 法 操 作 导 致 被 零 除 错 误, 它 将 被 捕 获,a 的 值 设 为 零, 程 序 继 续 运 行 import java.util.random; class HandleError { public static void main(string args[]) { int a = 0, b = 0, c = 0; Random r = new Random(); for (int i = 0; i < 10; i++) { try { b = r.nextint(); c = r.nextint(); a = 1000 / (b / c); catch (ArithmeticException e) { System.out.println("Division by zero."); a = 0; // set a to zero and continue System.out.println("a: " + a); try 块 可 以 嵌 套, 也 就 是 说, 一 个 try 语 句 可 以 在 另 一 个 try 块 内 部 每 次 进 入 try 语 句, 异 常 的 前 后 关 系 都 会 被 推 入 堆 栈 如 果 一 个 内 部 的 try 语 句 不 含 特 殊 异 常 的 catch 处 理 程 序, 堆 栈 将 弹 出, 下 一 个 try 语 句 的 catch 处 理 程 序 将 检 查 是 否 与 之 匹 配 这 个 过 程 将 继 续 直 到 一 个 catch 语 句 匹 配 成 功, 或 者 是 直 到 所 有 的 嵌 套 try 语 句 被 检 查 耗 尽 如 果 没 有 catch 语 句 匹 配,Java 的 运 行 时 系 统 将 处 理 这 个 异 常 下 面 是 运 用 嵌 套 try 语 句 的 一 个 例 子 : class Exc0 { public static void main(string args[]) { try { int a = 1 / 0; try { 第 188 页

int b = 2 / 0; catch (Exception e2) { // 异 常 处 理 System.out.println("e2"); catch (Exception e) { // 异 常 处 理 System.out.println("e1"); 当 执 行 到 第 4 行 代 码 时, 发 生 了 异 常, 被 第 11 行 的 catch 捕 捉 到, 再 执 行 第 14 行 的 异 常 处 理 代 码, 而 不 执 行 第 5 行 至 第 10 行 的 代 码 如 果 第 4 行 没 有 异 常 产 生, 将 会 捕 捉 到 第 6 行 代 码 的 异 常 当 多 个 catch 块 存 在 的 时 候, 从 上 往 下 catch 异 常 的 范 围 应 该 从 小 到 大, 因 为 catch 块 的 运 行 机 制 是 找 到 一 个 匹 配 的 就 进 行 处 理 了, 如 果 把 范 围 大 的 放 在 前 面, 那 么 后 面 的 代 码 就 没 有 机 会 运 行 了, 这 会 是 一 个 编 译 异 常 比 如 下 面 这 个 是 正 确 的 : public class Exc0 { public static void main(string[] args) { try { int a = 5 / 0; catch (ArithmeticException e) { e.printstacktrace(); catch (Exception err) { err.printstacktrace(); 而 下 面 这 个 就 是 错 误 的 了, 编 译 都 发 生 了 错 误 : public class Exc0 { public static void main(string[] args) { try { int a = 1 / 0; catch (Exception err) { err.printstacktrace(); catch (ArithmeticException e) { e.printstacktrace(); 第 189 页

8.2.2 finally 块 finally 块 表 示 : 无 论 是 否 出 现 异 常, 都 会 运 行 的 块 通 常 在 finally 块 中 可 以 编 写 资 源 返 还 给 系 统 的 语 句, 通 常, 这 些 语 句 包 括 但 不 限 于 : (1) 释 放 动 态 分 配 的 内 存 块 : (2) 关 闭 文 件 ; (3) 关 闭 数 据 库 结 果 集 ; (4) 关 闭 与 数 据 库 建 立 的 连 接 ; 它 紧 跟 着 最 后 一 个 块, 是 可 选 的, 不 论 是 否 抛 出 异 常, finally 块 总 会 被 执 行 finally 块 的 语 法 如 下 : try{ catch( 异 常 类 型 1 e){ catch( 异 常 类 型 2 e){ finally{ 下 面 的 程 序 显 示 的 是 finally 块 的 使 用 public class Test { static String name; static int n01, n02; public static void main(string args[]) { try { name = "Aptech Limited"; n01 = Integer.parseInt(args[0]); n02 = Integer.parseInt(args[1]); System.out.println(name); System.out.println("Division is" + n01 / n02); catch (ArithmeticException i) { System.out.println("Can not be divided by zero!"); finally { name = null; System.out.println("finally executed"); 从 下 面 的 命 令 行 执 行 此 程 序 : Java Test 20 0 将 会 得 到 下 面 的 输 出 : 第 190 页

Aptech Limited Can not be divided by zero! finally executed 现 在 从 下 面 的 命 令 行 执 行 此 程 序 : Java Test 20 4 则 会 得 到 下 面 这 样 的 输 出 : Aptech Limited Division is 5 finally executed 说 明 : 当 用 不 同 的 命 令 行 参 数 执 行 此 程 序 时, 均 会 看 见 finally executed 的 输 出 这 意 味 着, 无 论 try 块 是 否 抛 出 异 常, 都 会 执 行 finally 块 思 考 题 : 是 否 会 执 行 第 7 行 代 码? try{ System.out.println(1); return ; catch(exception e){ e.printstacktrace(); finally{ System.out.println(11); 8.2.3 try catch finally 块 的 关 系 (1)try 块 不 能 单 独 存 在, 后 面 必 须 跟 catch 块 或 者 finally 块 (2) 三 者 之 间 的 组 合 为 :try catch try catch finally try finally 这 几 种 是 合 法 的 (3) 一 个 try 块 可 以 有 多 个 catch 块, 从 上 到 下 多 个 catch 块 的 范 围 为 从 小 到 大 8.2.4 throw 语 句 throw 语 句 用 来 从 代 码 中 主 动 抛 出 异 常, 可 以 将 它 理 解 为 一 个 向 上 抛 出 的 动 作 throw 的 操 作 数 是 任 一 种 异 常 类 对 象 是 Throwable 类 类 型 或 Throwable 子 类 类 型 的 一 个 对 象 简 单 类 型, 例 如 int 或 char, 以 及 非 Throwable 类, 例 如 String 或 Object, 不 能 用 作 异 常 程 序 执 行 在 throw 语 句 之 后 立 即 停 止 ; 后 面 的 任 何 语 句 不 被 执 行 最 紧 紧 包 围 的 try 块 用 来 检 查 它 是 否 含 有 一 个 与 异 常 类 型 匹 配 的 catch 语 句 如 果 发 现 了 匹 配 的 块, 控 制 转 向 该 语 句 ; 如 果 没 有 发 现, 次 包 围 的 try 块 来 检 查, 以 此 类 推 如 果 没 有 发 现 匹 配 的 catch 块, 默 认 异 常 处 理 程 序 中 断 程 序 的 执 行 并 且 打 印 堆 栈 轨 迹 第 191 页

下 面 是 throw 关 键 字 的 一 个 示 例 : try { int i = 5/0; catch (ArithmeticException i) { throw new Exception("Can not be divided by zero!"); System.out.println("after throw"); 第 2 行 代 码 产 生 异 常, 然 后 执 行 catch 块 中 的 代 码, 第 4 行 抛 出 新 异 常, 将 不 再 执 行 第 5 行 代 码 序 下 面 是 一 个 创 建 并 引 发 异 常 的 例 子 程 序, 与 异 常 匹 配 的 处 理 程 序 再 把 它 引 发 给 外 层 的 处 理 程 class ThrowDemo { static void demoproc() { try { throw new NullPointerException("demo"); catch (NullPointerException e) { System.out.println("Caught inside demoproc."); throw e; // rethrow the exception public static void main(string args[]) { try { demoproc(); catch (NullPointerException e) { System.out.println("Recaught: " + e); 该 程 序 有 两 个 机 会 处 理 相 同 的 错 误 首 先, main() 设 立 了 一 个 异 常 关 系 然 后 调 用 demoproc() demoproc() 方 法 然 后 设 立 了 另 一 个 异 常 处 理 关 系 并 且 立 即 引 发 一 个 新 的 NullPointerException 实 例,NullPointerException 在 下 一 行 被 捕 获 异 常 于 是 被 再 次 引 发 下 面 是 输 出 结 果 : Caught inside demoproc. Recaught: java.lang.nullpointerexception: demo 该 程 序 还 阐 述 了 怎 样 创 建 Java 的 标 准 异 常 对 象, 特 别 注 意 下 面 这 一 行 : throw new NullPointerException("demo"); 这 里,new 用 来 构 造 一 个 NullPointerException 实 例 所 有 的 Java 内 置 的 运 行 时 异 常 有 两 个 构 造 函 数 : 一 个 没 有 参 数, 一 个 带 有 一 个 字 符 串 参 数 当 用 到 第 二 种 形 式 时, 参 数 指 定 描 述 异 常 的 字 符 串 如 果 对 象 用 作 print() 或 println() 的 参 数 时, 该 字 符 串 被 显 示 这 同 样 可 以 通 过 调 用 getmessage() 来 实 现,getMessage() 是 由 Throwable 定 义 的 第 192 页

8.2.5 throws 语 句 throws 用 来 在 方 法 定 义 时 声 明 异 常 Java 中 对 异 常 的 处 理 有 两 种 方 法, 一 个 就 是 try-catch, 然 后 自 己 处 理 ; 一 个 就 是 不 做 处 理, 向 外 throws, 由 调 用 该 方 法 的 代 码 去 处 理 Java 语 言 要 求 在 方 法 定 义 中 列 出 该 方 法 抛 出 的 异 常 : public class Example{ public static void exceptionexample() throws ExampleException,LookupException{ 在 上 面 的 示 例 中,exceptionExample() 声 明 包 括 throws 关 键 字, 其 后 列 出 了 此 方 法 可 能 抛 出 的 异 常 列 表 在 此 案 例 中 列 出 的 是 ExampleException 和 LookupException 比 如 前 面 那 个 例 子 写 完 整 如 下 : public class Exc0 { public static void main(string args[]) throws Exception { try { int a = 1 / 0; catch (ArithmeticException i) { throw new Exception("Can not be divided by zero!"); 8.2.6 调 用 栈 机 制 如 果 方 法 中 的 一 个 语 句 抛 出 一 个 没 有 在 相 应 的 try/catch 块 中 处 理 的 异 常, 那 么 这 个 异 常 就 被 抛 出 到 调 用 方 法 中 如 果 异 常 也 没 有 在 调 用 方 法 中 被 处 理, 它 就 被 抛 出 到 该 方 法 的 调 用 程 序 这 个 过 程 要 一 直 延 续 到 异 常 被 处 理 如 果 异 常 到 这 时 还 没 被 处 理, 它 便 回 到 main(), 而 且, 即 使 main() 不 处 理 它, 那 么, 该 异 常 就 异 常 地 中 断 程 序 考 虑 这 样 一 种 情 况, 在 该 情 况 中 main( ) 方 法 调 用 另 一 个 方 法 ( 比 如,first( )), 然 后 它 调 用 另 一 个 ( 比 如,second( )) 如 果 在 second( ) 中 发 生 异 常, 那 么 必 须 做 一 个 检 查 来 看 看 该 异 常 是 否 有 一 个 catch; 如 果 没 有, 那 么 对 调 用 栈 (first( )) 中 的 下 一 个 方 法 进 行 检 查, 然 后 检 查 下 一 个 (main()) 如 果 这 个 异 常 在 该 调 用 栈 上 没 有 被 最 后 一 个 方 法 处 理, 那 么 就 会 发 生 一 个 运 行 时 错 误, 程 序 终 止 执 行 第 193 页

8.3 异 常 的 分 类 8.3.1 异 常 的 分 类 在 Java 编 程 语 言 中, 异 常 有 两 种 分 类 java.lang.throwable 类 充 当 所 有 对 象 的 父 类, 可 以 使 用 异 常 处 理 机 制 将 这 些 对 象 抛 出 并 捕 获 在 Throwable 类 中 定 义 方 法 来 检 索 与 异 常 相 关 的 错 误 信 息, 并 打 印 显 示 异 常 发 生 的 栈 跟 踪 信 息 它 有 Error 和 Exception 两 个 基 本 子 类 错 误 (Error):JVM 系 统 内 部 错 误 资 源 耗 尽 等 严 重 情 况 ; 异 常 (Exception 违 例 ): 其 它 因 编 程 错 误 或 偶 然 的 外 在 因 素 导 致 的 一 般 性 问 题, 例 如 : 对 负 数 开 平 方 根 空 指 针 访 问 试 图 读 取 不 存 在 的 文 件 网 络 连 接 中 断 等 当 发 生 Error 时, 程 序 员 根 本 无 能 为 力, 只 能 让 程 序 终 止 比 如 说 内 存 溢 出, 不 可 能 指 望 程 序 能 处 理 这 样 的 情 况 而 对 于 Exception, 而 有 补 救 或 控 制 的 可 能, 程 序 员 也 可 以 预 先 防 范, 本 章 主 要 讨 论 Exception 的 处 理 为 有 效 地 描 述 异 常 状 况 传 递 有 关 的 异 常 信 息,JDK 中 针 对 各 种 普 遍 性 的 异 常 情 况 定 义 了 多 种 异 常 类 型 其 层 次 关 系 如 下 图 所 示 : VirtualMachineError LinkageError Error AWTError IOError Throwable ClassCastException RuntimeException ArrayIndexOutOfBound sexception EventException Exception SAXException FileNotFoundException IOException EOFException 第 194 页 FilterException

异 常 分 为 运 行 时 异 常 和 受 检 查 异 常 RuntimeException( 运 行 时 异 常 ) 是 指 因 设 计 或 实 现 方 式 不 当 导 致 的 问 题 也 可 以 说, 是 程 序 员 的 原 因 导 致 的, 本 来 可 以 避 免 发 生 的 情 况 比 如, 如 果 事 先 检 查 数 组 元 素 下 标 保 证 其 不 超 出 数 组 长 度, 那 么,ArrayIndexOutOfBoundsException 异 常 从 不 会 抛 出 ; 再 如, 先 检 查 并 确 保 一 个 引 用 类 型 变 量 值 不 为 null, 然 后 在 令 其 访 问 所 需 的 属 性 和 方 法, 那 么, NullPointerException 也 就 从 不 会 产 生 这 种 异 常 的 特 点 是 Java 编 译 器 不 会 检 查 它, 也 就 是 说 程 序, 程 序 中 可 能 出 现 这 类 异 常 时, 即 使 没 有 用 try-catch 语 句 捕 获 它, 也 没 有 用 throws 语 句 声 明 抛 出 它, 还 是 会 编 译 通 过 的 由 于 没 有 处 理 它, 当 出 现 这 类 异 常 时, 异 常 对 象 一 直 被 传 递 到 main() 方 法, 则 程 序 将 异 常 终 止 如 果 采 用 了 异 常 处 理, 异 常 将 会 被 相 应 的 程 序 执 行 处 理 除 了 RuntimeException 以 及 子 类, 其 他 的 Exception 及 其 子 类 都 是 受 检 查 异 常 这 种 异 常 的 特 点 是 Java 编 译 器 不 会 检 查 它, 也 就 是 说, 当 程 序 中 出 现 这 类 异 常 时, 要 么 用 try-catch 语 句 捕 获 它, 也 没 有 用 throws 语 句 声 明 抛 出 它, 否 则 编 译 不 会 通 过 这 些 异 常 的 产 生 不 是 因 为 程 序 员 的 过 错, 是 程 序 员 无 法 预 见 的 总 结 一 下,Java 程 序 异 常 处 理 的 原 则 为 : 的 ; (1) 对 于 Error 和 RuntimeException, 可 以 在 程 序 中 进 行 捕 获 和 处 理, 但 不 是 必 须 (2) 对 于 其 它 异 常, 必 须 在 程 序 中 进 行 捕 获 和 处 理 8.3.2 预 定 义 异 常 Java 编 程 语 言 中 预 先 定 义 好 的 异 常 叫 预 定 义 异 常, 上 面 提 到 的 异 常 都 是 预 定 义 异 常, 这 些 异 常 的 产 生 不 需 要 程 序 员 手 动 抛 出, 即 不 需 要 使 用 throw 语 句 抛 出 异 常, 当 产 生 异 常 时, 系 统 会 自 动 抛 出 下 面 是 几 种 常 见 的 异 常 : JDK 中 定 义 的 RuntimeException 子 类 名 称 描 述 ArithmeticException 算 术 错 误, 如 被 0 除 NullPointerException 非 法 使 用 空 引 用 ArrayIndexOutOfBoundsException 数 组 下 标 越 界 NegativeArraySizeException 创 建 带 负 维 数 大 小 的 数 组 的 尝 试 ClassCastException 非 法 强 制 转 换 类 型 ArrayStoreException 数 组 元 素 赋 值 类 型 不 兼 容 IllegalArgumentException 调 用 方 法 的 参 数 非 法 IllegalMonitorStateException 非 法 监 控 操 作, 如 等 待 一 个 未 锁 定 线 程 IllegalStateException 环 境 或 应 用 状 态 不 正 确 IllegalThreadStateException 请 求 操 作 与 当 前 线 程 状 态 不 兼 容 IndexOutOfBoundsException 某 些 类 型 索 引 越 界 NumberFormatException 字 符 串 到 数 字 格 式 非 法 转 换 第 195 页

SecurityException StringIndexOutOfBounds UnsupportedOperationException 试 图 违 反 安 全 性 试 图 在 字 符 串 边 界 之 外 索 引 遇 到 不 支 持 的 操 作 JDK 中 的 定 义 的 受 检 查 异 常 名 称 描 述 ClassNotFoundException 找 不 到 类 CloneNotSupportedException 试 图 克 隆 一 个 不 能 实 现 Cloneable 接 口 的 对 象 IllegalAccessException 对 一 个 类 的 访 问 被 拒 绝 InstantiationException 试 图 创 建 一 个 抽 象 类 或 者 抽 象 接 口 的 对 象 InterruptedException 一 个 线 程 被 另 一 个 线 程 中 断 NoSuchFieldException 请 求 的 字 段 不 存 在 NoSuchMethodException 请 求 的 方 法 不 存 在 8.3.3 自 定 义 异 常 Java 语 言 允 许 用 户 在 需 要 时 创 建 自 己 的 异 常 类 型, 用 于 表 述 JDK 中 未 涉 及 到 的 其 它 异 常 状 况, 这 些 类 型 也 必 须 继 承 Throwable 类 或 其 子 类 用 户 自 定 义 异 常 类 通 常 属 Exception 范 畴, 依 据 命 名 惯 例, 应 以 Exception 结 尾 用 户 自 定 义 异 常 未 被 加 入 JRE 的 控 制 逻 辑 中, 因 此 永 远 不 会 自 动 抛 出, 只 能 由 人 工 创 建 并 抛 出 Throwable 定 义 的 方 法 方 法 描 述 String getlocalizedmessage( ) 返 回 一 个 异 常 的 局 部 描 述 String getmessage( ) 返 回 一 个 异 常 的 描 述 void printstacktrace( ) 显 示 堆 栈 轨 迹 void printstacktrace(printstreamstream) 把 堆 栈 轨 迹 送 到 指 定 的 流 void printstacktrace(printwriterstream) 把 堆 栈 轨 迹 送 到 指 定 的 流 String tostring( ) 返 回 一 个 包 含 异 常 描 述 的 String 对 象 当 输 出 一 个 Throwable 对 象 时, 该 方 法 被 println( ) 调 用 看 一 个 用 户 自 定 义 异 常 的 例 子 : class MyException extends Exception { private int idnumber; public MyException(String message, int id) { super(message); this.idnumber = id; public int getid() { return idnumber; 第 196 页

public class Test { public void regist(int num) throws MyException { if (num < 0) { throw new MyException(" 人 数 为 负 值, 不 合 理 ", 3); System.out.println(" 登 记 人 数 " + num); public void manager() { try { regist(-100); catch (MyException e) { System.out.print(" 登 记 出 错, 类 别 :" + e.getid()); System.out.print(" 本 次 登 记 操 作 结 束 "); public static void main(string args[]) { Test t = new Test(); t.manager(); 第 197 页

8.4 学 习 目 标 1. 什 么 是 异 常? 2. 简 述 处 理 异 常 的 两 种 方 式? 3. 简 述 try 块 的 功 能 和 规 则 4. 简 述 catch 块 的 功 能 和 规 则 5. 简 述 finally 块 的 功 能 和 规 则 6. 简 述 throw 和 throws 的 功 能 和 使 用 方 法 7. 理 解 什 么 时 候 用 抓, 什 么 时 候 用 抛 8. 异 常 的 分 类? 9. 什 么 是 受 检 查 异 常, 描 述 其 特 点 10. 什 么 是 运 行 时 异 常, 描 述 其 特 点 11. 什 么 是 预 定 义 异 常 12. 简 述 自 定 义 异 常 的 规 则 第 198 页

9 集 合 框 架 9.1 基 本 概 念 9.1.1 数 学 背 景 在 常 见 用 法 中, 集 合 (Collection) 和 数 学 上 直 观 的 集 (set) 的 概 念 是 相 同 的 集 是 一 个 唯 一 项 组, 也 就 是 说 组 中 没 有 重 复 项 实 际 上, 集 合 框 架 包 含 了 一 个 Set 接 口 和 许 多 具 体 的 Set 类 但 正 式 的 集 概 念 却 比 Java 技 术 提 前 了 一 个 世 纪, 那 时 英 国 数 学 家 George Boole 按 逻 辑 正 式 的 定 义 了 集 的 概 念 大 部 分 人 在 小 学 时 通 过 我 们 熟 悉 的 维 恩 图 引 入 的 集 的 交 和 集 的 并 学 到 过 一 些 集 的 理 论 映 射 是 一 种 特 别 的 集 它 是 一 种 对 (pair) 集, 每 个 对 表 示 一 个 元 素 到 另 一 元 素 的 单 向 映 射 一 些 映 射 示 例 有 : 字 典 ( 词 到 含 义 的 映 射 ) 关 键 字 到 数 据 库 记 录 的 映 射 IP 地 址 到 域 名 (DNS) 的 映 射 2 进 制 到 10 进 制 转 换 的 映 射 9.1.2 什 么 是 集 合 集 合 是 包 含 多 个 对 象 的 简 单 对 象, 所 包 含 的 对 象 称 为 元 素 集 合 的 典 型 应 用 是 用 来 处 理 多 种 第 199 页

类 型 的 对 象, 这 些 类 型 必 须 有 共 同 的 父 类 集 合 框 架 由 一 组 用 来 操 作 对 象 的 接 口 组 成 不 同 接 口 描 述 不 同 类 型 的 组 在 很 大 程 度 上, 一 旦 你 理 解 了 接 口, 就 理 解 了 框 架 虽 然 总 要 创 建 接 口 特 定 的 实 现, 但 访 问 实 际 集 合 的 方 法 应 该 限 制 在 接 口 方 法 的 使 用 上 ; 因 此, 允 许 更 改 基 本 的 数 据 结 构 而 不 必 改 变 其 它 代 码 框 架 接 口 层 次 结 构 如 下 图 所 示 Collection Map Set List HashSet TreeSet ArrayList LinkedList HashMap TreeMap 从 上 图 中, 我 们 可 以 看 出, 集 合 主 要 分 为 3 中 类 型 : 7 5 6 3 4 1 2 0 3 k3 v3 1 2 2 6 k2 v2 3 2 k1 v1 Set( 集 ) List( 列 表 ) Map( 映 射 ) Set( 集 ) 中 的 对 象 不 允 许 重 复, 无 序 List( 列 表 ) 中 的 对 象 允 许 重 复, 有 序 允 许 按 照 对 象 在 集 合 中 的 索 引 位 置 检 索 对 象 List 与 数 组 有 些 相 似 Map( 映 射 ) 集 合 中 的 每 一 个 元 素 包 含 一 对 键 对 象 和 值 对 象, 集 合 中 没 有 重 复 的 键 对 象, 值 对 象 可 以 重 复 第 200 页

9.2 Collection 接 口 和 Iterator 接 口 在 Collection 接 口 中 声 明 了 适 用 于 Java 集 合 ( 只 包 含 Set 和 List) 的 通 用 方 法 : 方 法 描 述 boolean add(object o) 向 集 合 中 添 加 一 个 对 象 的 引 用 void clear() 删 除 集 合 中 所 有 的 对 象, 即 不 再 持 有 这 些 对 象 的 引 用 boolean contains(object o) 判 断 在 集 合 中 是 否 持 有 特 定 对 象 的 引 用 boolean isempty() 判 断 集 合 是 否 为 空 Iterator iterator() 返 回 一 个 Iterator 对 象, 可 用 它 来 遍 历 集 合 中 的 元 素 Boolean remove(object o) 从 集 合 中 删 除 一 个 对 象 的 引 用 int size() 返 回 集 合 中 元 素 的 数 目 Object[] toarray() 返 回 一 个 数 组, 该 数 组 包 含 集 合 中 所 有 的 元 素 Set 接 口 和 List 接 口 都 继 承 了 Collection 接 口, 而 Map 接 口 没 有 集 成 Collection 接 口, 因 此 可 以 对 Set 对 象 和 List 对 象 调 用 以 上 方 法, 但 是 不 能 对 Map 对 象 调 用 以 上 方 法 Collection 接 口 的 iterator() 和 toarray() 方 法 都 用 于 获 得 集 合 中 的 所 有 对 象, iterator() 方 法 返 回 一 个 Iterator 对 象,toArray() 方 法 返 回 一 个 包 含 集 合 中 所 有 元 素 的 数 组 Iterator 接 口 隐 藏 底 层 集 合 的 数 据 结 构, 向 客 户 程 序 提 供 了 遍 历 各 种 类 型 的 集 合 的 统 一 接 口 Iterator 接 口 中 声 明 了 如 下 方 法 : 方 法 描 述 boolean hasnext() 判 断 集 合 中 的 元 素 是 否 遍 历 完 毕, 如 果 没 有, 就 返 回 true Object next() 返 回 下 一 个 元 素 void remove() 从 集 合 中 删 除 上 一 个 由 next() 方 法 返 回 的 元 素 Collection 接 口 还 支 持 元 素 组 的 操 作 : 方 法 描 述 boolean containsall (Collection collection) 判 断 集 合 中 是 否 包 含 了 另 一 个 集 合 的 所 有 元 素, 即 另 一 个 集 合 是 否 是 当 前 集 合 的 子 集, 如 果 是, 就 返 回 true boolean addall (Collection collection) 将 另 一 个 集 合 中 的 所 有 元 素 都 添 加 到 当 前 的 集 合 中, 通 常 称 为 并 void removeall 类 似 于 clear(), 移 除 此 集 合 中 那 些 包 含 在 指 定 (Collection collection) collection 中 的 所 有 元 素 boolean retainall (Collection collection) 仅 保 留 此 集 合 中 那 些 也 包 含 在 指 定 collection 的 元 素, 即 交 集 第 201 页

9.3 Set( 集 ) Set 是 最 简 单 的 一 种 集 合, 集 合 中 的 对 象 不 按 特 定 的 方 式 排 序, 它 不 允 许 集 合 中 存 在 重 复 项 Set 接 口 主 要 有 两 个 实 现 类 :HashSet 和 TreeSet HashSet 按 照 哈 希 算 法 来 存 取 集 合 中 的 对 象, 存 取 速 度 比 较 快 Hash 类 还 有 一 个 子 类 LinkedHashSet 类, 它 不 仅 实 现 了 Hash 算 法, 而 且 实 现 了 链 表 数 据 结 构, 链 表 数 据 结 构 能 提 高 插 入 和 删 除 元 素 的 性 能 TreeSet 类 实 现 了 SortedSet 接 口, 具 有 排 序 功 能 9.3.1 Set 的 一 般 用 法 Set 集 合 中 存 放 的 是 对 象 的 引 用, 并 且 没 有 重 复 对 象 以 下 代 码 创 建 了 3 个 引 用 变 量 :s1 s2 s3 s2 和 s3 变 量 引 用 同 一 个 字 符 串 对 象 world, s1 变 量 引 用 另 一 个 字 符 串 对 象 hello,set 集 合 依 次 把 这 3 个 引 用 变 量 加 入 到 集 合 中 Set<String> set=new HashSet<String>(); String s1=new String("hello"); String s2=new String("world"); String s3=s2; set.add(s1); set.add(s2); set.add(s3); System.out.println(set.size());// 打 印 集 合 中 对 象 的 数 目 2 以 上 程 序 的 打 印 结 果 为 2, 实 际 上 只 向 Set 集 合 加 入 了 两 个 对 象, 引 用 变 量 set HashSet 对 象 hello 引 用 变 量 s1 world 引 用 变 量 s2 引 用 变 量 s3 当 一 个 新 对 象 加 入 到 Set 集 合 中 时,Set 采 用 对 象 的 equals() 方 法 比 较 两 个 对 象 是 否 相 等, 而 不 是 采 用 == 比 较 运 算 符 所 以 实 际 上 只 向 集 合 中 加 入 了 一 个 对 象 9.3.2 HashSet 类 HashSet 类 按 照 哈 希 算 法 来 存 取 集 合 中 的 对 象, 具 有 很 好 的 存 取 和 查 找 性 能 当 向 集 合 中 加 入 一 个 对 象 时,HashSet 会 调 用 对 象 的 hashcode() 方 法 来 获 得 哈 希 码, 然 后 根 据 这 个 哈 希 码 进 一 步 计 算 出 对 象 在 集 合 中 的 存 放 位 置 在 object 类 中 定 义 了 hashcode() 和 equals() 方 法,Object 类 的 equals() 方 法 按 照 内 存 地 址 比 较 对 象 是 否 相 等, 因 此 如 果 object1.equals(object2) 为 true, 则 表 明 object1 和 object2 变 量 实 际 上 引 用 同 一 个 对 象, 那 么 两 个 对 象 的 哈 希 码 也 肯 定 相 等 第 202 页

如 果 用 户 定 义 的 Customer 类 覆 盖 了 Object 类 的 equals() 方 法, 但 是 没 有 覆 盖 Object 类 的 hashcode() 方 法, 就 会 导 致 customer1.equals(customer2) 为 true 时, 而 customer1 和 customer2 的 哈 希 码 不 一 定 一 样, 这 会 使 HashSet 无 法 正 常 工 作 class Customer{ private String name; private int age; // 省 略 set get 方 法 public Customer(String name,int age){ this.name=name; this.age=age; public boolean equals(object obj) { if (this == obj) { return true; if (obj == null) { return false; if (obj instanceof Customer) { Customer customer = (Customer) obj; if (this.name.equals(customer.getname()) && this.age==customer.getage()) { return true; else { return false; else { return false; 以 下 程 序 向 HashSet 中 加 入 两 个 Customer 对 象 Set<Customer> set=new HashSet<Customer>(); Customer customer1=new Customer("Tom",25); Customer customer2=new Customer("Tom",25); set.add(customer1); set.add(customer2); System.out.println(set.size()); 由 于 customer1.equals(customer2) 的 比 较 结 果 为 true, 按 理 说 HashSet 只 应 该 把 customer1 加 入 集 合 中, 但 实 际 上 以 上 程 序 的 打 印 结 果 为 2, 表 明 集 合 中 加 入 了 两 个 对 象 出 现 这 一 非 正 常 现 象 在 于,customer1 和 customer2 的 哈 希 码 不 一 样, 因 此 HashSet 为 customer1 和 customer2 计 算 出 不 同 的 存 放 位 置, 于 是 把 它 们 存 放 在 集 合 中 的 不 同 地 方 为 了 保 证 HashSet 正 常 工 作, 如 果 Customer 类 覆 盖 了 equals() 方 法, 也 应 该 覆 盖 hashcode() 方 法, 并 且 保 证 两 个 相 等 的 Customer 对 象 的 哈 希 码 也 一 样 Customer 类 的 hashcode() 方 法 代 码 如 下 : 第 203 页

public int hashcode(){ int result; result=(name==null?0:name.hashcode()); result=29*result+age; return result; 判 断 name 是 否 为 null 是 为 了 保 证 程 序 代 码 的 健 壮 性 9.3.3 TreeSet 类 TreeSet 类 实 现 了 SortedSet 接 口, 能 够 对 集 合 中 的 对 象 进 行 排 序 以 下 程 序 创 建 了 一 个 TreeSet 对 象, 然 后 向 集 合 中 加 入 4 个 Integer 对 象 Set<Integer> set = new TreeSet<Integer>(); set.add(new Integer(3)); set.add(new Integer(1)); set.add(new Integer(4)); set.add(new Integer(2)); Iterator<Integer> it=set.iterator(); while(it.hasnext()){ System.out.print(it.next()+" "); 以 上 程 序 的 打 印 结 果 为 : 1 2 3 4 当 treeset 向 集 合 中 加 入 一 个 对 象 时, 会 把 它 插 入 到 有 序 的 对 象 序 列 中 那 么 TressSet 是 如 何 对 对 象 进 行 排 序 的 呢?TreeSet 支 持 两 种 排 序 方 式 : 自 然 排 序 和 客 户 化 排 序 在 默 认 情 况 下 TreeSet 采 用 自 然 排 序 方 式 9.3.3.1 自 然 排 序 在 JDK 类 库 中, 有 一 部 分 类 实 现 Comparable 接 口, 如 Integer Double 和 String 等 Comparable 接 口 有 一 个 compareto(object o) 方 法, 它 返 回 整 数 类 型 对 于 表 达 式 x.compareto(y), 如 果 返 回 值 为 0, 则 表 示 x 和 y 相 等, 如 果 返 回 值 大 于 0, 则 表 示 x 大 于 y, 如 果 返 回 值 小 于 0, 则 表 示 x 小 于 y TreeSet 调 用 对 象 的 compareto() 方 法 比 较 集 合 中 对 象 的 大 小, 然 后 进 行 升 序 排 列, 这 种 排 序 方 式 称 为 自 然 排 序 下 表 中 显 示 了 JDK 类 库 中 实 现 了 Comparable 接 口 的 一 些 类 的 排 序 方 式 类 BigDecimal BigInteger Byte Float Integer Long Short Character 按 数 字 大 小 排 序 排 序 按 字 符 的 Unicode 值 的 数 字 大 小 排 序 第 204 页

String 按 字 符 串 中 字 符 的 Unicode 值 排 序 使 用 自 然 排 序 时, 只 能 向 TreeSet 集 合 中 加 入 同 类 型 的 对 象, 并 且 这 些 对 象 的 类 必 须 实 现 Comparable 接 口 以 下 程 序 先 后 向 TreeSet 集 合 中 加 入 了 一 个 Integer 对 象 和 String 对 象 Set<Object> set = new TreeSet<Object>(); set.add(new Integer(3)); set.add(new String("1"));// 运 行 时 抛 出 ClassCastException 当 第 二 次 调 用 TreeSet 的 add() 方 法 时 抛 出 ClassCastException Exception in thread "main" java.lang.classcastexception: java.lang.integer cannot be cast to java.lang.string at java.lang.string.compareto(string.java:92) at java.util.treemap.put(treemap.java:545) at java.util.treeset.add(treeset.java:238) at Client.main(Client.java:17) 在 string 类 的 compareto(object o) 方 法 中, 首 先 对 参 数 o 进 行 类 型 转 换 String s=(string)o; 如 果 参 数 o 实 际 引 用 的 不 是 String 类 型 的 对 象, 以 上 代 码 就 会 抛 出 ClassCastException 下 面 的 示 例 中 向 TreeSet 集 合 加 入 了 3 个 Customer 对 象, 但 是 Customer 类 没 有 实 现 Comparable 接 口 Set<Customer> set = new TreeSet<Customer>(); set.add(new Customer("Tom",25)); set.add(new Customer("Tom",24)); set.add(new Customer("Jim",25)); 当 第 二 次 调 用 TreeSet 的 add() 方 法 时, 也 会 抛 出 ClassCastException 异 常 如 果 希 望 避 免 这 种 异 常, 应 该 使 Customer 类 实 现 Comparable 接 口 class Customer implements Comparable{ private String name; private int age; // 省 略 set get 方 法 public Customer(String name, int age) { this.name = name; this.age = age; public int compareto(object o){ Customer other=(customer)o; // 先 按 照 name 属 性 排 序 if(this.name.compareto(other.getname())>0){ return 1; 第 205 页

else if(this.name.compareto(other.getname())<0){ return -1; // 再 按 照 age 属 性 排 序 if(this.age>other.getage()){ return 1; else if(this.age<other.getage()){ return -1; return 0; public boolean equals(object obj) { if (this == obj) { return true; if (obj == null) { return false; if (obj instanceof Customer) { Customer customer = (Customer) obj; if (this.name.equals(customer.getname()) && this.age == customer.getage()) { return true; else { return false; else { return false; public int hashcode(){ int result; result=(name==null?0:name.hashcode()); result=29*result+age; return result; 为 了 保 证 TreeSet 能 正 确 排 序, 要 求 Customer 类 的 compareto() 方 法 与 equals 方 法 按 相 同 的 规 则 比 较 两 个 Customer 对 象 是 否 相 等 也 就 是 说, 如 果 customer1.equals(customer2) 为 true, 那 么 customer1.compareto(customer2) 为 0 测 试 代 码 如 下 : Set<Customer> set = new TreeSet<Customer>(); set.add(new Customer("Tom",25)); set.add(new Customer("Tom",24)); 第 206 页

set.add(new Customer("Jim",25)); Iterator<Customer> it=set.iterator(); while(it.hasnext()){ Customer customer=it.next(); System.out.println(customer.getName()+" "+customer.getage()); 打 印 结 果 为 : Jim 25 Tom 24 Tom 25 9.3.3.2 客 户 化 排 序 除 了 自 然 排 序,TreeSet 还 支 持 客 户 化 排 序 使 用 Java.util.Comparator<Type> 接 口 提 供 具 体 的 排 序 方 式,<Type> 指 定 被 比 较 的 对 象 的 类 型,Comparator 有 个 compare(type x,type y) 方 法, 用 于 比 较 两 个 对 象 的 大 小 当 compare(x,y) 的 返 回 值 大 于 0 时, 表 示 x 大 于 y; 当 compare(x,y) 的 返 回 值 小 于 0 时, 表 示 x 小 于 y; 当 compare(x,y) 的 返 回 值 等 于 0 时, 表 示 x 等 于 y 如 果 希 望 TreeSet 按 照 Customer 对 象 的 name 属 性 进 行 降 序 排 列, 可 以 先 创 建 一 个 实 现 Comparator 接 口 的 类 CustomerComparator import java.util.comparator; import java.util.iterator; import java.util.set; import java.util.treeset; public class CustomerComparator implements Comparator<Customer>{ public int compare(customer c1, Customer c2) { if(c1.getname().compareto(c2.getname())>0){ return -1; else if(c1.getname().compareto(c2.getname())<0){ return 1; return 0; public static void main(string[] args){ Set<Customer> set = new TreeSet<Customer>(new CustomerComparator()); set.add(new Customer("Tom",25)); set.add(new Customer("Tom",24)); set.add(new Customer("Jim",25)); Iterator<Customer> it=set.iterator(); while(it.hasnext()){ Customer customer=it.next(); System.out.println(customer.getName()+" "+customer.getage()); 第 207 页

当 treeset 向 集 合 中 加 入 Customer 对 象 时, 会 调 用 CustomerComparator 类 的 compare() 方 法 进 行 排 序 以 上 TreeSet 按 照 Customer 对 象 的 name 属 性 进 行 降 序 排 列, 最 后 打 印 结 果 为 : Tom 25 Jim 25 因 为 compare() 方 法 使 用 Customer 对 象 的 name 属 性 进 行 比 较,set 集 合 只 保 存 了 第 一 个 Tom 9.4 List( 列 表 ) List 的 主 要 特 征 是 其 元 素 以 线 性 方 式 存 储, 集 合 中 允 许 存 放 重 复 对 象 list 接 口 主 要 的 实 现 类 包 括 : ArrayList--ArrayList 代 表 长 度 可 变 的 数 组 允 许 对 元 素 进 行 快 速 的 随 机 访 问, 但 是 向 ArrayList 中 插 入 与 删 除 元 素 的 速 度 较 慢 LinkedList 在 实 现 中 采 用 链 表 数 据 结 构 对 顺 序 访 问 进 行 优 化, 向 List 中 插 入 和 删 除 元 素 的 速 度 较 快, 随 机 访 问 速 度 则 相 对 较 慢 随 机 访 问 是 指 检 索 位 于 特 定 索 引 位 置 的 元 素 LinkedList 单 独 具 有 addfirst() addlast() getfirst() getlast() removefirst() 和 removelast() 方 法, 这 些 方 法 使 得 LinkedList 可 以 作 为 堆 栈 队 列 和 双 向 队 列 来 使 用 9.4.1 访 问 列 表 的 元 素 List 中 的 对 象 按 照 索 引 位 置 排 序, 客 户 程 序 可 以 按 照 对 象 在 集 合 中 的 索 引 位 置 来 检 索 对 象 以 下 程 序 向 List 中 加 入 4 个 Integer 对 象 List<Integer> list = new ArrayList<Integer>(); list.add(new Integer(3)); list.add(new Integer(2)); list.add(new Integer(1)); list.add(new Integer(2)); List 的 get(int index) 方 法 返 回 集 合 中 由 参 数 index 指 定 的 索 引 位 置 的 对 象, 第 一 个 加 入 到 集 合 中 的 对 象 的 索 引 位 置 为 0, 依 次 类 推 以 下 程 序 依 次 检 索 出 集 合 中 的 所 有 对 象 for(int i=0;i<list.size();i++){ System.out.print(list.get(i)+" "); 以 上 程 序 的 打 印 结 果 为 : 3 2 1 2 List 的 iterator() 方 法 和 Set 的 iterator() 方 法 一 样, 也 能 返 回 Iterator 对 象, 可 第 208 页

以 用 Iterator 来 遍 历 集 合 中 的 所 有 对 象, 例 如 : Iterator<Integer> it=list.iterator(); while(it.hasnext()){ System.out.print(it.next()); 9.4.2 为 列 表 排 序 List 只 能 对 集 合 中 的 对 象 按 索 引 位 置 排 序, 如 果 希 望 对 List 中 的 对 象 按 其 他 特 定 的 方 式 排 序, 可 以 借 助 Comparator 接 口 和 Collections 类 Collections 类 是 Java 集 合 类 库 中 的 辅 助 类, 它 提 供 了 操 作 集 合 的 各 种 静 态 方 法, 其 中 sort() 方 法 用 于 对 List 中 的 对 象 进 行 排 序 sort(list list): 对 List 中 的 对 象 进 行 自 然 排 序 sort(list list,comparator comparator): 对 List 中 的 对 象 进 行 客 户 化 排 序, comparator 参 数 指 定 排 序 方 式 以 下 程 序 对 List 中 的 Integer 对 象 进 行 自 然 排 序 List<Integer> list = new ArrayList<Integer>(); list.add(new Integer(3)); list.add(new Integer(2)); list.add(new Integer(1)); list.add(new Integer(2)); Collections.sort(list); for(int i=0;i<list.size();i++){ System.out.print(list.get(i)+" "); 以 上 程 序 的 打 印 结 果 为 : 1 2 2 3 9.4.3 ListIterator 接 口 List 的 listiterator() 方 法 返 回 一 个 ListIterator 对 象,ListIterator 接 口 继 承 了 Iterator 接 口, 此 外 还 提 供 了 专 门 操 作 列 表 的 方 法 add(): 向 列 表 中 插 入 一 个 元 素 hasnext(): 判 断 列 表 中 是 否 还 有 下 一 个 元 素 HasPrevious(): 判 断 列 表 中 是 否 还 有 上 一 个 元 素 第 209 页

next(): 返 回 列 表 中 的 下 一 个 元 素 previous(): 返 回 列 表 中 的 上 一 个 元 素 下 面 示 例 中 的 insert() 方 法 向 一 个 排 序 的 List 列 表 中 按 顺 序 插 入 数 据 class ListInserter { // 向 List 列 表 中 按 顺 序 插 入 元 素 public static void insert(list<integer> list,int data) { ListIterator<Integer> it=list.listiterator(); while(it.hasnext()){ Integer in=it.next(); if(data<=in.intvalue()){ // 指 针 向 前 移 动 it.previous(); // 插 入 元 素 it.add(new Integer(data)); break; public static void main(string[] args){ // 创 建 一 个 链 接 列 表 List<Integer> list = new ArrayList<Integer>(); list.add(new Integer(3)); list.add(new Integer(5)); list.add(new Integer(1)); list.add(new Integer(2)); // 为 列 表 排 序 Collections.sort(list); // 向 列 表 中 插 入 一 个 元 素 insert(list,4); System.out.print(Arrays.toString(list.toArray())); 以 上 程 序 的 打 印 结 果 如 下 : [1, 2, 3, 4, 5] 9.4.4 获 得 固 定 长 度 的 List 对 象 Java.util.Arrays 类 的 aslist() 方 法 能 够 把 一 个 Java 数 据 包 装 成 一 个 List 对 象, 这 个 List 对 象 代 表 固 定 长 度 的 数 组 所 有 对 List 对 象 的 操 作 都 会 被 作 用 到 底 层 的 Java 数 组 由 于 数 组 的 长 度 不 能 改 变, 因 此 不 能 调 用 这 种 List 对 象 的 add() 和 remove() 方 法, 否 则 就 会 抛 出 java.lang.unsupportedoperationexception 运 行 时 异 常 String[] arr={"smith","tom","jack"; 第 210 页

List<String> list=arrays.aslist(arr); list.set(1, "jane"); // 合 法, 可 以 修 改 某 个 位 置 的 元 素 System.out.println(Arrays.toString(arr)); // 打 印 [Smith, jane, Jack] list.remove("tom");// 非 法, 抛 出 UnsupportedOperationException list.add("mary");// 非 法, 抛 出 UnsupportedOperationException 9.4.5 比 较 Java 数 组 和 各 种 List 的 性 能 List 的 两 个 实 现 类 ArrayList 和 LinkedList 都 表 示 列 表, 在 JDK1.0 版 本 中 有 一 个 Vector 类, 也 表 示 列 表, 在 JDK1.2 版 本 中 把 Vector 类 改 为 实 现 了 List 接 口 分 别 对 Java 数 组 ArrayList LinkedList Vector 进 行 测 试, 测 试 的 数 据 量 是 10 万 条 数 据, 次 数 是 10 万 次 测 试 结 果 如 下 ( 单 位 : 毫 秒 ): 类 型 Java 数 组 ArrayList LinkedList Vector 随 机 访 问 操 作 (get) 10 16 56453 16 迭 代 操 作 (iterator) 0 0 47 16 插 入 操 作 (insert) 不 适 用 13281 232109 13297 删 除 操 作 (remove) 不 适 用 95031 167390 87687 总 结 如 下 :ArrayList 的 效 率 相 对 平 衡, 对 LinkedList 进 行 操 作, 因 为 要 先 进 行 顺 序 查 找, 所 以 效 率 较 低,Vector 类 在 各 方 面 的 性 能 也 不 是 太 差, 属 于 历 史 集 合 类, 已 经 不 提 倡 使 用 它 9.5 Map( 映 射 ) Map( 映 射 ) 是 一 种 把 键 对 象 和 值 对 象 进 行 映 射 的 集 合, 它 的 每 一 个 元 素 都 包 含 一 对 键 对 象 和 值 对 象, 而 值 对 象 仍 可 以 是 Map 类 型, 以 此 类 推, 这 样 就 形 成 了 多 级 映 射 向 Map 集 合 中 加 入 元 素 时, 必 须 提 供 一 对 键 对 象 和 值 对 象, 从 Map 集 合 中 检 索 元 素 时, 只 要 给 出 键 对 象, 就 会 返 回 对 应 的 值 对 象 以 下 程 序 通 过 Map 的 put(object key,object value) 方 法 向 集 合 中 加 入 元 素, 通 过 Map 的 get(obejct key) 方 法 来 检 索 与 键 对 象 对 应 的 值 对 象 Map<String,String> map=new HashMap<String,String>(); map.put("1", "Monday"); map.put("2", "Tuesday"); map.put("3", "Wendsday"); map.put("4", "Thursday"); String day=map.get("2");//day 的 值 为 "Tuesday" Map 集 合 中 的 键 对 象 不 允 许 重 复, 也 就 是 说 任 意 两 个 键 对 象 通 过 equals() 方 法 比 较 的 结 果 都 是 false 对 于 值 对 象 则 没 有 唯 一 性 的 要 求, 可 以 将 任 意 多 个 键 对 象 映 射 到 一 个 值 对 象 上 例 如 以 下 Map 集 合 中 的 键 对 象 1 和 one 都 和 同 一 个 值 对 象 Monday 对 应 Map<String,String> map=new HashMap<String,String>(); map.put("1", "Mon"); map.put("1", "Monday"); map.put("one", "Monday"); 第 211 页

Set<String> set=map.keyset(); Iterator<String> it=set.iterator(); while(it.hasnext()){ String key=it.next(); String value=map.get(key); System.out.println("key="+key+",value="+value); 由 于 第 一 次 和 第 二 次 加 入 Map 中 的 键 对 象 都 为 1, 因 此 第 一 次 加 入 的 值 对 象 将 被 覆 盖, Map 集 合 中 最 后 只 有 两 个 元 素, 分 别 为 : 1--->Monday one--->monday Map 的 keyset() 方 法 返 回 集 合 中 所 有 键 对 象 的 集 合 Map 有 两 种 比 较 常 用 的 实 现 :HashMap 和 TreeMap HashMap 按 照 哈 希 算 法 来 存 取 键 对 象, 有 很 好 的 存 取 性 能, 为 了 保 证 HashMap 能 正 常 工 作, 和 HashSet 一 样, 要 求 当 两 个 键 对 象 通 过 equals() 方 法 比 较 为 true 时, 这 两 个 键 对 象 的 hashcode() 方 法 返 回 的 哈 希 码 也 一 样 TreeMap 实 现 了 SortedMap 接 口, 能 对 键 对 象 进 行 排 序 和 TreeSet 一 样,TreeMap 也 支 持 自 然 排 序 和 客 户 化 排 序 两 种 方 式 以 下 程 序 中 TreeMap 会 对 4 个 String 类 型 的 键 对 象 进 行 自 然 排 序 Map<String,String> map=new TreeMap<String,String>(); map.put("3", "Wendsday"); map.put("1", "Monday"); map.put("4", "Thursday"); map.put("2", "Tuesday"); Set<String> set=map.keyset(); Iterator<String> it=set.iterator(); while(it.hasnext()){ String key=it.next(); String value=map.get(key); System.out.println("key="+key+",value="+value); 以 上 程 序 的 打 印 结 果 为 : key=1,value=monday key=2,value=tuesday key=3,value=wendsday key=4,value=thursday 如 果 希 望 TreeMap 对 键 对 象 进 行 客 户 化 排 序, 可 调 用 它 的 另 一 个 构 造 方 法 ---TreeMap(Comparator comparator), 参 数 comparator 指 定 具 体 的 排 序 方 式 第 212 页

9.6 历 史 集 合 类 Collection Set List HashSet TreeSet ArrayList LinkedList Vector Map HashMap TreeMap Propertie HashTable 在 早 期 的 JDK1.0 版 本 中, 代 表 集 合 的 类 只 有 Vector Stack Enumeration Hashtable Properties 和 BitSet 从 JDK1.2 版 本 开 始, 才 出 现 了 Collection Set List 和 Map 接 口 及 各 种 实 现 类, 它 们 构 成 了 完 整 的 Java 集 合 框 架 JDK1.0 版 本 中 的 集 合 类 也 称 为 历 史 集 合 类 s 历 史 集 合 类 描 述 缺 点 替 代 类 Vector 集 合 中 的 元 素 有 索 引 位 置, 在 新 的 集 合 框 架 中 把 它 改 为 实 现 了 List 接 口 采 用 了 同 步 机 制, 影 响 操 纵 集 合 的 性 能 ArrayList LinkedList Stack 表 示 堆 栈, 支 持 后 进 先 出 的 操 采 用 了 同 步 机 制, 影 响 操 作 集 LinkedList 作 合 的 性 能 ;Stack 继 承 了 Vector 类, 使 得 Stack 不 能 作 为 严 格 的 堆 栈, 还 允 许 随 机 访 问 Hashtable 集 合 中 的 每 个 元 素 包 含 一 对 键 采 用 了 同 步 机 制, 影 响 操 作 集 HashMap 与 值 在 新 的 集 合 框 架 中 把 它 改 为 实 现 了 Map 接 口 合 的 性 能 Properties 集 合 中 的 每 个 元 素 包 含 一 对 键 采 用 了 同 步 机 制, 影 响 操 作 集 无 第 213 页

Enumeratio n BitSet 与 值, 继 承 了 Hashtable 合 的 性 能 用 于 遍 历 集 合 中 的 元 素 只 能 与 Vector 和 Hashtable 等 历 史 集 合 配 套 使 用 ;Enumeration 类 的 名 字 较 长,Iterator 类 的 名 字 简 短 存 放 一 组 boolean 类 型 无 数 据, 支 持 与 或 和 异 或 操 作 Iterator 无 9.7 数 据 结 构 ( 可 选 ) 9.7.1 线 性 表 线 性 表 (List) 是 由 叫 作 元 素 (Element) 的 数 据 项 组 成 的 一 种 有 限 并 且 有 序 的 序 列 有 序 是 指 线 性 表 中 的 每 一 个 元 素 都 有 自 己 的 位 置 (index) 线 性 表 中 的 元 素 有 相 同 的 类 型 ; 线 性 表 中 不 包 含 任 何 元 素 时, 我 们 称 之 为 空 表 (empty List); 当 前 实 际 存 储 的 元 素 数 据 的 个 数 叫 做 线 性 表 的 长 度 (length); 线 性 表 的 开 始 节 点 ( 第 一 个 元 素 ) 叫 作 表 头 (head); 线 性 表 的 结 尾 节 点 ( 最 后 一 个 元 素 ) 叫 作 表 尾 (tail); 如 果 线 性 表 的 元 素 按 照 值 的 递 增 顺 序 排 列, 我 们 称 之 为 有 序 线 性 表 (sorted list); 如 果 线 性 表 的 元 素 与 位 置 没 有 关 系, 我 们 称 之 为 无 序 线 性 表 (unsorted list); 线 性 表 的 表 示 :(a 0,a 1,a 2,,a n-1 ) 线 性 表 的 操 作 public interface List { //remove all Objects from list public void clear(); //insert Object at current position public void insert(object item); //insert Object at tail of list public void append(object item); 第 214 页

//remove/return current Object public Object remove(); //set current to first position public void setfirst(); //move current to next position public void next(); //move current to prev position public void prev(); //return current length of list public int length(); //set current to specified pos public void setpost(int pos); //set current Object's value public void setvalue(object val); //return value of current Object public Object currvalue(); //return true if list is empty public boolean isempty(); //return true if current is within list public boolean isinlist(); //print all of list's elements public void print(); 线 性 表 有 两 种 标 准 的 实 现 方 法 : 顺 序 表 (array-based list) 和 链 表 (linked list) 9.7.1.1 顺 序 表 顺 序 表 的 实 现 是 用 数 组 来 存 储 表 中 的 元 素, 这 就 意 味 着 将 要 分 配 固 定 长 度 的 数 组 因 此 当 线 性 表 生 成 时 数 组 的 长 度 必 须 是 已 知 的 既 然 每 个 线 性 表 可 以 有 一 个 不 等 长 的 数 组, 那 么 这 个 长 度 就 必 须 由 线 性 表 对 象 来 记 录 在 任 何 给 定 的 时 刻, 线 性 表 都 有 一 定 数 目 的 元 素, 这 个 数 目 应 该 小 于 数 组 允 许 的 最 大 值 线 性 表 中 当 前 的 实 际 元 素 数 目 也 必 须 在 线 性 表 中 记 录 顺 序 表 把 表 中 的 元 素 存 储 在 数 组 中 相 邻 的 位 置 上 数 组 的 位 置 与 元 素 的 位 置 相 对 应 换 句 话 说, 就 是 表 中 第 i 个 元 素 存 储 在 数 组 的 第 i 个 单 元 中 表 头 总 是 在 第 0 个 位 置, 这 就 使 得 对 表 中 任 意 一 个 元 素 的 随 机 访 问 相 当 容 易 给 出 表 中 的 某 一 个 位 置, 这 个 位 置 对 应 元 素 的 值 就 可 以 直 接 获 取 第 215 页

如 果 在 表 尾 进 行 插 入 和 删 除 操 作 很 方 便 ; 如 果 在 表 中 插 入 一 个 元 素, 就 要 将 此 元 素 之 后 的 所 有 元 素 向 后 移 动 一 个 位 置 ; 如 果 在 表 中 删 除 一 个 元 素, 就 要 将 此 元 素 之 后 的 所 有 元 素 向 前 移 动 一 个 位 置 public class ArrayList implements List { // default array size private static final int defaultsize = 10; // max size of list private int maxsize; // actual number of Objects in list private int length; // position of current Object private int curr; // Array holding list Objects private Object[] listarray; /** * Constructor use default size */ public ArrayList() { setup(defaultsize); /** * Constructor use specified size */ public ArrayList(int size) { setup(size); private void setup(int size) { maxsize = size; length = curr = 0; listarray = new Object[size]; //remove all Objects from list public void clear(){ length = curr = 0; //insert Object at current position public void insert(object item){ if (isfull()){ throw new RuntimeException(" 顺 序 表 达 到 最 大 容 量 "); for(int i=length;i>curr;i--){ 第 216 页

listarray[i]=listarray[i-1]; listarray[curr]=item; length++; //insert Object at tail of list public void append(object item){ if (isfull()){ throw new RuntimeException(" 顺 序 表 达 到 最 大 容 量 "); listarray[length] = item; length++; //remove/return current Object public Object remove(){ if (isempty()){ throw new RuntimeException(" 顺 序 表 为 空, 无 法 再 删 除 了 "); Object o=listarray[curr]; for(int i=curr;i<length-1;i++){ listarray[i]=listarray[i+1]; length--; return o; //set current to first position public void setfirst(){ curr=0; //move current to next position public void next(){ curr++; //move current to prev position public void prev(){ curr--; //return current length of list public int length(){ return length; //set current to specified post 第 217 页

public void setpost(int pos){ curr=pos; //set current Object's value public void setvalue(object val){ listarray[curr]=val; //return value of current Object public Object currvalue(){ return listarray[curr]; //return true if list is empty public boolean isempty(){ if(length==0) { return true; else { return false; //return true if list is full public boolean isfull(){ if (length == maxsize){ return true; else{ return false; //return true if current is within list public boolean isinlist(){ return curr>=0 && curr<length; //print all of list's elements public void print(){ if(isempty()){ System.out.println("[]"); else{ System.out.print("["); for(setfirst();isinlist();next()){ System.out.print(currValue()+" "); System.out.print("]"); 第 218 页

9.7.1.2 链 表 间 链 表 是 利 用 指 针 来 实 现 的, 是 动 态 的, 也 就 是 说, 能 够 按 照 需 要 为 表 中 新 的 元 素 分 配 存 储 空 链 表 是 由 一 系 列 叫 作 结 点 的 对 象 组 成, 每 一 个 结 点 都 是 一 个 独 立 的 对 象 下 面 代 码 中 表 示 了 结 点 的 完 整 定 义,Link 类 包 含 一 个 存 储 单 元 值 的 element 属 性 和 一 个 存 储 表 中 下 一 个 结 点 指 针 的 next 属 性 因 为 在 这 种 结 点 建 立 的 链 表 中, 每 个 结 点 只 有 一 个 指 向 表 中 下 一 个 节 点 的 指 针, 所 以 叫 作 单 链 表 (singly linked list) public class Link { //object for this node private Object element; //pointer to next node in list private Link next; Link(Object element,link next){ this.element=element; this.next=next; Link(Link next){ this.next=next; Link next(){ return next; Link setnext(link next){ this.next=next; return next; Object element(){ return element; Object setelement(object element){ return this.element=element; Link 类 非 常 简 单 它 有 两 个 构 造 方 法, 一 个 有 初 始 化 元 素 的 值, 另 一 个 没 有 其 他 方 法 帮 助 用 户 很 方 便 的 访 问 两 个 私 有 数 据 成 员 单 链 表 类 的 实 现 代 码 如 下 : public class LinkList implements List{ //pointer to list header private Link head; //pointer to last Object in list 第 219 页

private Link tail; //pointer to current Object protected Link curr; public LinkList(){ tail=head=curr=new Link(null); //remove all Objects from list public void clear(){ head.setnext(null); curr=tail=head; //insert Object at current position public void insert(object item){ curr.setnext(new Link(item,curr.next())); if(tail==curr){ tail=curr.next(); //insert Object at tail of list public void append(object item){ tail.setnext(new Link(item,null)); tail=tail.next(); //remove/return current Object public Object remove(){ if(!isinlist()){ throw new RuntimeException(" 当 前 节 点 为 null"); Object o=curr.element(); if(null==curr.next()){ prev(); curr.setnext(null); tail=curr; else{ Link temp= curr.next(); prev(); curr.setnext(temp); return o; //set current to first position public void setfirst(){ curr=head.next(); 第 220 页

//move current to next position public void next(){ if(curr!=null){ curr=curr.next(); //move current to prev position public void prev(){ if(curr==null curr==head){ //no previous object return; //so just return Link temp=head; //start at front of list while(temp!=null && temp.next()!=curr){ temp=temp.next(); curr=temp; //found previous link //return current length of list public int length(){ int count=0; for(link temp=head.next();temp!=null;temp=temp.next()){ count++; return count; //set current to specified post public void setpost(int pos){ curr=head; for(int i=0;curr!=null && i<pos;i++){ curr=curr.next(); //set current Object's value public void setvalue(object val){ if(isinlist()){ curr.setelement(val); else{ throw new RuntimeException(" 当 前 节 点 为 null"); //return value of current Object public Object currvalue(){ 第 221 页

if(curr==null){ return null; return curr.element(); //return true if list is empty public boolean isempty(){ return head.next()==null; //return true if current is within list public boolean isinlist(){ return curr!=null && curr.next()!=null; //print all of list's elements public void print(){ if(isempty()){ System.out.println("[]"); else{ System.out.print("["); for(setfirst();isinlist();next()){ System.out.print(currValue()+ " " ); System.out.println("]"); 单 链 表 中 增 加 了 特 殊 的 表 态 结 点, 这 个 表 头 结 点 是 表 中 的 第 一 个 结 点, 它 与 表 中 其 他 元 素 一 样, 只 是 它 的 值 被 忽 略, 不 被 看 做 表 中 的 实 际 元 素 这 样 我 们 就 不 再 需 要 考 虑 空 链 表, 表 中 一 定 有 一 个 结 点, 这 样 的 设 计 节 省 了 源 代 码, 降 低 了 源 程 序 的 复 杂 性 存 储 结 构 如 下 : curr tail head 空 的 单 链 表 ( 只 有 表 头 元 素 ) 当 使 用 append 方 法 向 表 中 添 加 新 的 元 素 时, 只 需 要 改 变 tail 指 向 结 点 的 next 属 性, 将 新 的 节 点 赋 值 给 该 属 性 即 可 第 222 页

head curr tail 2 4 0 3 append 方 法 添 加 新 元 素 4 2 当 使 用 insert 方 法 时, 向 curr 指 向 的 结 点 后 添 加 一 个 新 的 节 点 head curr tail 0 2 3 4 4 2 insert 方 法 添 加 新 元 素 6 3 当 使 用 remove 方 法 时, 将 curr 指 向 的 结 点 删 除, 如 果 curr 指 向 尾 结 点, 将 curr 指 针 向 前 移 动, 设 置 next 指 向 空 ; 如 果 curr 不 指 向 尾 结 点, 取 出 curr 的 下 一 个 结 点 temp, 将 curr 指 针 向 前 移 动, 设 置 curr 指 针 的 next 为 temp 结 点 head curr tail 删 前 除 head 0 2 3 4 curr tail 4 2 删 后 除 0 2 3 4 4 2 当 curr 指 向 尾 结 点 时 使 用 remove 方 法 第 223 页

head curr tail 删 前 除 2 4 0 3 4 head curr tail 2 删 后 除 0 2 3 4 4 2 当 curr 没 有 指 向 尾 结 点 时 使 用 remove 方 法 注 : 代 码 中 设 计 删 除 当 前 结 点 后, 指 针 向 前 移 动 ; 也 可 以 设 计 成 删 除 结 点 后, 指 针 向 后 移 动 9.7.1.3 线 性 表 实 现 方 法 的 比 较 呢? 前 面 已 经 给 出 线 性 表 的 两 种 截 然 不 同 的 实 现 方 法, 哪 一 种 更 好 呢, 当 使 用 线 性 表 时 如 何 选 择 顺 序 表 的 缺 点 是 长 度 固 定 虽 然 便 于 给 数 组 分 配 空 间, 但 它 不 仅 不 能 超 过 预 定 的 长 度, 而 且 当 线 性 表 中 只 有 几 个 元 素 时, 浪 费 了 相 当 多 的 空 间 链 表 的 优 点 是 只 有 实 际 在 链 表 中 的 对 象 需 要 空 间 只 有 有 可 用 的 内 存 空 间 分 配, 链 表 中 元 素 的 个 数 就 没 有 限 制 顺 序 表 的 优 点 是 对 于 表 中 每 一 个 元 素 没 有 浪 费 空 间, 而 链 表 需 要 在 每 个 结 点 上 附 加 一 个 指 针 如 果 element 对 象 占 据 的 空 间 较 小, 则 链 表 的 结 构 性 开 销 就 占 去 了 整 个 存 储 空 间 的 一 大 部 分 当 顺 序 表 被 填 满 时, 存 储 上 没 有 结 构 性 开 销 这 这 种 情 况 下, 书 序 表 有 更 高 的 空 间 效 率 所 以 当 线 性 表 元 素 数 目 变 化 较 大 或 者 未 知 时, 最 好 使 用 链 表 实 现 而 如 果 用 户 事 先 知 道 线 性 表 的 大 致 长 度, 使 用 顺 序 表 的 空 间 效 率 会 更 高 当 要 求 对 线 性 表 进 行 随 机 访 问 时, 使 用 顺 序 表 更 快 一 些 ; 通 过 next 和 prev 只 可 以 调 整 当 前 位 置 向 前 或 向 后 移 动 其 中 next 操 作 很 容 易 实 现, 而 对 于 prev 操 作, 在 单 链 表 中 不 能 直 接 访 问 前 面 的 元 素, 只 能 从 表 头 开 始 寻 找 那 个 特 定 的 位 置 当 进 行 插 入 和 删 除 操 作 时, 链 表 比 顺 序 表 的 时 间 效 率 更 高 9.7.1.4 双 链 表 当 链 表 只 允 许 从 一 个 表 结 点 直 接 访 问 它 的 后 继 结 点, 而 双 链 表 (double linked list) 可 以 从 一 个 表 结 点 出 发, 方 便 地 再 线 性 表 中 访 问 它 的 前 驱 结 点 和 后 继 结 点 双 链 表 存 储 了 两 个 指 针, 一 个 指 向 它 的 后 继 结 点 ( 与 单 链 表 相 同 ), 另 一 个 指 向 它 的 前 驱 结 第 224 页

点 结 构 如 下 : head curr tail 2 4 2 0 双 链 表 结 构 3 4 双 链 表 比 单 链 表 更 容 易 实 现, 因 为 有 一 个 指 针 prev 可 以 访 问 前 一 个 结 点, 使 得 指 针 curr 先 前 或 向 后 移 动 变 得 非 常 方 便 9.7.2 栈 栈 (stack) 是 限 定 仅 在 一 端 进 行 插 入 或 删 除 的 线 性 表 虽 然 这 个 限 制 减 小 了 栈 的 灵 活 性, 但 是 会 使 栈 更 有 效 且 更 容 易 实 现 栈 的 访 问 遵 循 后 进 先 出 (last in first out) 原 则, 就 是 栈 的 可 访 问 元 素 为 栈 顶 (top) 元 素, 元 素 的 插 入 栈 称 作 压 栈 (push), 删 除 元 素 时 称 作 出 栈 (pop) 图 示 如 下 : 出 栈 进 栈 栈 顶 4 3 2 栈 底 1 思 考 题 : 如 果 进 栈 顺 序 为 1 2 3 4, 那 么 下 面 哪 种 出 栈 顺 序 是 可 以 实 现 的? 1 4 3 2 1 3 4 2 4 3 2 1 3 4 2 1 两 种 常 用 实 现 方 法 : 顺 序 栈 (array-based stack) 和 链 式 栈 (linked stack) 9.7.3 队 列 同 栈 一 样, 队 列 (queue) 也 是 一 种 受 限 的 线 性 表 队 列 元 素 只 能 从 队 尾 插 入 ( 称 为 入 队 操 作 ), 从 队 首 进 行 删 除 ( 称 为 出 队 操 作 ) 队 列 操 作 就 像 在 电 影 院 前 排 队 买 票 一 样, 如 果 没 有 人 为 破 坏, 那 么 新 来 者 应 该 站 在 队 列 的 后 端, 在 队 列 最 前 端 的 人 是 下 一 个 要 被 服 务 的 对 象 第 225 页

队 列 的 访 问 遵 循 先 进 先 出 (first in first out) 原 则, 图 示 如 下 : 出 队 1 6 2 3 4 5 入 队 队 头 队 尾 两 种 常 用 实 现 方 法 : 顺 序 栈 (array-based queue) 和 链 式 栈 (linked queue) 9.8 学 习 目 标 1. 能 够 描 述 集 合 框 架 的 结 构 :Collection 接 口 List 接 口 Set 接 口 Map 接 口 及 实 现 类 2. 理 解 List 接 口 和 Set 接 口 的 特 点 3. 理 解 Map 接 口 的 特 点 4. 熟 练 掌 握 Collection 接 口 的 方 法, 重 点 是 迭 代 方 法 5. 熟 练 掌 握 Map 接 口 中 的 方 法, 重 点 是 迭 代 方 法 6. 查 看 JDK API 文 档 中 和 集 合 相 关 的 API 7. 完 成 课 后 作 业 题, 通 过 老 师 的 讲 解, 理 解 ColDB 的 作 用 和 原 理 ( 讲 过 作 业 题 后 ) 9.9 练 习 1. 写 一 个 方 法 reverselist, 该 方 法 接 收 一 个 List 参 数, 然 后 把 该 List 倒 序 排 列 2. 综 合 设 计 题 : 定 义 一 个 类 ListDB, 类 里 面 有 一 个 属 性 list, 类 型 是 集 合 类 型 List, 实 现 下 列 方 法 : 可 以 向 list 里 面 添 加 数 据 修 改 数 据 查 询 数 据 删 除 数 据 也 就 是 把 这 个 list 当 作 一 个 数 据 存 储 的 容 器, 对 其 实 现 数 据 的 增 删 改 查 的 方 法 注 意 这 些 方 法 是 否 需 要 传 入 参 数, 是 否 应 该 有 返 回 类 型 3. 综 合 设 计 题 : 已 知 有 十 六 支 男 子 足 球 队 参 加 2008 北 京 奥 运 会 写 一 个 程 序, 把 这 16 只 球 队 随 机 分 为 4 个 组 2008 北 京 奥 运 会 男 足 参 赛 国 家 : 科 特 迪 瓦, 阿 根 廷, 澳 大 利 亚, 塞 尔 维 亚, 荷 兰, 尼 日 利 亚 日 本, 美 国, 中 国, 新 西 兰, 巴 西, 比 利 时, 韩 国, 喀 麦 隆, 洪 都 拉 斯, 意 大 利 第 226 页

10 图 形 用 户 接 口 AWT 10.1 GUI 的 基 本 概 念 10.1.1 Component AWT 提 供 用 于 所 有 Java applets 及 应 用 程 序 中 的 基 本 GUI 组 件, 还 为 应 用 程 序 提 供 与 机 器 的 界 面 这 将 保 证 一 台 计 算 机 上 出 现 的 东 西 与 另 一 台 上 的 相 一 致 在 学 AWT 之 前, 简 单 回 顾 一 下 对 象 层 次 记 住, 超 类 是 可 以 扩 展 的, 它 们 的 属 性 是 可 继 承 的 而 且, 类 可 以 被 抽 象 化, 这 就 是 说, 它 们 是 可 被 分 成 子 类 的 模 板, 子 类 用 于 类 的 具 体 实 现 显 示 在 屏 幕 上 的 每 个 GUI 组 件 都 是 抽 象 类 组 件 的 子 类 也 就 是 说, 每 个 从 组 件 类 扩 展 来 的 图 形 对 象 都 与 允 许 它 们 运 行 的 大 量 方 法 和 实 例 变 量 共 享 10.1.2 Container Container 是 Component 的 一 个 抽 象 子 类, 它 允 许 其 它 的 组 件 被 嵌 套 在 里 面 这 些 组 件 也 可 以 是 允 许 其 它 组 件 被 嵌 套 在 里 面 的 容 器, 于 是 就 创 建 了 一 个 完 整 的 层 次 结 构 在 屏 幕 上 布 置 GUI 组 件, 容 器 是 很 有 用 的 Panel 是 Container 的 最 简 单 的 类 Container 的 另 一 个 子 类 是 Window Window 是 Java.awt.Window 的 对 象 Window 是 显 示 屏 上 独 立 的 本 机 窗 口, 它 独 立 于 其 它 容 器 Window 有 两 种 形 式 :Frame( 框 架 ) 和 Dialog( 对 话 框 ) Frame 和 Dialog 是 Window 的 子 类 Frame 是 一 个 带 有 标 题 和 缩 放 角 的 窗 口 对 话 没 有 菜 单 条 尽 管 它 能 移 动, 但 它 不 能 缩 放 Panel 是 Java.awt.Panel 的 对 象 Panel 包 含 在 另 一 个 容 器 中, 或 是 在 Web 浏 览 器 的 窗 口 中 Panel 确 定 一 个 四 边 形, 其 它 组 件 可 以 放 入 其 中 Panel 必 须 放 在 Window 之 中 ( 或 Window 的 子 类 中 ) 以 便 能 显 示 出 来 本 的 容 器 不 但 能 容 纳 组 件, 还 能 容 纳 其 它 容 器, 这 一 事 实 对 于 建 立 复 杂 的 布 局 是 关 键 的, 也 是 基 10.1.3 组 件 定 位 容 器 里 的 组 件 的 位 置 是 由 布 局 管 理 器 决 定 的 容 器 对 布 局 管 理 器 的 特 定 实 例 保 持 一 个 引 用 当 容 器 需 要 定 位 一 个 组 件 时, 它 将 调 用 布 局 管 理 器 来 做 当 决 定 一 个 组 件 的 大 小 时, 同 样 如 此 第 227 页

布 局 管 理 器 完 全 控 制 容 器 内 的 所 有 组 件 它 负 责 计 算 并 定 义 上 下 文 中 对 象 在 实 际 屏 幕 中 所 需 的 大 小 10.2 容 器 的 基 本 使 用 10.2.1 Frame 的 使 用 Frame 是 Window 的 一 个 子 类 它 是 带 有 标 题 和 缩 放 角 的 窗 口 它 继 承 于 Java.awt.Container, 因 此, 可 以 用 add() 方 式 来 给 框 架 添 加 组 件 框 架 的 缺 省 布 局 管 理 器 就 是 Border Layout 它 可 以 用 setlayout() 方 式 来 改 变 框 架 类 中 的 构 造 程 序 Frame(String) 用 由 String 规 定 的 标 题 来 创 建 一 个 新 的 不 可 见 的 框 架 对 象 当 它 还 处 于 不 可 见 状 态 时, 将 所 有 组 件 添 加 到 框 架 中 import java.awt.*; public class MyFrame extends Frame { public MyFrame(String str) { super(str); public static void main(string args[]) { MyFrame fr = new MyFrame(" 我 的 第 一 个 Frame"); // 设 置 大 小 fr.setsize(500, 500); // 设 置 背 景 颜 色 fr.setbackground(color.blue); // 设 置 框 架 可 见 fr.setvisible(true); 上 述 程 序 创 建 了 下 述 框 架, 它 有 一 个 具 体 的 标 题 大 小 及 背 景 颜 色 第 228 页

在 框 架 显 示 在 屏 幕 上 之 前, 必 须 做 成 可 见 的 ( 通 过 调 用 程 序 setvisible(true)), 而 且 其 大 小 是 确 定 的 ( 通 过 调 用 程 序 setsize() 或 pack()) 10.2.2 Panel 的 使 用 像 Frame 一 样,Panel 提 供 空 间 来 连 接 任 何 GUI 组 件, 包 括 其 它 面 板 每 个 面 板 都 可 以 有 它 自 己 的 布 管 理 程 序 一 旦 一 个 面 板 对 象 被 创 建, 为 了 能 看 得 见, 它 必 须 添 加 到 窗 口 或 框 架 对 象 上 用 Container 类 中 的 add() 方 式 可 以 做 到 这 一 点 下 面 的 程 序 创 建 了 一 个 小 的 黄 色 面 板, 并 将 它 加 到 一 个 框 架 对 象 上 : import java.awt.*; public class FrameWithPanel extends Frame { // Constructor public FrameWithPanel(String str) { super(str); public static void main(string args[]) { FrameWithPanel fr = new FrameWithPanel(" 我 的 第 一 个 Frame"); Panel pan = new Panel(); fr.setsize(500, 500); fr.setbackground(color.red); 第 229 页

fr.setlayout(null); // override default layout mgr pan.setsize(300, 300); pan.setbackground(color.blue); pan.setlayout(null); // override default layout mgr fr.add(pan); fr.setvisible(true); 10.3 AWT 组 件 的 使 用 AWT 组 件 提 供 了 控 制 界 面 外 观 的 机 制, 包 括 用 于 文 本 显 示 的 颜 色 和 字 体 此 外,AWT 还 支 持 打 印 这 个 功 能 是 在 JDK1.1 之 后 中 引 入 的 10.3.1 按 钮 (Button) 你 已 经 比 较 熟 悉 Button 组 件 了 这 个 组 件 提 供 了 按 下 并 动 作 的 基 本 用 户 界 面 可 以 构 造 一 个 带 文 标 签 的 按 钮, 用 来 告 诉 用 户 它 的 作 用 第 230 页

Button b=new Button(" 按 钮 "); b.setsize(100,50); b.setlocation(100,100); pan.add(b); 10.3.2 复 选 框 (Checkbox) Checkbox 组 件 提 供 一 种 简 单 的 开 / 关 输 入 设 备, 它 旁 边 有 一 个 文 本 标 签 Checkbox one=new Checkbox("one",true); Checkbox two =new Checkbox("two",false); Checkbox three =new Checkbox("three",false); one.setsize(50,50); two.setsize(50,50); three.setsize(50,50); one.setlocation(50,50); two.setlocation(100,50); three.setlocation(150,50); pan.add(one); pan.add(two); pan.add(three); 第 231 页

10.3.3 复 选 框 组 - 单 选 框 (Checkbox group-radio Button) 复 选 框 组 提 供 了 将 多 个 复 选 框 作 为 互 斥 的 一 个 集 合 的 方 法, 因 此 在 任 何 时 刻, 这 个 集 合 中 只 有 一 个 复 选 框 的 值 是 true 值 为 true 的 复 选 框 就 是 当 前 被 选 中 的 复 选 框 你 可 以 使 用 带 有 一 个 额 外 的 CheckboxGroup 参 数 的 构 造 函 数 来 创 建 一 组 中 的 每 个 复 选 框 正 是 这 个 CheckBoxGroup 对 象 将 各 个 复 选 框 连 接 成 一 组 如 果 你 这 么 做 的 话, 那 么 复 选 框 的 外 观 会 发 生 改 变, 而 且 所 有 和 一 个 复 选 框 组 相 关 联 的 复 选 框 将 表 现 出 单 选 框 的 行 为 CheckboxGroup cbg=new CheckboxGroup(); Checkbox one=new Checkbox("one",true,cbg); Checkbox two =new Checkbox("two",false,cbg); Checkbox three =new Checkbox("three",false,cbg); one.setsize(50,50); two.setsize(50,50); three.setsize(50,50); one.setlocation(50,50); two.setlocation(100,50); three.setlocation(150,50); pan.add(one); pan.add(two); pan.add(three); 第 232 页

10.3.4 下 拉 列 表 (Choice) 下 拉 列 表 组 件 提 供 了 一 个 简 单 的 从 列 表 中 选 取 一 个 类 型 的 输 入 例 如 : Choice c=new Choice(); c.add("first"); c.add("second"); c.add("third"); c.setsize(100,100); c.setlocation(50,50); pan.add(c); 点 击 下 拉 列 表 组 件 时, 它 会 显 示 一 个 列 表, 列 表 中 包 含 了 所 有 加 入 其 中 的 条 目 注 意 所 加 入 的 条 目 是 String 对 象 第 233 页

10.3.5 标 签 (Label) 一 个 标 签 对 象 显 示 一 行 静 态 文 本 程 序 可 以 改 变 文 本, 但 用 户 不 能 改 变 标 签 没 有 任 何 特 殊 的 边 框 和 装 饰 Label lbl=new Label("HelloWorld"); lbl.setsize(100,50); lbl.setlocation(50,50); pa.add(lbl); 标 签 通 常 不 处 理 事 件, 但 也 可 以 按 照 和 画 布 相 同 的 方 式 来 处 理 事 件 也 就 是 说, 只 有 调 用 了 requestfocus() 方 法 后, 才 能 可 靠 地 检 取 击 键 事 件 10.3.6 文 本 域 (Textfield) 文 本 域 是 一 个 单 行 的 文 本 输 入 设 备 例 如 : TextField tf=new TextField(); tf.setsize(300,30); tf.setlocation(50,50); pan.add(tf); 第 234 页

10.3.7 文 本 区 (TextArea) 文 本 区 是 一 个 多 行 多 列 的 文 本 输 入 设 备 文 本 区 将 显 示 水 平 和 垂 直 的 滚 动 条 下 面 这 个 范 例 创 建 了 一 个 文 本 区, 最 初 它 含 有 Hello! TextArea t = new TextArea("Hello!"); t.setlocation(100, 100); t.setsize(300, 100); add.add(t); 10.3.8 列 表 (list) 一 个 列 表 将 各 个 文 本 选 项 显 示 在 一 个 区 域 中, 这 样 就 可 以 在 同 时 看 到 若 干 个 条 目 列 表 可 以 滚 动, 并 支 持 单 选 和 多 选 两 种 模 式 例 如 : List lst=new List(); lst.add(" 篮 球 "); lst.add(" 足 球 "); lst.add(" 排 球 "); lst.setsize(50,60); lst.setlocation(50,50); lst.setmultiplemode(true); pa.add(lst); 第 235 页

10.4 菜 单 的 实 现 菜 单 与 其 他 组 件 有 一 个 重 要 的 不 同 : 你 不 能 将 菜 单 添 加 到 一 般 的 容 器 中, 而 且 不 能 使 用 布 局 管 理 器 对 它 们 进 行 布 局 你 只 能 将 菜 单 加 到 一 个 菜 单 容 器 中 然 而, 你 可 以 将 一 个 Jmenuswing 组 件 加 到 一 个 Jcontainer 中 你 可 以 通 过 使 用 setmenubar() 方 法 将 菜 单 放 到 一 个 框 架 中, 从 而 启 动 一 个 菜 单 树 从 那 个 时 刻 之 后, 你 可 以 将 菜 单 加 到 菜 单 条 中, 并 将 菜 单 或 菜 单 项 加 到 菜 单 中 弹 出 式 菜 单 是 一 个 例 外, 因 为 它 们 可 以 以 浮 动 窗 口 形 式 出 现, 因 此 不 需 要 布 局 10.4.1 帮 助 菜 单 菜 单 条 的 一 个 特 性 是 你 可 以 将 一 个 菜 单 指 定 为 帮 助 菜 单 这 可 以 用 sethelpmenu(menu) 来 做 到 要 作 为 帮 助 菜 单 的 菜 单 必 须 加 入 到 菜 单 条 中 ; 然 后 它 就 会 以 和 本 地 平 台 的 帮 助 菜 单 同 样 的 方 式 被 处 理 对 于 X/Motif 类 型 的 系 统, 这 涉 及 将 菜 单 条 放 置 在 菜 单 条 的 最 右 边 10.4.2 菜 单 条 (MenuBar) 一 个 菜 单 条 组 件 是 一 个 水 平 菜 单 它 只 能 加 入 到 一 个 框 架 中, 并 成 为 所 有 菜 单 树 的 根 在 一 个 时 刻, 一 个 框 架 可 以 显 示 一 个 菜 单 条 然 而, 你 可 以 根 据 程 序 的 状 态 修 改 菜 单 条, 这 样 在 不 同 的 时 刻 就 可 以 显 示 不 同 的 菜 单 例 如 : MenuBar mb = new MenuBar(); frame.setmenubar(mb); 没 有 菜 单 的 菜 单 条 是 看 不 到 的, 所 以 大 家 在 Frame 中 看 不 到 菜 单 条 的 10.4.3 菜 单 组 件 如 : 菜 单 组 件 提 供 了 一 个 基 本 的 下 拉 式 菜 单 它 可 以 加 入 到 一 个 菜 单 条 或 者 另 一 个 菜 单 中 例 MenuBar mb = new MenuBar(); Menu m1 = new Menu("File"); 第 236 页

Menu m2 = new Menu("Edit"); Menu m3 = new Menu("Help"); mb.add(m1); mb.add(m2); mb.sethelpmenu(m3); frame.setmenubar(mb); 这 里 显 示 的 菜 单 是 空 的, 这 正 是 File 菜 单 的 外 观 10.4.4 菜 单 项 (MenuItem) 例 如 : 菜 单 项 组 件 是 菜 单 树 的 文 本 叶 结 点 它 们 通 常 被 加 入 到 菜 单 中, 以 构 成 一 个 完 整 的 菜 单 MenuItem mi1 = new MenuItem("New"); MenuItem mi2 = new MenuItem("Load"); MenuItem mi3 = new MenuItem("Save"); MenuItem mi4 = new MenuItem("Quit"); m1.add(mi1); m1.add(mi2); m1.addseparator(); m1.add(mi3); 10.4.5 复 选 菜 单 项 (CheckboxMenuItem) 复 选 菜 单 项 是 一 个 可 复 选 的 菜 单 项, 所 以 你 可 以 在 菜 单 上 有 选 项 ( 开 或 关 ) 例 如 : 第 237 页

MenuItem mi1 = new MenuItem("Save"); CheckboxMenuItem mi2 =new CheckboxMenuItem("Persistent"); m1.add(mi1); m1.add(mi2); 10.4.6 弹 出 式 菜 单 (PopupMenu) 弹 出 式 菜 单 提 供 了 一 种 独 立 的 菜 单, 它 可 以 在 任 何 组 件 上 显 示 你 可 以 将 菜 单 条 目 和 菜 单 加 入 到 弹 出 式 菜 单 中 去 例 如 : PopupMenu p = new PopupMenu("Popup"); MenuItem s = new MenuItem("Save"); MenuItem l = new MenuItem("Load"); p.add(s); p.add(l); frame.add(p); // 显 示 弹 出 式 菜 单 p.show(fr, 100, 70); 注 - 弹 出 式 菜 单 必 须 加 入 到 一 个 父 组 件 中 这 与 将 组 件 加 入 到 容 器 中 是 不 同 的 在 上 面 这 个 范 例 中, 弹 出 式 菜 单 被 加 入 到 周 围 的 框 架 中 10.5 控 制 外 观 你 可 以 控 制 在 AWT 组 件 中 所 显 示 的 文 本 的 前 景 背 景 颜 色 背 景 颜 色 和 字 体 第 238 页

10.6 布 局 管 理 器 和 布 局 10.6.1 FlowLayout( 流 式 布 局 ) 使 用 FlowLayout 布 局 方 式 的 容 器 中 组 件 按 照 加 入 的 先 后 顺 序 按 照 设 置 的 对 齐 方 式 ( 居 中 左 对 齐 右 对 齐 ) 从 左 向 右 排 列, 一 行 排 满 ( 即 组 件 超 过 容 器 宽 度 后 ) 到 下 一 行 开 始 继 续 排 列 流 式 布 局 特 征 如 下 : 组 件 按 照 设 置 的 对 齐 方 式 进 行 排 列 不 管 对 齐 方 式 如 何, 组 件 均 按 照 从 左 到 右 的 方 式 进 行 排 列, 一 行 排 满, 转 到 下 一 行 ( 比 如 按 照 右 对 齐 排 列, 第 一 个 组 件 在 第 一 行 最 右 边, 添 加 第 二 个 组 件 时, 第 一 个 组 件 向 左 平 移, 第 二 个 组 件 变 成 该 行 最 右 边 的 组 件, 这 就 是 从 左 向 右 方 式 进 行 排 列 ) import java.awt.button; import java.awt.flowlayout; import java.awt.font; import java.awt.frame; public class FlowLayoutDemo extends Frame { public FlowLayoutDemo() { // 设 置 窗 体 为 流 式 布 局, 无 参 数 默 认 为 居 中 对 齐 setlayout(new FlowLayout()); // 设 置 窗 体 中 显 示 的 字 体 样 式 setfont(new Font("Helvetica", Font.PLAIN, 14)); // 将 按 钮 添 加 到 窗 体 中 this.add(new Button("Button 1")); this.add(new Button("Button 2")); this.add(new Button("Button3")); this.add(new Button("Button 4")); public static void main(string args[]) { FlowLayoutDemo frame = new FlowLayoutDemo(); frame.settitle(" 流 式 布 局 "); // 该 代 码 依 据 放 置 的 组 件 设 定 窗 口 的 大 小 使 之 正 好 能 容 纳 你 放 置 的 所 有 组 件 frame.pack(); frame.setvisible(true); frame.setlocationrelativeto(null); // 让 窗 体 居 中 显 示 第 239 页

原 始 界 面 : 拉 伸 原 始 界 面 : 拉 窄 原 始 界 面 : 10.6.2 BorderLayout( 边 框 布 局 ) Border 布 局 管 理 器 为 在 一 个 Panel 或 Window 中 放 置 组 件 提 供 一 个 更 复 杂 的 方 案 Border 布 局 管 理 器 包 括 五 个 明 显 的 区 域 : 东 南 西 北 中 北 占 据 面 板 的 上 方, 东 占 据 面 板 的 右 侧, 等 等 中 间 区 域 是 在 东 南 西 北 都 填 满 后 剩 下 的 区 域 当 窗 口 垂 直 延 伸 时, 东 西 中 区 域 也 延 伸 ; 而 当 窗 口 水 平 延 伸 时, 东 西 中 区 域 也 延 伸 Border 布 局 管 理 器 是 用 于 Dialog 和 Frame 的 缺 省 布 局 管 理 器 第 240 页

当 窗 口 缩 放 时, 按 钮 相 应 的 位 置 不 变 化, 但 其 大 小 改 变 import java.awt.borderlayout; import java.awt.button; import java.awt.frame; public class BorderLayoutDemo extends Frame{ public BorderLayoutDemo(){ Button N=new Button(" 北 "); Button S=new Button(" 南 "); Button W=new Button(" 西 "); Button E=new Button(" 东 "); Button C=new Button(" 中 "); this.add(n,borderlayout.north); this.add(s,borderlayout.south); this.add(w,borderlayout.west); this.add(e,borderlayout.east); this.add(c,borderlayout.center); public static void main(string[] args){ BorderLayoutDemo frame = new BorderLayoutDemo(); frame.settitle(" 边 框 布 局 "); // 该 代 码 依 据 放 置 的 组 件 设 定 窗 口 的 大 小 使 之 正 好 能 容 纳 你 放 置 的 所 有 组 件 frame.pack(); frame.setvisible(true); frame.setlocationrelativeto(null); // 让 窗 体 居 中 显 示 10.6.3 GridLayout( 网 格 布 局 ) Grid 布 局 管 理 器 为 放 置 组 件 提 供 了 灵 活 性 用 许 多 行 和 栏 来 创 建 管 理 程 序 然 后 组 件 就 填 充 到 由 管 理 程 序 规 定 的 单 元 中 比 如, 由 语 句 new GridLayout(3,2) 创 建 的 有 三 行 两 栏 的 第 241 页

Grid 布 局 能 产 生 如 下 六 个 单 元 : 变 因 为 有 Border 布 局 管 理 器, 组 件 相 应 的 位 置 不 随 区 域 的 缩 放 而 改 变 只 是 组 件 的 大 小 改 Grid 布 局 管 理 器 总 是 忽 略 组 件 的 最 佳 大 小 所 有 单 元 的 宽 度 是 相 同 的, 是 根 据 单 元 数 对 可 用 宽 度 进 行 平 分 而 定 的 同 样 地, 所 有 单 元 的 高 度 是 相 同 的, 是 根 据 行 数 对 可 用 高 度 进 行 平 分 而 定 的 将 组 件 添 加 到 网 格 中 的 命 令 决 定 它 们 占 有 的 单 元 单 元 的 行 数 是 从 左 到 右 填 充, 就 象 文 本 一 样, 而 页 是 从 上 到 下 由 行 填 充 import java.awt.borderlayout; import java.awt.button; import java.awt.frame; import java.awt.gridlayout; import java.awt.panel; import java.awt.textfield; public class GridLayoutDemo extends Frame { public GridLayoutDemo() { // 创 建 第 一 个 Panel, 显 示 输 入 框 Panel p1 = new Panel(); p1.add(new TextField(30)); this.add(p1,borderlayout.north); // 创 建 第 一 个 Panel, 显 示 数 字 和 操 作 符 的 按 钮 Panel p2 = new Panel(); p2.setlayout(new GridLayout(3, 5, 4, 4)); String[] name = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "." ; for (int i = 0; i < name.length; i++) { p2.add(new Button(name[i])); this.add(p2); public static void main(string[] args) { GridLayoutDemo frame = new GridLayoutDemo(); 第 242 页

frame.settitle(" 网 格 布 局 "); // 该 代 码 依 据 放 置 的 组 件 设 定 窗 口 的 大 小 使 之 正 好 能 容 纳 你 放 置 的 所 有 组 件 frame.pack(); frame.setvisible(true); frame.setlocationrelativeto(null); // 让 窗 体 居 中 显 示 10.6.4 CardLayout( 卡 片 布 局 ) Card 布 局 管 理 器 能 将 界 面 看 作 一 系 列 的 卡, 其 中 的 一 个 在 任 何 时 候 都 可 见 用 add() 方 法 来 将 卡 添 加 到 Card 布 局 中 Card 布 局 管 理 器 的 show() 方 法 应 请 求 转 换 到 一 个 新 卡 中 下 例 就 是 一 个 带 有 5 张 卡 的 框 架 import java.awt.*; import java.awt.event.actionevent; import java.awt.event.actionlistener; public class CardLayoutDemo { Frame f; Panel p1; 第 243 页

Panel p2; String[] name = { "1", "2", "3", "4", "5" ; CardLayout c; public CardLayoutDemo(){ f = new Frame(" 卡 片 布 局 "); p1 = new Panel(); p2 = new Panel(); c = new CardLayout(); p1.setlayout(c); for (int i = 0; i < name.length; i++){ p1.add(name[i], new Button(name[i])); // 控 制 显 示 上 一 张 的 按 钮 Button previous = new Button(" 上 一 张 "); previous.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e){ c.previous(p1); ); // 控 制 显 示 下 一 张 的 按 钮 Button next = new Button(" 下 一 张 "); next.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e){ c.next(p1); ); // 控 制 显 示 第 一 张 的 按 钮 Button first = new Button(" 第 一 张 "); first.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e){ c.first(p1); ); // 控 制 显 示 最 后 一 张 的 按 钮 Button last = new Button(" 最 后 一 张 "); last.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e){ c.last(p1); ); // 根 据 card 名 显 示 的 按 钮 第 244 页

Button third = new Button(" 第 三 张 "); third.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e) { c.show(p1, "3"); ); p2.add(previous); p2.add(next); p2.add(first); p2.add(last); p2.add(third); f.add(p1);// 默 认 添 加 到 中 间 f.add(p2, BorderLayout.SOUTH); f.pack(); f.setvisible(true); public static void main(string[] args){ new CardLayoutDemo(); 10.6.5 GridBag 布 局 管 理 器 除 了 Flow Border Grid 和 Card 布 局 管 理 器 外, 核 心 Java.awt 也 提 供 GridBag 布 局 管 理 器 GridBag 布 局 管 理 器 在 网 格 的 基 础 上 提 供 复 杂 的 布 局, 但 它 允 许 单 个 组 件 在 一 个 单 元 中 而 不 是 填 满 整 个 单 元 那 样 地 占 用 它 们 的 最 佳 大 小 网 格 包 布 局 管 理 器 也 允 许 单 个 组 件 扩 展 成 不 止 一 个 单 元 第 245 页

11 I/O 流 11.1 File 类 11.1.1 创 建 File 对 象 File 类 的 对 象 主 要 用 来 获 取 文 件 本 身 的 一 些 信 息, 例 如 文 件 所 在 的 目 录, 文 件 的 长 度, 文 件 读 写 权 限 等, 不 涉 及 对 文 件 的 读 写 操 作 创 建 一 个 File 对 象 的 构 造 方 法 有 3 个 public File(String pathname) public File(String parentpath, String filename) public File(File parentfile, String filename) 其 中,pathname 和 filename 是 文 件 名 字,parentPath 是 文 件 的 路 径,parentFile 是 指 定 的 一 个 目 录 文 件 11.1.2 File 类 的 方 法 public boolean canwrite() 判 断 文 件 是 否 可 被 写 入 // 创 建 一 个 文 件 对 象,( 在 硬 盘 中 没 有 javakc.txt 文 件 ) File f=new File("d:/javakc.txt"); // 判 断 此 文 件 是 否 可 写 boolean flag=f.canwrite(); // 输 出 结 果 :false System.out.println(flag); public boolean exists() 判 断 文 件 是 否 存 在 // 创 建 一 个 文 件 对 象 File f=new File("d:/javakc.txt");// 文 件 在 硬 盘 中 存 在 File f2=new File("d:/kc/javakc.txt");// 文 件 在 硬 盘 中 不 存 在 // 输 出 文 件 是 否 存 在 System.out.println(f.exists());//true System.out.println(f2.exists());//false 第 246 页

public boolean createnewfile() 当 且 仅 当 不 存 在 具 有 此 抽 象 路 径 名 指 定 名 称 的 文 件 时, 不 可 分 地 创 建 一 个 新 的 空 文 件 // 创 建 一 个 文 件 对 象,( 在 硬 盘 中 没 有 javakc.txt 文 件 ) File f=new File("d:/javakc.txt"); // 创 建 文 件 boolean flag=f.createnewfile(); // 第 二 次 创 建 文 件 boolean flag2=f.createnewfile(); // 输 出 结 果 System.out.println(flag);//true System.out.println(flag2);//false public String getname() 获 取 文 件 的 名 字 // 创 建 一 个 文 件 对 象 File f=new File("d:/javakc.txt"); // 输 出 文 件 的 名 称 System.out.println(f.getName());//javakc.txt public long length() 获 取 文 件 的 长 度, 单 位 是 字 节 // 创 建 一 个 文 件 对 象 File f=new File("d:/javakc.txt");// 文 件 在 硬 盘 中 存 在 且 文 件 不 为 空 File f2=new File("d:/javakc2.txt");// 文 件 在 硬 盘 中 存 在 且 文 件 为 空 File f3=new File("d:/kc/javakc.txt");// 文 件 在 硬 盘 中 不 存 在 // 输 出 文 件 的 长 度 System.out.println(f.length());//6 System.out.println(f2.length());//0 System.out.println(f3.length());//0 public boolean equals(object obj) 测 试 此 抽 象 路 径 名 与 给 定 对 象 是 否 相 等 // 创 建 文 件 对 象 File f=new File("d:/javakc.txt"); File f2=new File("d:/javakc.txt"); // 输 出 两 个 文 件 是 否 相 等 System.out.println(f.equals(f2));//true // 使 用 相 对 路 径 创 建 文 件 对 象 File f3=new File("javakc.txt"); // 使 用 绝 对 路 径 创 建 文 件 对 象 File f4=new File("D:/work/javakc38/JseTest/javakc.txt"); // 输 出 两 个 文 件 是 否 相 等 System.out.println(f3.equals(f4));//false 第 247 页

public String getabsolutefile() 获 取 文 件 的 绝 对 路 径 // 使 用 相 对 路 径 创 建 文 件 对 象 File f3=new File("javakc.txt"); // 使 用 绝 对 路 径 创 建 文 件 对 象 File f4=new File("D:/work/javakc38/JseTest/javakc.txt"); // 输 出 两 个 文 件 是 否 相 等 System.out.println(f3.equals(f4));//false // 将 相 对 路 径 转 换 成 绝 对 路 径 File f5=f3.getabsolutefile(); System.out.println(f4.equals(f5));//true public boolean isfile() 测 试 此 抽 象 路 径 名 表 示 的 文 件 是 否 是 一 个 标 准 文 件 public boolean isdirectory() 测 试 此 抽 象 路 径 名 表 示 的 文 件 是 否 是 一 个 目 录 // 创 建 文 件 对 象 File f=new File("d:/javakc.txt"); File f2=new File("d:/kc"); // 测 试 此 抽 象 路 径 名 表 示 的 文 件 是 否 是 一 个 标 准 文 件 System.out.println(f.isFile());//true System.out.println(f2.isFile());//false // 测 试 此 抽 象 路 径 名 表 示 的 文 件 是 否 是 一 个 目 录 System.out.println(f.isDirectory());//false System.out.println(f2.isDirectory());//true public File[] listfiles() 返 回 一 个 抽 象 路 径 名 数 组, 这 些 路 径 名 表 示 此 抽 象 路 径 名 表 示 的 目 录 中 的 文 件 // 创 建 文 件 对 象 File f=new File("D:/work/javakc38/JseTest"); // 取 得 目 录 中 的 所 有 文 件 File[] fs=f.listfiles(); for(file child:fs){ System.out.println(child); 输 出 结 果 : D:\work\javakc38\JseTest\.classpath D:\work\javakc38\JseTest\.project D:\work\javakc38\JseTest\.settings D:\work\javakc38\JseTest\bin D:\work\javakc38\JseTest\javakc.txt D:\work\javakc38\JseTest\src 第 248 页

public String getparent() 获 取 文 件 的 父 目 录 // 创 建 文 件 对 象 File f=new File("javakc.txt"); // 根 据 相 对 路 径 转 换 成 绝 对 路 径 File f2=f.getabsolutefile();//d:\work\javakc38\jsetest\javakc.txt // 得 到 f2 的 父 目 录 File parent=f2.getparentfile(); System.out.println(parent);// D:\work\javakc38\JseTest public File[] listfiles(filefilter filter) 返 回 抽 象 路 径 名 数 组, 这 些 路 径 名 表 示 此 抽 象 路 径 名 表 示 的 目 录 中 满 足 指 定 过 滤 器 的 文 件 和 目 录 File f=new File("D:/work/javakc38/JseTest"); // 通 过 文 件 过 滤 器 取 得 目 录 中 的 所 有 标 准 文 件 File[] fs=f.listfiles(new FileFilter(){ // 文 件 过 滤 器 中 的 过 滤 方 法 public boolean accept(file f) { // 当 此 文 件 为 标 准 文 件 时 返 回 true if(f.isfile()){ return true; return false; ); // 展 示 结 果 for(file child:fs){ System.out.println(child); // 创 建 文 件 对 象 输 出 结 果 ( 只 有 文 件, 没 有 目 录 ): D:\work\javakc38\JseTest\.classpath D:\work\javakc38\JseTest\.project D:\work\javakc38\JseTest\javakc.txt public long getfreespace() 返 回 此 抽 象 路 径 名 指 定 的 分 区 中 未 分 配 的 字 节 数 // 创 建 文 件 对 象 File f=new File("D:/work/javakc38/JseTest"); System.out.println("D 盘 中 未 分 配 的 字 节 数 :"+f.getfreespace()); public boolean mkdir() 创 建 此 抽 象 路 径 名 指 定 的 目 录 // 创 建 文 件 对 象 第 249 页

File f=new File("D:/work/javakc40"); // 创 建 目 录 f.mkdir(); 目 录 public boolean mkdirs() 创 建 此 抽 象 路 径 名 指 定 的 目 录, 包 括 所 有 必 需 但 不 存 在 的 父 // 创 建 文 件 对 象 File f=new File("D:/work/javakc41/kc"); // 创 建 目 录 f.mkdirs(); public boolean renameto(file dest) 重 新 命 名 此 抽 象 路 径 名 表 示 的 文 件 // 创 建 文 件 对 象 File f=new File("D:/javakc.txt"); File f2=new File("D:/javakc39.txt"); // 修 改 文 件 名 称 f.renameto(f2); 第 250 页

11.2 流 的 基 本 知 识 流 是 字 节 从 源 到 目 的 的 轨 迹, 次 序 是 有 意 义 的 两 种 基 本 的 流 是 : 输 入 流 和 输 出 流 你 可 以 从 输 入 流 读, 但 你 不 能 对 它 写 要 从 输 入 流 读 取 字 节, 必 须 有 一 个 与 这 个 流 相 关 联 的 字 符 源 绍 在 java.io 包 中 定 义 了 一 些 流 类 下 图 表 明 了 包 中 的 类 层 次 一 些 更 公 共 的 类 将 在 后 面 介 11.3 FileInputStream 类 如 果 需 要 从 本 地 硬 盘 读 取 文 件, 可 以 使 用 FileInputStream 类, 该 类 是 从 InputStream 中 派 生 出 来 的 简 单 输 入 类 该 类 的 所 有 方 法 都 是 从 InputStream 类 继 承 来 的 为 了 创 建 FileInputStream 类 的 对 象, 可 以 调 用 下 面 两 个 构 造 方 法 : FileInputStream(String name) FileInputStream(File file) 第 一 个 构 造 器 使 用 给 定 的 文 件 名 name 创 建 一 个 FileInputStream 对 象, 第 二 个 构 造 器 使 用 File 对 象 创 建 FileInputStream 对 象 第 251 页

11.3.1 创 建 文 件 输 入 流 例 如 读 取 一 个 名 为 a.txt 的 文 件, 建 立 一 个 文 件 输 入 流 对 象, 如 下 所 示 : FileInputStream fis=new FileInputStream("a.txt"); 或 者 使 用 File 对 象 : File f=new File("a.txt"); FileInputStream fis=new FileInputStream(f); 11.3.2 处 理 IO 异 常 当 使 用 文 件 输 入 流 构 造 器 建 立 通 往 文 件 的 输 入 流 时, 可 能 会 出 现 异 常 例 如, 试 图 要 打 开 的 文 件 可 能 不 存 在, 就 会 出 现 IO 异 常 程 序 必 须 使 用 一 个 try-catch 块 检 测 并 处 理 这 个 异 常 示 例 如 下 : FileInputStream fis=null; try { fis=new FileInputStream("a.txt"); catch (FileNotFoundException e) { // 文 件 不 存 在 异 常 System.out.println("File read error:"+e); 由 于 IO 操 作 对 于 错 误 特 别 敏 感, 所 以 许 多 其 他 的 流 类 构 造 器 和 方 法 也 抛 出 IO 异 常, 你 都 可 以 按 照 上 述 程 序 段 的 方 式 捕 获 处 理 这 些 异 常 11.3.3 从 输 入 流 中 读 取 字 节 输 入 流 的 唯 一 目 的 是 提 供 通 往 数 据 的 通 道, 程 序 可 以 通 过 这 个 通 道 读 取 数 据 Read 方 法 给 程 序 提 供 一 个 从 输 入 流 中 读 取 数 据 的 基 本 方 法 int read( ) 从 输 入 流 中 读 取 数 据 的 下 一 个 字 节 返 回 0 到 255 范 围 内 的 int 字 节 值 如 果 因 为 已 经 到 达 流 末 尾 而 没 有 可 用 的 字 节, 则 返 回 值 -1 int read(byte[] b) 从 输 入 流 中 读 取 一 定 数 量 的 字 节, 并 将 其 存 储 在 缓 冲 区 数 组 b 中 以 整 数 形 式 返 回 实 际 读 取 的 字 节 数 如 果 遇 到 输 入 流 的 结 尾, 则 返 回 -1 int read(byte[] b,int off, int len ) 这 三 个 方 法 提 供 对 输 入 管 道 数 据 的 存 取 简 单 读 方 法 返 回 一 个 int 值, 它 包 含 从 流 里 读 出 的 一 个 字 节 或 者 -1, 其 中 后 者 表 明 文 件 结 束 其 它 两 种 方 法 将 数 据 读 入 到 字 节 数 组 中, 并 返 回 所 第 252 页

读 的 字 节 数 第 三 个 方 法 中 的 两 个 int 参 数 指 定 了 所 要 填 入 的 数 组 的 子 范 围 FileInputStream 流 顺 序 地 读 取 文 件, 只 要 不 关 闭 流, 每 次 调 用 read 方 法 就 顺 序 地 读 取 源 其 余 的 内 容, 直 到 流 的 末 尾 或 流 被 关 闭 11.3.4 关 闭 流 虽 然 Java 在 程 序 结 束 时 自 动 关 闭 所 有 打 开 的 流, 但 是 当 我 们 使 用 完 流 后, 显 式 地 关 闭 任 何 打 开 的 流 仍 是 一 个 良 好 的 习 惯 一 个 被 打 开 的 流 可 能 会 用 尽 系 统 资 源, 这 取 决 于 平 台 和 实 现 如 果 没 有 关 闭 那 些 被 打 开 的 流, 那 么 在 另 一 个 程 序 可 能 无 法 得 到 这 些 资 源 关 闭 输 出 流 的 另 一 个 原 因 是 把 该 缓 冲 区 的 内 容 刷 出, 也 就 是 把 缓 冲 区 的 内 容 写 到 目 的 地 FileInputStream fis = null; try { File f = new File("a.txt"); // 创 建 字 节 流 fis = new FileInputStream(f); // 根 据 文 件 的 大 小, 创 建 相 同 长 度 的 字 节 数 组 byte[] arr = new byte[(int) f.length()]; // 读 取 流 中 的 数 据 到 字 节 数 组 中 fis.read(arr); // 将 读 取 的 数 据 转 换 成 String String msg = new String(arr); System.out.println(msg); catch (IOException e) { e.printstacktrace(); finally { // 判 断 字 节 流 是 否 为 空 if (fis!= null) { try { // 关 闭 字 节 流 fis.close(); catch (IOException e) { e.printstacktrace(); 11.4 FileOutputStream 类 与 FileInputStream 类 相 对 应 的 类 是 FileOutputStream 类 FileOutputStream 提 供 了 基 本 的 文 件 写 入 能 力 FileOutputStream 类 有 两 个 构 造 方 法 : FileOutputStream(String name) 第 253 页

FileOutputStream(File file) FileOutputStream 类 有 三 个 基 本 的 write() 方 法 void write(int n) void write(byte b[]) void write(byte b[], int off, int len) 这 些 方 法 写 输 出 流 和 输 入 一 样, 总 是 尝 试 以 实 际 最 大 的 块 进 行 写 操 作 void close() 当 你 完 成 写 操 作 后, 就 关 闭 输 出 流 如 果 你 有 一 个 流 所 组 成 的 栈, 就 关 闭 栈 顶 部 的 流 这 个 关 闭 操 作 会 关 闭 其 余 的 流 void flush() 操 作 有 时 一 个 输 出 流 在 积 累 了 若 干 次 之 后 才 进 行 真 正 的 写 操 作 flush() 方 法 允 许 你 强 制 执 行 写 11.5 对 象 字 节 流 11.5.1 ObjectInputStream 和 ObjectOutputStream ObjectInputStream 类 和 ObjectOutputStream 类 分 别 是 InputStream 类 和 OutputStream 类 的 子 类 ObjectInputStream 类 和 ObjectOutputStream 类 创 建 的 对 象 被 称 为 对 象 输 入 流 和 对 象 输 出 流 对 象 输 出 流 使 用 writeobject(object obj) 方 法 将 一 个 对 象 obj 写 入 到 一 个 文 件, 对 象 输 入 流 使 用 readobject() 读 取 一 个 对 象 到 程 序 中 ObjectInputStream 类 和 ObjectOutputStream 类 的 构 造 方 法 分 别 是 : ObjectInputStream(InputStream in) ObjectOutputStream(OutputStream out) ObjectOutputStream 的 指 向 的 是 一 个 输 出 流 对 象, 因 此 准 备 将 一 个 对 象 写 入 到 文 件 时, 首 先 用 FileOutputStream 创 建 一 个 文 件 输 出 流, 如 下 所 示 : FileOutputStream fos = null; 第 254 页

ObjectOutputStream oos=null; try { File f = new File("javakc.txt"); // 创 建 字 节 流 fos = new FileOutputStream(f); // 创 建 对 象 流 oos=new ObjectOutputStream(fos); // 将 日 期 对 象 写 入 到 对 象 流 中 Date d=new Date(); oos.writeobject(d); catch (IOException e) { e.printstacktrace(); finally { // 关 闭 流 if (oos!= null) { try { oos.close(); catch (IOException e) { e.printstacktrace(); 同 样 ObjectInputStream 的 指 向 应 当 是 一 个 输 入 流 对 象, 因 此 当 准 备 从 文 件 中 读 入 一 个 对 象 到 程 序 中 时, 首 先 用 FileInputStream 创 建 一 个 文 件 输 入 流, 如 下 列 代 码 所 以 : FileInputStream fis = null; ObjectInputStream ois=null; try { File f = new File("javakc.txt"); // 创 建 字 节 流 fis = new FileInputStream(f); // 创 建 对 象 流 ois=new ObjectInputStream(fis); // 从 对 象 流 中 读 取 出 日 期 对 象 Object o=ois.readobject(); Date d=(date)o; System.out.println(o); catch (Exception e) { e.printstacktrace(); finally { // 关 闭 流 if (ois!= null) { try { ois.close(); catch (IOException e) { e.printstacktrace(); 第 255 页

11.5.2 串 行 化 将 一 个 对 象 存 放 到 某 种 类 型 的 永 久 存 储 器 上 称 为 保 持 如 果 一 个 对 象 可 以 被 存 放 到 磁 盘 或 磁 带 上, 或 者 可 以 发 送 到 另 外 一 台 机 器 并 存 放 到 存 储 器 或 磁 盘 上, 那 么 这 个 对 象 就 被 称 为 可 保 持 的 java.io.serializable 接 口 没 有 任 何 方 法, 它 只 作 为 一 个 标 记 者, 用 来 表 明 实 现 了 这 个 接 口 的 类 可 以 考 虑 串 行 化 类 中 没 有 实 现 Serializable 的 对 象 不 能 保 存 或 恢 复 它 们 的 状 态 当 一 个 对 象 被 串 行 化 时, 只 有 对 象 的 数 据 被 保 存 ; 方 法 和 构 造 函 数 不 属 于 串 行 化 流 如 果 一 个 数 据 变 量 是 一 个 对 象, 那 么 这 个 对 象 的 数 据 成 员 也 会 被 串 行 化 树 或 者 对 象 数 据 的 结 构, 包 括 这 些 子 对 象, 构 成 了 对 象 图 因 为 有 些 对 象 类 所 表 示 的 数 据 在 不 断 地 改 变, 所 以 它 们 不 会 被 串 行 化 ; 例 如, java.io.fileinputstream java.io.fileoutputstream 和 java.lang.thread 等 流 如 果 一 个 可 串 行 化 对 象 包 含 对 某 个 不 可 串 行 化 元 素 的 引 用, 那 么 整 个 串 行 化 操 作 就 会 失 败, 而 且 会 抛 出 一 个 NotSerializableException 如 果 对 象 图 包 含 一 个 不 可 串 行 化 的 引 用, 只 要 这 个 引 用 已 经 用 transient 关 键 字 进 行 了 标 记, 那 么 对 象 仍 然 可 以 被 串 行 化 public class MyClass implements Serializable { public transient Thread mythread; private String customerid; private int total; 11.6 缓 冲 字 节 流 第 256 页

java.io.bufferedinputstream 与 java.io.bufferedoutputstream 可 以 为 InputStream OutputStream 类 增 加 缓 冲 区 功 能 构 建 BufferedInputStream 实 例 时, 需 要 给 定 一 个 InputStream 类 型 的 实 例, 实 现 BufferedInputStream 时, 实 际 上 最 后 是 实 现 InputStream 实 例 同 样, 构 建 BufferedOutputStream 时, 也 需 要 给 定 一 个 OutputStream 实 例, 实 现 BufferedOutputStream 时, 实 际 上 最 后 是 实 现 OutputStream 实 例 BufferedInputStream 的 数 据 成 员 buf 是 一 个 位 数 组, 默 认 为 2048 字 节 当 读 取 数 据 来 源 时, 例 如 文 件,BufferedInputStream 会 尽 量 将 buf 填 满 当 使 用 read() 方 法 时, 实 际 上 是 先 读 取 buf 中 的 数 据, 而 不 是 直 接 对 数 据 来 源 作 读 取 当 buf 中 的 数 据 不 足 时, BufferedInputStream 才 会 再 实 现 给 定 的 InputStream 对 象 的 read() 方 法, 从 指 定 的 装 置 中 提 取 数 据 BufferedOutputStream 的 数 据 成 员 buf 也 是 一 个 位 数 组, 默 认 为 512 字 节 当 使 用 write() 方 法 写 入 数 据 时 实 际 上 会 先 将 数 据 写 到 buf 中, 当 buf 已 满 时 才 会 实 现 给 定 的 OutputStream 对 象 的 write() 方 法, 将 buf 数 据 写 到 目 的 地, 而 不 是 每 次 都 对 目 的 地 作 写 入 的 动 作 下 面 示 例 中, 将 javakc.jpg 复 制 成 temp.jpg: byte[] data = new byte[1024]; File srcfile = new File("D:/javakc.jpg"); File desfile = new File("E:/temp.jpg"); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { bis = new BufferedInputStream(new FileInputStream(srcFile)); bos = new BufferedOutputStream(new FileOutputStream(desFile)); System.out.println(" 复 制 文 件 :" + srcfile.length() + " 字 节 "); // 存 储 读 取 文 件 的 长 度 int len=0; while ( len=(bis.read(data))!= -1) { bos.write(data,0,len); // 将 缓 冲 区 中 的 数 据 全 部 写 出 bos.flush(); catch (Exception e) { e.printstacktrace(); finally { // 关 闭 流 try { if (bis!= null) { 第 257 页

bis.close(); if (bos!= null) { bos.close(); catch (Exception e) { e.printstacktrace(); System.out.println(" 复 制 完 成 "); 为 了 确 保 缓 冲 区 中 的 数 据 一 定 被 写 出 至 目 的 地, 建 议 最 后 执 行 flush() 将 缓 冲 区 中 的 数 据 全 部 写 出 目 的 流 中 11.7 数 据 字 节 流 DataInputStream 类 和 DataOutputStream 类 创 建 的 对 象 被 称 为 数 据 输 入 流 和 数 据 输 出 流 数 据 流 允 许 程 序 按 照 机 器 无 关 的 风 格 读 取 操 作 数 据, 也 就 是 当 我 们 操 作 一 个 数 据 时, 不 必 关 心 这 个 数 值 应 当 是 多 少 个 字 节 // 写 操 作 FileOutputStream fos = null; DataOutputStream dos = null; try { File f = new File("javakc.txt"); // 创 建 字 节 流 fos = new FileOutputStream(f); dos = new DataOutputStream(fos); // 写 入 数 据 dos.writeint(2013); dos.writeutf("java 快 车,ok"); dos.writefloat(100.0f); catch (IOException e) { e.printstacktrace(); finally { // 关 闭 流 if (dos!= null) { try { dos.close(); catch (IOException e) { e.printstacktrace(); // 读 操 作 FileInputStream fis = null; DataInputStream dis = null; 第 258 页

try { File f = new File("javakc.txt"); // 创 建 字 节 流 fis = new FileInputStream(f); dis = new DataInputStream(fis); // 读 出 数 据 int firstint = dis.readint(); String str = dis.readutf(); float secflt = dis.readfloat(); System.out.println(firstInt+","+str+","+secFlt); catch (IOException e) { e.printstacktrace(); finally { // 关 闭 流 if (dis!= null) { try { dis.close(); catch (IOException e) { e.printstacktrace(); 11.8 字 符 流 11.8.1 Reader 和 Writer Java 技 术 使 用 Unicode 来 表 示 字 符 串 和 字 符, 而 且 它 提 供 了 16 位 版 本 的 流, 以 便 用 类 似 的 方 法 来 处 理 字 符 这 些 16 位 版 本 的 流 称 为 读 者 和 作 者 和 流 一 样, 它 们 都 在 java.io 包 中 读 者 和 作 者 中 最 重 要 的 版 本 是 InputStreamReader 和 OutputStreamWriter 这 些 类 用 来 作 为 字 节 流 与 读 者 和 作 者 之 间 的 接 口 当 你 构 造 一 个 InputStreamReader 或 OutputStreamWriter 时, 转 换 规 则 定 义 了 16 位 Unicode 和 其 它 平 台 的 特 定 表 示 之 间 的 转 换 缺 省 情 况 下, 如 果 你 构 造 了 一 个 连 接 到 流 的 读 者 和 作 者, 那 么 转 换 规 则 会 在 使 用 缺 省 平 台 所 定 义 的 字 节 编 码 和 Unicode 之 间 切 换 在 英 语 国 家 中, 所 使 用 的 字 节 编 码 是 :ISO8859-1 第 259 页

字 符 流 在 进 行 中 文 操 作 时 会 更 加 方 便 和 准 确, 比 如 在 读 取 中 文 文 档 内 容 时, 字 节 流 可 能 会 读 取 到 中 文 的 一 半, 而 字 符 流 则 不 会 出 现 这 样 的 问 题 比 如, 我 们 用 字 节 流 读 取 大 文 件, 需 要 通 过 字 节 数 组, 一 批 一 批 将 数 据 读 取 出 来, 代 码 如 下 FileInputStream fis = null; try { File f = new File("javakc.txt"); // 创 建 字 节 流 fis = new FileInputStream(f); // 创 建 字 节 数 组, 每 次 读 取 5 个 字 节 byte[] arr = new byte[5]; // 读 取 的 字 节 长 度 int length=0; while((length=fis.read(arr))!=-1){ // 将 读 取 的 数 据 转 换 成 String String msg = new String(arr,0,length); // 输 出 System.out.print(msg); catch (IOException e) { // 文 件 不 存 在 异 常 System.out.println("File read error:" + e); finally { if (fis!= null) { try { fis.close(); catch (IOException e) { e.printstacktrace(); 当 读 取 英 文 文 档 时, 读 取 的 数 据 没 有 问 题, 结 果 如 下 图 : 但 取 得 中 文 文 档 时, 因 为 将 中 文 字 符 拆 分, 则 出 现 了 编 码 问 题, 结 果 如 下 图 : 第 260 页

如 果 采 用 字 符 流 读 取 数 据, 则 不 会 出 现 上 述 问 题 : FileInputStream fis = null; InputStreamReader reader = null; try { File f = new File("javakc.txt"); // 创 建 字 节 流 fis = new FileInputStream(f); // 创 建 字 符 流 reader = new InputStreamReader(fis); // 创 建 字 符 数 组, 每 次 读 取 5 个 字 符 char[] arr = new char[5]; // 读 取 的 字 符 长 度 int length = 0; while ((length = reader.read(arr))!= -1) { // 将 读 取 的 数 据 转 换 成 String String msg = new String(arr, 0, length); // 输 出 System.out.print(msg); catch (IOException e) { e.printstacktrace(); finally { if (reader!= null) { try { reader.close(); catch (IOException e) { e.printstacktrace(); 运 行 结 果 如 下 : 第 261 页

11.8.2 缓 冲 读 者 和 作 者 因 为 在 各 种 格 式 之 间 进 行 转 换 和 其 它 I/O 操 作 很 类 似, 所 以 在 处 理 大 块 数 据 时 效 率 最 高 在 InputStreamReader 和 OutputStreamWriter 的 结 尾 链 接 一 个 BufferedReader 和 BufferedWriter 是 一 个 好 主 意 记 住 对 BufferedWriter 使 用 flush() 方 法 FileInputStream fis = null; InputStreamReader reader = null; BufferedReader buf = null; try { File f = new File("javakc.txt"); // 创 建 字 节 流 fis = new FileInputStream(f); // 创 建 字 符 流 reader = new InputStreamReader(fis); buf = new BufferedReader(reader); String s = null; // 读 取 流 中 的 数 据 ( 按 行 读 取 ) while ((s = buf.readline())!= null) { System.out.println(s); catch (IOException e) { e.printstacktrace(); finally { if (buf!= null) { try { buf.close(); catch (IOException e) { e.printstacktrace(); 11.9 随 机 访 问 文 件 你 经 常 会 发 现 你 只 想 读 取 文 件 的 一 部 分 数 据, 而 不 需 要 从 头 至 尾 读 取 整 个 文 件 你 可 能 想 访 问 一 个 作 为 数 据 库 的 文 本 文 件, 此 时 你 会 移 动 到 某 一 条 记 录 并 读 取 它 的 数 据, 接 着 移 动 到 另 一 个 记 录, 然 后 再 到 其 他 记 录 每 一 条 记 录 都 位 于 文 件 的 不 同 部 分 Java 编 程 语 言 提 供 了 一 个 RandomAccessFile 类 来 处 理 这 种 类 型 的 输 入 输 出 你 可 以 用 如 下 两 种 构 造 方 法 来 打 开 一 个 随 机 存 取 文 件 : RandomAccessFile(String name, String mode); RandomAccessFile(File file, String mode); 第 262 页

mode 参 数 决 定 了 你 对 这 个 文 件 的 存 取 是 只 读 (r) 还 是 读 / 写 (rw) 例 如, 你 可 以 打 开 一 个 打 开 一 个 数 据 库 文 件 并 准 备 更 新 : RandomAccessFile raf; raf = new RandomAccessFile("javakc.txt","rw"); RandomAccessFile 对 象 按 照 与 数 据 输 入 输 出 对 象 相 同 的 方 式 来 读 写 信 息 你 可 以 访 问 在 DataInputStrem 和 DataOutputStream 中 所 有 的 read() 和 write() 操 作 Java 编 程 语 言 提 供 了 若 干 种 方 法, 用 来 帮 助 你 在 文 件 中 移 动 long getfilepointer() 返 回 文 件 指 针 的 当 前 位 置 void seek(long pos) 设 置 文 件 指 针 到 给 定 的 绝 对 位 置 这 个 位 置 是 按 照 从 文 件 开 始 的 字 节 偏 移 量 给 出 的 位 置 0 标 志 文 件 的 开 始 long length() 返 回 文 件 的 长 度 位 置 length() 标 志 文 件 的 结 束 在 文 件 末 尾, 写 入 字 符 : RandomAccessFile raf = null; try { File f = new File("javakc.txt"); raf = new RandomAccessFile(f, "rw"); raf.seek(f.length()); raf.write("welcome to Javakc!".getBytes()); catch (IOException e) { e.printstacktrace(); finally { if (raf!= null) { try { raf.close(); catch (IOException e) { e.printstacktrace(); 第 263 页

11.10 学 习 目 标 1. 理 解 File 类 封 装 的 是 文 件 的 抽 象 路 径 名, 并 且 不 能 操 作 文 件 的 内 容 2. 熟 练 使 用 File 类 的 主 要 方 法 ( 课 堂 上 老 师 讲 过 的 方 法 ) 3. 理 解 相 对 路 径 和 绝 对 路 径 4. File 类 的 Api 中, 有 的 返 回 文 件 路 径 名, 有 的 返 回 File, 理 解 其 本 质 是 一 样 的 比 如 getparent( ) 和 getparentfile( ),list( ) 和 listfiles( ) 5. 理 解 File 类 的 Api 中, 有 的 方 法 需 要 区 分 此 File 是 文 件 还 是 目 录 也 就 是 说 文 件 和 目 录 要 区 分 对 待, 比 如 list( ), 如 果 是 文 件 调 用 此 方 法 返 回 null, 如 果 目 录 调 用 此 方 法 返 回 数 组 11.11 作 业 1. 递 归 展 示 目 录 的 结 构 第 264 页

12 多 线 程 12.1 进 程 与 线 程 12.1.1 概 念 几 乎 每 种 操 作 系 统 都 支 持 进 程 的 概 念 进 程 就 是 在 某 种 程 度 上 相 互 隔 离 的 独 立 运 行 的 程 序, 每 一 个 进 程 都 有 自 己 独 立 的 内 存 空 间 比 如 IE 浏 览 器 程 序, 每 打 开 一 个 IE 浏 览 器 窗 口, 就 启 动 一 个 新 的 进 程 在 java 中, 我 们 执 行 java.exe 程 序, 就 启 动 一 个 独 立 的 Java 虚 拟 机 进 程, 该 进 程 的 任 务 就 是 解 析 并 执 行 Java 程 序 代 码 线 程 是 指 进 程 中 的 一 个 执 行 流 程, 一 个 进 程 可 以 由 多 个 线 程 组 成, 即 一 个 进 程 中 可 以 同 时 运 行 多 个 不 同 的 线 程, 它 们 分 别 执 行 不 同 的 任 务 当 进 程 内 的 多 个 线 程 同 时 运 行 时, 这 种 运 行 方 式 成 为 并 发 运 行 线 程 又 被 称 为 轻 量 级 进 程, 它 和 进 程 一 样 拥 有 独 立 的 执 行 控 制, 由 操 作 系 统 进 行 调 度 线 程 和 进 程 的 区 别 是 : 每 个 进 程 都 有 独 立 的 代 码 和 存 储 空 间 ( 进 程 上 下 文 ), 进 程 切 换 的 开 销 大 线 程 没 有 独 立 的 存 储 空 间, 而 是 和 所 属 进 程 中 其 他 的 线 程 共 享 代 码 和 存 储 空 间, 但 每 个 线 程 有 独 立 的 运 行 栈 和 程 序 计 数 器, 因 此 线 程 切 换 的 开 销 较 小 多 进 程 在 操 作 系 统 中 能 同 时 运 行 多 个 任 务 ( 程 序 ), 也 称 多 任 务 多 线 程 在 同 一 应 用 程 序 中 有 多 个 顺 序 流 同 时 执 行 许 多 服 务 器 程 序, 如 数 据 库 服 务 器 和 Web 服 务 器, 都 支 持 并 发 运 行, 这 些 服 务 器 能 同 时 响 应 来 自 不 同 客 户 的 请 求 12.1.2 java 线 程 的 运 行 机 制 在 java 虚 拟 机 进 程 中, 执 行 程 序 代 码 的 任 务 是 由 线 程 来 完 成 的 每 个 线 程 都 有 一 个 独 立 的 程 序 计 数 器 和 方 法 调 用 栈 程 序 计 数 器 : 也 称 为 PC 寄 存 器, 当 线 程 执 行 一 个 方 法 时, 程 序 计 数 器 指 向 方 法 区 中 下 一 条 要 执 行 的 字 节 码 指 令 方 法 调 用 栈 : 简 称 方 法 栈, 用 来 跟 踪 线 程 运 行 中 一 系 列 的 方 法 调 用 过 程, 栈 中 的 元 素 称 为 栈 帧, 每 当 线 程 调 用 一 个 方 法 的 时 候, 就 会 向 方 法 栈 压 入 一 个 新 帧 帧 用 来 存 储 方 法 的 参 数 局 部 变 量 和 运 算 过 程 中 的 临 时 数 据 栈 帧 由 以 下 三 个 部 分 组 成 : 局 部 变 量 区 : 存 放 局 部 变 量 和 方 法 参 数 第 265 页

操 作 数 栈 : 是 线 程 的 工 作 区, 用 来 存 放 运 算 过 程 中 生 成 的 临 时 数 据 栈 数 据 区 : 为 线 程 执 行 指 令 提 供 相 关 的 信 息, 包 括 如 何 定 位 到 位 于 堆 区 和 方 法 区 的 特 定 数 据, 以 及 如 何 正 常 退 出 方 法 或 者 异 常 中 断 方 法 每 当 用 Java 命 令 启 动 一 个 Java 虚 拟 机 进 程 时,Java 虚 拟 机 都 会 创 建 一 个 主 线 程, 该 线 程 从 程 序 入 口 main() 方 法 开 始 执 行 以 下 面 程 序 为 例, 介 绍 线 程 的 运 行 过 程 public class Test { private int num; // 实 例 变 量 public int add(){ int b=0; // 局 部 变 量 num++; b=num; return b; public static void main(string[] args) { Test t=new Test(); // 局 部 变 量 int num=0; // 局 部 变 量 num=t.add(); System.out.println(num); 主 线 程 从 main() 方 法 的 程 序 代 码 开 始 运 行, 当 它 开 始 执 行 method() 方 法 的 a++ 操 作 时, 运 行 时 数 据 区 的 状 态 如 下 图 所 示 Java 栈 区 add() 方 法 的 栈 帧 局 部 变 量 num 堆 区 Test 对 象 实 例 变 量 num 方 法 区 Test 类 的 数 据 结 构 add() 方 法 的 数 据 结 构 main() 方 法 的 栈 帧 局 部 变 量 t num++ 操 作 的 指 令 局 部 变 量 num 主 线 程 的 方 法 帧 主 线 程 的 的 程 序 计 数 器 main b=a 方 法 操 的 作 字 的 节 指 码 令 当 主 线 程 执 行 a++ 操 作 时, 它 能 根 据 method() 方 法 的 栈 帧 的 栈 数 据 区 中 的 有 关 信 息, 正 确 地 定 位 到 堆 区 的 Test 对 象 的 实 例 变 量 num, 并 把 它 的 值 加 1 当 add() 方 法 执 行 完 毕 后, 它 的 栈 帧 就 会 从 方 法 栈 中 弹 出, 它 的 局 部 变 量 b 结 束 生 命 周 期 main() 方 法 的 栈 帧 就 成 为 当 前 帧, 主 线 程 继 续 执 行 main() 方 法 方 法 区 存 放 了 线 程 所 执 行 的 字 节 码 指 令, 堆 区 存 放 了 线 程 所 操 作 的 数 据 ( 以 对 象 的 形 式 存 放 ), Java 栈 区 则 是 线 程 的 工 作 区, 保 存 线 程 的 运 行 状 态 第 266 页

另 外, 计 算 机 机 器 指 令 的 真 正 执 行 者 是 CPU, 线 程 必 须 获 得 CPU 的 使 用 权, 才 能 执 行 一 条 指 令 下 图 中 显 示 了 线 程 运 行 中 需 要 使 用 的 计 算 机 CPU 和 内 存 资 源 CPU 堆 区 的 数 据 方 法 区 的 代 码 Java 栈 区 的 方 法 调 用 栈 程 在 Java 的 方 法 中, 可 以 通 过 Thread 类 的 currentthread 方 法 得 到 正 在 调 用 该 方 法 的 线 public class Test { public static void main(string[] args) { Thread t=thread.currentthread(); System.out.println(" 调 用 main 方 法 的 线 程 名 字 是 :"+t.getname()); 虚 拟 机 为 调 用 main 方 法 的 线 程 命 名 为 main 12.2 线 程 的 创 建 和 启 动 Java 在 代 码 中 对 线 程 进 行 了 支 持, 程 序 员 可 以 创 建 自 己 的 线 程, 它 将 和 主 线 程 并 发 运 行 创 建 线 程 有 两 种 方 式 : 扩 展 Thread 类 实 现 Runnable 接 口 12.2.1 扩 展 Thread 类 Thread 类 代 表 线 程 类, 它 的 最 主 要 的 两 个 方 法 是 : run() 包 含 线 程 运 行 时 所 执 行 的 代 码 start() 用 于 启 动 线 程 开 发 线 程 类 只 需 要 继 承 Thread 类, 覆 盖 Thread 类 的 run() 方 法 即 可 在 Thread 类 中, run() 方 法 的 定 义 如 下 : public void run() 该 方 法 没 有 声 明 抛 出 任 何 异 常, 根 据 方 法 覆 盖 的 规 则,Thread 子 类 的 run() 方 法 也 不 能 声 明 抛 出 任 何 异 常 示 例 如 下 : 第 267 页

public class MyThread extends Thread { public void run(){ // 线 程 体 内 的 实 现 for(int i=0;i<100;i++){ System.out.println(i); public static void main(string[] args) { MyThread mt=new MyThread(); mt.start(); // 启 动 MyThread 线 程 当 执 行 java MyThread 命 令 时,Java 虚 拟 机 首 先 创 建 并 启 动 主 线 程 主 线 程 的 任 务 是 执 行 main 方 法,main 方 法 创 建 了 一 个 MyThread 对 象, 然 后 调 用 它 的 start() 方 法 启 动 MyThread 线 程 MyThread 线 程 的 任 务 是 执 行 它 的 run() 方 法 主 线 程 和 自 定 义 线 程 并 发 运 行 在 下 面 的 例 子 中,main 方 法 创 建 并 启 动 两 个 MyThread 线 程 : public class MyThread extends Thread { public void run(){ // 线 程 体 内 的 实 现 for(int i=0;i<100;i++){ // 打 印 线 程 的 名 字 System.out.println(this.getName()+":"+i); public static void main(string[] args) { MyThread mt=new MyThread(); MyThread mt2=new MyThread(); mt.start(); // 启 动 MyThread 线 程 mt2.start(); // 启 动 MyThread 线 程 执 行 结 果 : Thread-1:7 Thread-1:8 Thread-1:9 Thread-1:10 Thread-1:11 Thread-0:1 Thread-1:12 Thread-1:13 Thread-1:14 Thread-0:2 Thread-0:3 第 268 页

Thread-0:4 当 主 线 程 执 行 main() 方 法 时, 会 创 建 两 个 MyThread 对 象, 然 后 启 动 两 个 MyThread 线 程 在 Java 虚 拟 机 钟 有 两 个 线 程 并 发 执 行 MyThread 对 象 的 run() 方 法 在 两 个 线 程 各 自 的 方 法 栈 中 都 有 代 表 run() 方 法 的 栈 帧, 在 这 个 帧 中 存 放 了 局 部 变 量 num, 也 就 是 每 个 线 程 都 拥 有 自 己 的 局 部 变 量 num, 它 们 都 分 别 从 0 增 加 到 100 因 为 Thread 类 中 有 getname() 方 法,MyThread 类 继 承 了 Thread 类, 所 以 在 代 码 中 可 以 使 用 this.getname() 得 到 当 前 线 程 的 名 字 mt 对 象 启 动 线 程 的 名 字 是 Thread-0,mt2 对 象 启 动 线 程 的 名 字 是 Thread-1 从 运 行 结 果 上, 我 们 可 以 看 到 两 个 线 程 交 替 运 行, 两 个 线 程 轮 流 得 到 CPU 的 运 行 时 间 片 sleep 方 法 Thread 类 中 有 一 个 sleep 方 法, 在 指 定 的 毫 秒 数 内 让 当 前 正 在 执 行 的 线 程 休 眠 ( 暂 停 执 行 ), 就 是 线 程 睡 眠 一 定 的 时 间, 也 就 是 交 出 CPU 时 间 片, 根 据 参 数 来 决 定 暂 停 时 间 长 度, 让 给 等 待 序 列 中 的 下 一 个 线 程 Sleep 方 法 抛 出 InterruptedException public class MyThread extends Thread { public void run(){ for(int i=0;i<100;i++){ System.out.println(this.getName()+":"+i); try { // 让 当 前 线 程 休 眠 100 毫 秒 sleep(100); catch (InterruptedException e) { e.printstacktrace(); public static void main(string[] args) { MyThread mt=new MyThread(); MyThread mt2=new MyThread(); mt.start(); mt2.start(); 运 行 结 果 : Thread-0:0 Thread-1:0 Thread-1:1 Thread-0:1 Thread-1:2 Thread-0:2 Thread-1:3 Thread-0:3 第 269 页

Thread-1:4 Thread-0:4 Thread-1:5 当 Thread-0 线 程 执 行 打 印 后, 休 眠 100 毫 秒, 也 就 失 去 了 CPU 的 时 间 片,Thread-1 线 程 就 得 到 了 CPU 的 时 间 片, 执 行 了 打 印 操 作, 也 休 眠 100 毫 秒,100 毫 秒 后,Thread-0 线 程 先 恢 复 到 可 运 行 状 态, 接 着 运 行, 这 样 两 个 线 程 交 替 运 行 不 要 随 便 覆 盖 Thread 类 的 start() 方 法 创 建 一 个 线 程 对 象 后, 线 程 并 不 自 动 开 始 运 行, 必 须 调 用 它 的 start() 方 法 才 能 启 动 线 程 JDK 为 Thread 类 的 start() 方 法 提 供 了 默 认 的 实 现, 启 动 线 程 后 调 用 run() 方 法 如 果 不 通 过 start() 方 法 启 动 线 程, 而 是 直 接 调 用 run() 方 法, 那 只 是 普 通 的 方 法 调 用, 并 不 能 启 动 线 程 看 看 如 下 代 码 : public class MyThread extends Thread { public void run(){ for(int i=0;i<100;i++){ try { sleep(100); catch (InterruptedException e) { e.printstacktrace(); System.out.println(this.getName()+":"+i); public void start(){ run(); public static void main(string[] args) { MyThread mt=new MyThread(); MyThread mt2=new MyThread(); mt.start(); mt2.start(); 运 行 结 果 : Thread-0:0 Thread-0:1 Thread-0:2 Thread-0:99 Thread-1:0 Thread-1:1 Thread-1:3 Thread-1:4 当 主 线 程 main 执 行 start() 方 法 时,start() 方 法 并 没 有 启 动 MyThread 线 程, 而 是 直 第 270 页

接 调 用 了 run() 方 法, 这 只 是 普 通 的 方 法 调 用 第 一 个 run() 方 法 执 行 完 成 后, 才 开 始 调 用 第 二 个 run() 方 法, 并 没 有 出 现 两 个 线 程 并 发 运 行 的 情 况 所 以, 在 Thread 子 类 中 不 要 随 意 覆 盖 start() 方 法, 假 如 一 定 要 覆 盖 start() 方 法, 那 么 应 该 先 调 用 super.start() 方 法 public class MyThread extends Thread { public static int count=0; public void run(){ for(int i=0;i<100;i++){ try { sleep(100); catch (InterruptedException e) { e.printstacktrace(); public void start(){ super.start(); System.out.println(" 第 "+(++count)+" 线 程 启 动 了 "); 一 个 线 程 只 能 被 启 动 一 次 一 个 线 程 只 能 被 启 动 一 次, 以 下 代 码 视 图 两 次 启 动 MyThread 线 程 MyThread mt=new MyThread(); mt.start(); mt.start(); // 抛 出 IllegalThreadStateException 异 常 第 二 次 调 用 mt.start() 方 法 时, 会 抛 出 java.lang.illegalthreadstateexception 异 常 12.2.2 实 现 Runnable 接 口 Java 类 不 允 许 一 个 类 继 承 多 个 类, 因 此 一 旦 一 个 类 继 承 了 Thread 类, 就 不 能 再 继 承 其 他 的 类, 为 了 解 决 这 一 问 题,Java 提 供 了 java.lang.runnable 接 口, 它 有 一 个 run() 方 法, 定 义 如 下 : public void run() 示 例 中 MyThread 类 实 现 了 Runnable 接 口,run() 方 法 表 示 线 程 所 执 行 的 代 码 public class MyThread implements Runnable { int count=0; public void run(){ while(true){ System.out.println(Thread.currentThread().getName()+":"+count++); if(count>10){ 第 271 页

break;// 当 count 大 于 10 的 时 候, 循 环 结 束 try { Thread.sleep(100); catch (InterruptedException e) { e.printstacktrace(); public static void main(string[] args) { MyThread mt=new MyThread(); Thread t1=new Thread(mt); Thread t2=new Thread(mt); t1.start(); t2.start(); 在 Thread 类 中 定 义 了 如 下 形 式 的 构 造 方 法 : public Thread(Runnable runnable) 当 线 程 启 动 时, 将 执 行 参 数 runnable 所 引 用 对 象 的 run() 方 法 其 实 Thread 类 也 实 现 了 Runnable 接 口 在 示 例 中, 主 线 程 创 建 了 t1 和 t2 两 个 线 程 对 象 启 动 t1 和 t2 线 程 将 执 行 MyThread 对 象 的 run() 方 法 t1 和 t2 共 享 同 一 个 MyThread 对 象, 在 执 行 run() 方 法 时 将 操 作 同 一 个 实 例 变 量 count 打 印 结 果 如 下 : Thread-0:0 Thread-1:1 Thread-0:2 Thread-1:9 Thread-0:10 Thread-1:11 将 main() 做 如 下 修 改 : public static void main(string[] args) { MyThread mt1=new MyThread(); MyThread mt2=new MyThread(); Thread t1=new Thread(mt1); Thread t2=new Thread(mt2); t1.start(); t2.start(); t1 和 t2 线 程 启 动 后, 将 分 别 执 行 mt1 和 mt2 变 量 所 引 用 的 MyThread 对 象 的 run() 方 法, 因 此 t1 和 t2 线 程 操 作 不 同 的 MyThread 对 象 的 实 例 变 量 count 运 行 结 果 如 下 : Thread-0:0 Thread-1:0 第 272 页

Thread-0:1 Thread-1:1 Thread-0:2 Thread-0:8 Thread-1:9 Thread-0:9 Thread-0:10 Thread-1:10 12.3 线 程 的 状 态 转 换 12.3.1 新 建 状 态 (New) 用 new 语 句 创 建 的 线 程 对 象 处 于 新 建 状 态, 此 时 和 其 他 Java 对 象 一 样, 仅 仅 在 堆 区 中 被 分 配 了 内 存 12.3.2 就 绪 状 态 (Runnable) 当 一 个 线 程 对 象 创 建 后, 其 他 线 程 调 用 它 的 start() 方 法, 该 线 程 就 进 入 了 就 绪 状 态, Java 虚 拟 机 会 为 它 创 建 方 法 调 用 栈 和 程 序 计 数 器 处 于 这 个 状 态 的 线 程 位 于 可 运 行 池 中, 等 待 获 得 CPU 的 使 用 权 12.3.3 运 行 状 态 (Running) 处 于 这 个 状 态 的 线 程 占 用 CPU, 执 行 程 序 代 码 在 并 发 运 行 环 境 中, 如 果 计 算 机 只 有 一 个 CPU, 那 么 任 何 时 刻 只 会 有 一 个 线 程 处 于 这 个 状 态 如 果 计 算 机 有 多 个 CPU, 那 么 同 一 时 刻 可 以 让 几 个 线 程 占 用 不 同 的 CPU, 使 它 们 都 处 于 运 行 状 态 只 有 处 于 就 绪 状 态 的 线 程 才 有 机 会 转 到 运 行 状 态 12.3.4 阻 塞 状 态 (Blocked) 阻 塞 状 态 是 指 线 程 因 为 某 些 原 因 放 弃 CPU, 暂 时 停 止 运 行 当 线 程 处 于 阻 塞 状 态 时,Java 虚 拟 机 不 会 给 线 程 分 配 CPU, 直 到 线 程 重 新 进 入 就 绪 状 态, 才 有 机 会 转 到 运 行 状 态 阻 塞 状 态 可 以 分 为 以 下 3 种 : 位 于 对 象 等 待 池 中 的 阻 塞 状 态 : 当 线 程 处 于 运 行 状 态 时, 如 果 执 行 了 wait() 方 法,Java 虚 拟 机 就 会 把 线 程 放 到 等 待 池 中 位 于 对 象 锁 池 中 的 阻 塞 状 态 : 当 线 程 处 于 运 行 状 态 时, 试 图 获 得 某 个 对 象 的 同 步 锁 时, 如 果 第 273 页

该 对 象 的 同 步 锁 已 经 被 其 他 线 程 占 用,Java 虚 拟 机 就 会 把 这 个 线 程 放 到 锁 池 中 其 他 的 阻 塞 状 态 : 当 前 线 程 执 行 了 sleep() 方 法, 或 者 调 用 了 其 他 线 程 的 join() 方 法, 或 者 发 出 了 I/O 请 求 时, 就 会 进 入 这 个 状 态 当 一 个 线 程 执 行 System.out.println() 或 者 System.in.read() 方 法 时, 就 会 发 出 一 个 I/O 请 求, 该 线 程 放 弃 CPU, 进 入 阻 塞 状 态, 知 道 I/O 处 理 完 毕, 该 线 程 才 会 恢 复 运 行 import java.io.ioexception; class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.println(getName() + ":" + count++); try { Thread.sleep(3000); catch (InterruptedException e) { e.printstacktrace(); class YourThread extends Thread { public void run() { while (true) { try { System.out.println(" 等 待 用 户 输 入 "); int data = System.in.read(); System.out.println(getName() + " 用 户 输 入 了 :"+ data); catch (IOException e) { e.printstacktrace(); class Client { public static void main(string[] arr) { MyThread mt=new MyThread(); YourThread yt=new YourThread(); mt.start(); yt.start(); 运 行 结 果 : Thread-0:0 等 待 用 户 输 入 Thread-0:1 第 274 页

Thread-0:2 a Thread-1 用 户 输 入 了 :97 等 待 用 户 输 入 Thread-1 用 户 输 入 了 :13 等 待 用 户 输 入 Thread-1 用 户 输 入 了 :10 等 待 用 户 输 入 Thread-0:3 Thread-0:4 在 上 面 的 示 例 中, 主 线 程 main 启 动 了 mt 和 yt 两 个 线 程 mt 线 程 启 动 后, 运 行 了 一 次, 进 入 休 眠 的 阻 塞 状 态 yt 线 程 得 到 时 间 片, 开 始 运 行 输 出 了 等 待 用 户 输 入, 之 后 进 入 了 I/O 请 求 的 阻 塞 状 态, 等 待 用 户 的 输 入 mt 线 程 又 得 到 时 间 片, 执 行 后 又 休 眠, 这 样 重 复 了 两 次 用 户 输 入 了 a 和 回 车,yt 由 阻 塞 状 态 变 为 运 行 状 态, 连 续 打 印 出 用 户 输 入 的 值 后, 又 进 入 I/O 请 求 的 阻 塞 状 态 mt 线 程 又 得 到 时 间 片, 继 续 运 行 12.3.5 死 亡 状 态 (Dead) 当 线 程 退 出 run( 方 法 ) 时, 就 进 入 死 亡 状 态, 表 示 该 线 程 结 束 生 命 周 期 线 程 有 可 能 是 正 常 执 行 完 run() 方 法 而 退 出 的, 也 有 可 能 是 遇 到 异 常 而 退 出 不 管 线 程 正 常 结 束 还 是 异 常 结 束, 都 不 会 对 其 他 线 程 造 成 影 响 在 下 面 的 示 例 中,MyThread 线 程 在 运 行 时 因 为 抛 出 RuntimeException 异 常 而 结 束, 此 时 主 线 程 main 正 常 运 行 class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.println(getName() + ":" + count++); try { Thread.sleep(3000); if(count==3){ throw new RuntimeException(); catch (InterruptedException e) { e.printstacktrace(); 第 275 页

class Client { public static void main(string[] arr) throws InterruptedException { MyThread mt=new MyThread(); mt.start(); while(true){ System.out.println(Thread.currentThread().getName()+":is alive===="+mt.isalive()); Thread.sleep(3000); Thread 类 的 isalive() 方 法 能 判 断 一 个 线 程 是 否 活 着, 当 线 程 处 于 死 亡 状 态 活 着 新 建 状 态 时, 该 方 法 返 回 false, 在 其 余 状 态 下, 该 方 法 返 回 true 运 行 结 果 : Thread-0:0 main:is alive====true main:is alive====true Thread-0:1 main:is alive====true Thread-0:2 main:is alive====true Exception in thread "Thread-0" java.lang.runtimeexception at MyThread.run(Client.java:13) main:is alive====false main:is alive====false 12.4 线 程 的 调 度 计 算 机 通 常 只 有 一 个 CPU, 在 任 何 时 刻 只 能 执 行 一 条 机 器 指 令, 每 个 线 程 只 有 获 得 CPU 的 使 用 权 才 能 执 行 指 令 所 谓 多 线 程 的 并 发, 其 实 是 指 宏 观 上 看, 各 个 线 程 轮 流 获 得 CPU 的 使 用 权, 分 别 执 行 各 自 的 任 务 在 可 运 行 池 中, 会 有 多 个 处 于 就 绪 状 态 的 线 程 等 待 CPU,Java 虚 拟 机 的 一 项 任 务 就 是 负 责 线 程 的 调 度 线 程 的 调 度 是 指 按 照 特 定 的 机 制 为 多 个 线 程 分 配 CPU 的 使 用 权 有 两 种 调 度 模 型 : 分 时 调 度 模 型 和 抢 占 式 调 度 模 型 分 时 调 度 模 型 是 指 让 所 有 线 程 轮 流 获 得 CPU 的 使 用 权, 并 且 平 均 分 配 每 个 线 程 占 用 CPU 的 时 间 片 Java 虚 拟 机 采 用 抢 占 式 调 度 模 型, 是 指 优 先 让 可 运 行 池 中 优 先 级 高 的 线 程 占 用 CPU, 如 果 可 运 行 池 中 线 程 的 优 先 级 相 同, 那 么 就 随 机 选 择 一 个 线 程, 使 其 占 用 CPU 处 于 运 行 状 态 的 线 程 会 一 直 运 行, 直 至 它 不 得 不 放 弃 CPU 一 个 线 程 会 因 为 一 下 原 因 而 放 弃 CPU: Java 虚 拟 机 让 当 前 线 程 暂 时 放 弃 CPU, 转 到 就 绪 状 态, 使 其 他 的 线 程 获 得 运 行 机 会 当 前 线 程 因 为 某 些 原 因 而 进 入 阻 塞 状 态 第 276 页

线 程 运 行 结 束 值 得 注 意 的 是, 线 程 的 调 度 不 是 跨 平 台 的, 它 不 仅 取 决 于 Java 虚 拟 机, 还 依 赖 操 作 系 统 在 某 些 操 作 系 统 中, 只 要 运 行 中 的 线 程 没 有 遇 到 阻 塞, 也 会 在 运 行 一 段 时 间 后 放 弃 CPU, 给 其 他 线 程 运 行 的 机 会 在 java 中, 同 时 启 动 多 个 线 程 后, 不 能 保 证 各 个 线 程 轮 流 获 得 均 等 的 CPU 时 间 片, 从 之 前 的 例 子 中, 大 家 可 以 体 会 到 这 一 点 一 个 线 程 运 行 机 毫 秒 后, 就 放 弃 的 CPU 时 间 片, 另 一 个 线 程 就 得 到 了 CPU 时 间 片, 各 个 线 程 交 替 运 行 以 下 程 序 可 以 证 明 这 一 点 : class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.print(getName() + ":" + count++ +","); class Client { public static void main(string[] arr){ MyThread mt=new MyThread(); MyThread mt2=new MyThread(); mt.start(); mt2.start(); 两 个 线 程 抢 占 时 间 片 的 结 果 如 下 : Thread-0:0,Thread-0:1,Thread-0:2,,Thread-0:7,Thread-0:8,Thread -0:9, Thread-1:0, Thread-0:10,Thread-1:1,Thread-0:11,Thread-0:12,Thread-0:13,Thread-1:2, Thread-0:14, Thread-1:3,Thread-0:15,Thread-1:4,Thread-0:16,Thread-1:5, Thread-0:17,Thread-0:18,Thread-0:19,Thread-0:20,Thread-0:21,Thread-0:2 2,Thread-0:23, Thread-1:6,Thread-1:7,Thread-1:8,Thread-1:9,Thread-1:10, Thread-0:24,Thread-0:25,Thread-0:26,Thread-0:27, Thread-1:11,Thread-1:12,Thread-1:13,,Thread-1:16,Thread-1:17,Thr ead-0:28,thread-1:18, 如 果 通 过 代 码, 希 望 明 确 地 让 一 个 线 程 给 另 外 一 个 线 程 运 行 的 机 会, 可 以 采 用 以 下 方 法 之 一 : 调 整 各 个 线 程 的 优 先 级 让 处 于 运 行 状 态 的 线 程 调 用 Thread.sleep() 方 法 让 处 于 运 行 状 态 的 线 程 调 用 Thread.yield() 方 法 第 277 页

让 处 于 运 行 状 态 的 线 程 调 用 另 一 个 线 程 的 join() 方 法 12.4.1 调 整 各 个 线 程 的 优 先 级 所 有 处 于 就 绪 状 态 的 线 程 根 据 优 先 级 存 放 在 可 运 行 池 中, 优 先 级 低 的 线 程 获 得 较 少 的 运 行 机 会, 优 先 级 高 的 线 程 获 得 较 多 的 运 行 机 会 Thread 类 的 setpriority(int) 和 getpriority() 方 法 分 别 用 来 设 置 优 先 级 和 读 取 优 先 级 优 先 级 用 整 数 表 示, 取 值 范 围 是 1~10,Thread 类 有 以 下 3 个 静 态 常 量 MAX_PRIORITY: 取 值 为 10, 表 示 最 高 优 先 级 MIN_PRIORITY: 取 值 为 1, 表 示 最 低 优 先 级 NORM_PRIORITY: 取 值 为 5, 表 示 默 认 的 优 先 级 修 改 之 前 的 代 码, 分 别 设 置 两 个 线 程 的 优 先 级 class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.print(getName() + ":" + count++ +","); class Client { public static void main(string[] arr){ MyThread mt=new MyThread(); MyThread mt2=new MyThread(); mt.setpriority(thread.max_priority);// 设 置 最 高 的 优 先 级 mt2.setpriority(thread.min_priority);// 设 置 最 低 的 优 先 级 mt.start(); mt2.start(); 由 于 mt(thread-0) 线 程 的 优 先 级 高 于 mt2(thread-1) 线 程 的 优 先 级, 因 此 前 者 优 先 获 得 CPU 的 使 用 权, 运 行 结 果 如 下 : Thread-0:0,Thread-1:0,Thread-0:1, Thread-1:1, Thread-0:2, Thread-1:2, Thread-0:3,Thread-0:4,Thread-0:5,Thread-0:6,Thread-0:7,Thread-0:8,Thre ad-0:9, Thread-0:305,Thread-0:306,Thread-0:307,Thread-0:308,Thread-0:309,Threa d-0:310, 第 278 页

Thread-1:3, Thread-0:311, Thread-1:4, Thread-0:312,Thread-0:313,Thread-0:314,Thread-0:315,Thread-0:316,Threa d-0:317, Thread-0:995,Thread-0:996,Thread-0:997,Thread-0:998,Thread-0:999,Threa d-0:1000, Thread-1:21,Thread-1:22,Thread-1:23,Thread-1:24,Thread-1:25,Thread-1:2 6, Thread-1:996,Thread-1:997,Thread-1:998,Thread-1:999,Thread-1:1000, 在 两 个 线 程 同 时 运 行 的 时 候, 每 当 mt2(thread-1) 线 程 获 得 时 间 片 后, 往 往 只 运 行 一 次, 就 放 弃 了 CPU 的 时 间 片, 所 以 mt(thread-0) 线 程 最 先 运 行 完 毕 如 果 不 设 置 线 程 的 优 先 级, 线 程 默 认 的 优 先 级 为 5 值 得 注 意 的 是, 尽 管 Java 提 供 了 10 个 优 先 级, 但 它 与 多 数 操 作 系 统 都 不 能 很 好 地 映 射 比 如 Windows2000 有 7 个 优 先 级, 并 且 不 是 固 定 的, 而 Sun 公 司 的 Solaris 操 作 系 统 有 2 的 31 次 方 个 优 先 级 如 果 希 望 程 序 能 移 植 到 各 个 操 作 系 统 中, 应 该 确 保 在 设 置 线 程 的 优 先 级 时, 只 使 用 MAX_PRIORITY MIN_PRIORITY NORM_PRIORITY 这 3 个 优 先 级 这 样 才 能 保 证 在 不 同 的 操 作 系 统 中, 对 同 样 优 先 级 的 线 程 采 用 同 样 的 调 度 方 式 12.4.2 线 程 睡 眠 :Thread.sleep() 方 法 当 一 个 线 程 在 运 行 过 程 中 执 行 了 sleep() 方 法 时, 它 就 会 放 弃 CPU, 转 到 阻 塞 状 态 下 面 示 例 中 每 执 行 一 次 循 环, 就 睡 眠 1000 毫 秒 class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.print(getName() + ":" + count++); try { sleep(1000);// 睡 眠 1 秒 钟 catch (InterruptedException e) { e.printstacktrace(); class Client { public static void main(string[] arr) { MyThread mt=new MyThread(); mt.start(); 第 279 页

Thread 类 的 sleep(long millis) 方 法 是 静 态 的,millis 参 数 设 定 睡 眠 的 时 间, 以 毫 秒 为 单 位 当 执 行 sleep() 方 法 时, 就 会 放 弃 CPU 开 始 睡 眠,1 秒 钟 后 线 程 结 束 睡 眠, 就 会 获 得 CPU, 继 续 进 行 下 一 次 循 环 所 以 会 感 觉 程 序 运 行 很 慢 值 得 注 意 的 是, 当 某 线 程 结 束 睡 眠 后, 首 先 转 到 就 绪 状 态, 假 如 其 他 的 线 程 正 在 占 用 CPU, 那 么 该 线 程 就 在 可 运 行 池 中 等 待 获 得 CPU 线 程 在 睡 眠 中 如 果 被 中 断, 就 会 收 到 一 个 InterrupedException 异 常, 线 程 就 会 跳 到 异 常 处 理 代 码 块 把 InterrupedException 异 常 包 装 成 一 个 RuntionException, 然 后 继 续 将 它 抛 出 在 下 面 的 示 例 中, 主 线 程 调 用 interrupt() 方 法 中 断 了 睡 眠 中 的 mt 线 程,mt 线 程 就 抛 出 了 InterrupedException 异 常 class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.println(getName() + ":" + count++); try { sleep(5000);// 休 眠 5 秒 钟 catch (InterruptedException e) { e.printstacktrace(); class Client { public static void main(string[] arr) throws InterruptedException { MyThread mt=new MyThread(); mt.start(); Thread.sleep(1000); mt.interrupt();// 中 断 mt 线 程 的 睡 眠 运 行 结 果 如 下 : Thread-0:0 Thread-0:1java.lang.InterruptedException: sleep interrupted at java.lang.thread.sleep(native Method) at MyThread.run(Client.java:10) Thread-0:2 Thread-0:3 Thread-0:4 可 以 看 到 主 线 程 main 欲 中 断 正 在 睡 眠 中 的 mt 线 程, 因 为 线 程 mt 正 在 睡 眠, 所 以 中 断 失 败, 报 出 错 误, 线 程 mt 醒 来 后, 还 可 以 继 续 运 行 interrupt() 方 法 对 于 正 在 运 行 中 的 线 程 ( 不 是 睡 眠 中 的 线 程 ) 是 不 起 作 用 的, 只 有 对 阻 塞 第 280 页

中 的 线 程 有 效 12.4.3 线 程 让 步 :Thread.yield() 方 法 当 线 程 在 运 行 中 执 行 了 Thread 类 的 yield() 静 态 方 法, 如 果 此 时 具 有 相 同 优 先 级 的 其 他 线 程 处 于 就 绪 状 态, 那 么 yield() 方 法 将 把 当 前 运 行 的 线 程 放 到 可 运 行 池 中 并 使 另 一 个 线 程 运 行 如 果 没 有 相 同 优 先 级 的 可 运 行 线 程, 则 yield() 方 法 什 么 也 不 做 下 面 代 码 中, 线 程 执 行 完 一 次 循 环 后, 就 执 行 了 yield() 方 法 class MyThread extends Thread { int count = 0; public void run() { while (true) { System.out.println(getName() + ":" + count++); yield(); class Client { public static void main(string[] arr) throws InterruptedException { MyThread mt=new MyThread(); MyThread mt2=new MyThread(); mt.start(); mt2.start(); 从 运 行 结 果 中, 我 们 可 以 看 到 两 个 线 程 交 替 运 行 Thread-0:0 Thread-1:0 Thread-0:1 Thread-1:1 Thread-0:2 Thread-1:2 Thread-0:3 Thread-1:3 sleep() 方 法 和 yield() 方 法 都 是 Thread 类 的 静 态 方 法, 都 会 使 当 前 处 于 运 行 状 态 的 线 程 放 弃 CPU, 把 运 行 机 会 让 给 其 他 线 程 两 者 的 区 别 在 于 : sleep() 方 法 会 给 其 他 线 程 运 行 机 会, 而 不 考 虑 其 他 线 程 的 优 先 级, 因 此 会 给 较 低 优 先 级 线 程 一 个 机 会 ;yield() 方 法 只 会 给 相 同 优 先 级 或 者 更 高 优 先 级 线 程 一 个 运 行 的 机 会 当 线 程 执 行 了 sleep(long millis) 方 法 后, 会 转 到 阻 塞 状 态, 参 数 millis 指 定 睡 眠 的 时 间 ; 当 线 程 执 行 了 yield() 方 法 后, 将 转 到 就 绪 状 态 第 281 页

异 常 sleep() 方 法 方 法 抛 出 InterrupedException 异 常, 而 yield() 方 法 没 有 声 明 抛 出 任 何 sleep() 方 法 比 yield() 方 法 具 有 更 好 的 可 移 植 性 不 能 依 靠 yield() 方 法 来 提 高 程 序 的 并 发 性 能 对 于 大 多 数 程 序 员 来 说,yield() 方 法 的 唯 一 用 途 是 在 测 试 期 间 人 为 地 提 高 程 序 的 并 发 性 能, 以 帮 助 发 现 一 些 隐 藏 的 错 误 12.4.4 等 待 其 他 线 程 结 束 :join() 当 前 运 行 的 线 程 可 以 调 用 另 一 个 线 程 的 join() 方 法, 当 前 运 行 的 线 程 将 转 到 阻 塞 状 态, 直 至 另 一 个 线 程 运 行 结 束, 它 才 恢 复 运 行 class MyThread extends Thread { int count = 0; public void run() { while (count<5) { System.out.println(getName() + ":" + count++); class Client { public static void main(string[] arr) throws InterruptedException { MyThread mt=new MyThread(); mt.setname("mt"); mt.start(); mt.join();// 主 线 程 等 待 mt 线 程 的 运 行 结 束 System.out.println("main end"); 主 线 程 调 用 了 mt 线 程 的 join() 方 法, 主 线 程 将 等 到 mt 线 程 运 行 结 束 后, 才 能 恢 复 运 行 mt:0 mt:1 mt:2 mt:3 mt:4 main end join() 方 法 有 两 种 重 载 形 式 : public void join() public void join(long timeout) timeout 参 数 设 定 当 前 线 程 被 阻 塞 的 时 间, 以 毫 秒 为 单 位 如 果 把 示 例 main() 方 法 中 的 mt.join() 改 为 mt.join(10), 那 么 当 主 线 程 被 阻 塞 的 时 间 超 过 了 10 毫 秒, 或 者 mt 线 程 运 行 结 束 时, 主 线 程 就 会 恢 复 运 行 第 282 页

12.5 获 得 当 前 线 程 对 象 的 引 用 Thread 类 的 currentthread() 静 态 方 法 返 回 当 前 线 程 对 象 的 引 用 在 主 线 程 main 中 执 行 currentthread() 方 法 时, 返 回 主 线 程 对 象 的 引 用 class Client { public static void main(string[] arr) { Thread main=thread.currentthread(); System.out.println(main.getName()); 12.6 后 台 线 程 演 员 在 前 台 演 戏, 许 多 工 作 人 员 在 后 台 为 演 员 提 供 服 务, 例 如 灯 光 音 效, 当 演 出 结 束 后, 后 台 的 服 务 也 就 停 止 了 有 一 点 需 要 注 意 一 下, 是 演 员 演 戏 先 停 止, 后 台 服 务 再 停 止 后 台 线 程 是 指 为 其 他 线 程 提 供 服 务 的 线 程, 也 成 为 守 护 线 程 如 果 说 演 员 是 前 台 线 程, 那 么 其 他 工 作 人 员 就 是 后 台 线 程 Java 虚 拟 机 的 垃 圾 回 收 线 程 就 是 典 型 的 后 台 线 程, 它 负 责 回 收 其 他 线 程 不 再 使 用 的 内 存 后 台 线 程 的 特 点 是 : 后 台 线 程 和 前 台 线 程 相 伴 相 随, 只 有 前 台 线 程 都 结 束 生 命 周 期, 后 台 线 程 才 会 结 束 生 命 周 期 只 要 有 一 个 前 台 线 程 还 没 有 结 束 运 行, 后 台 线 程 就 不 会 结 束 生 命 周 期 主 线 程 在 默 认 情 况 下 是 前 台 线 程, 由 前 台 线 程 创 建 的 线 程 在 默 认 情 况 下 也 是 前 台 线 程 调 用 Thread 类 的 setdaemon(true) 方 法, 就 能 把 一 个 线 程 设 置 为 后 台 线 程 Thread 类 的 isdaemon() 方 法 用 来 判 读 一 个 线 程 是 否 是 后 台 线 程 在 下 面 的 例 子 中 没 有 设 置 后 台 线 程, 当 main 线 程 结 束 后,mt 线 程 继 续 运 行 class MyThread extends Thread { int count = 0; public void run() { while (true) { try { sleep(1000); catch (InterruptedException e) { e.printstacktrace(); System.out.println(getName() + ":" + count++); class Client { public static void main(string[] arr) throws InterruptedException { MyThread mt=new MyThread(); 第 283 页

mt.setname("mt"); mt.start(); Thread.sleep(5000); System.out.println("main end"); 运 行 结 果 如 下 : mt:0 mt:1 mt:2 mt:3 main end mt:4 mt:5 如 果 设 置 mt 线 程 为 后 台 线 程 : public static void main(string[] arr) throws InterruptedException { MyThread mt=new MyThread(); mt.setname("mt"); mt.setdaemon(true);// 设 置 mt 线 程 为 后 台 线 程 mt.start(); Thread.sleep(5000); System.out.println("main end"); 运 行 结 果 如 下 : mt:0 mt:1 mt:2 mt:3 mt:4 main end 尽 管 后 台 线 程 的 run() 方 法 执 行 的 是 无 限 循 环, 只 要 当 main 线 程 睡 眠 5 秒 钟 结 束 后,mt 线 程 也 就 结 束 了 在 使 用 后 台 线 程 时, 有 以 下 注 意 点 : Java 虚 拟 机 保 证 : 当 所 有 前 台 线 程 运 行 结 束 后, 再 终 止 后 台 线 程, 体 现 的 是 先 后 顺 序 那 么 前 台 线 程 运 行 结 束 后, 后 台 线 程 是 一 次 也 不 运 行 吗? 这 取 决 于 程 序 的 实 现 只 有 线 程 启 动 前 ( 即 调 用 start() 方 法 以 前 ), 才 能 把 它 设 置 为 后 台 线 程 如 果 线 程 启 动 后, 再 调 用 这 个 线 程 的 setdaemon() 方 法, 就 会 导 致 IllegalThreadStateException 异 常 由 于 前 台 线 程 创 建 的 线 程 在 默 认 情 况 下 仍 然 是 前 台 线 程, 由 后 台 线 程 创 建 的 线 程 在 默 认 情 况 下 仍 然 是 后 台 线 程 第 284 页

12.7 定 时 器 Timer 在 JDK 的 java.util 包 中 提 供 了 一 个 实 用 类 Timer, 它 能 够 定 时 执 行 特 定 的 任 务 TimerTask 类 表 示 定 时 器 执 行 的 一 项 任 务 class Client { public static void main(string[] arr) throws InterruptedException { Timer timer=new Timer(); TimerTask task=new TimerTask(){ public void run(){ System.out.println("time is:"+new Date()); ; timer.schedule(task,10,5000);// 设 置 定 时 任 务 java.util.timertask 类 是 一 个 抽 象 类, 它 实 现 了 Runnable 接 口 run() 方 法 表 示 定 时 器 需 要 完 成 的 任 务 Timer 类 的 schedule(timertask task,long delay,long period) 方 法 用 来 设 置 定 时 器 需 要 执 行 的 任 务 task 参 数 表 示 任 务 ;delay 参 数 表 示 延 迟 执 行 的 时 间, 以 毫 秒 为 单 位 ; period 参 数 表 示 每 次 执 行 任 务 的 间 隔 时 间, 以 毫 秒 为 单 位 例 如 : timer.schedule(task,10,5000); 以 上 代 码 表 示 定 时 器 将 在 10 毫 秒 后 开 始 执 行 task 任 务, 以 后 每 隔 5000 毫 秒 重 复 执 行 一 次 task 任 务 同 一 个 定 时 器 对 象 可 以 执 行 多 个 定 时 任 务, 例 如 : timer.schedule(task1,0,5000); timer.schedule(task2,0,3000); 以 上 代 码 表 示 定 时 器 会 执 行 两 个 任 务, 第 一 个 任 务 每 隔 5 秒 执 行 一 次, 第 二 个 任 务 每 隔 3 秒 执 行 一 个 12.8 线 程 的 同 步 线 程 的 职 责 就 是 执 行 一 些 操 作, 而 多 数 操 作 都 涉 及 到 处 理 数 据 下 面 的 线 程 的 操 作 主 要 是 处 理 实 例 变 量 count 通 过 四 个 线 程 模 拟 卖 票 系 统 class TicketSell implements Runnable{ // 有 100 张 票 int count=100; public void run(){ while(true){ if(count>0){ try{ Thread.sleep(10); catch(exception e){ 第 285 页

System.out.println(Thread.currentThread().getName() +"="+count); count--; else{ break; class Client { public static void main(string[] arr){ TicketSell ts=new TicketSell(); Thread t1=new Thread(ts); Thread t2=new Thread(ts); Thread t3=new Thread(ts); Thread t4=new Thread(ts); // 启 动 四 个 线 程 卖 票 t1.start(); t2.start(); t3.start(); t4.start(); 运 行 结 果 如 下 : Thread-1=100 Thread-0=99 Thread-3=98 Thread-0=3 Thread-3=2 Thread-2=1 Thread-1=0 Thread-3=-1 Thread-0=-1 票 的 数 量 count 是 一 个 共 享 资 源, 四 个 线 程 对 共 享 资 源 开 始 了 竞 争 当 线 程 Thread-2 卖 掉 最 后 一 张 票 后, 其 他 的 三 个 线 程, 还 认 为 有 最 后 一 张 票, 继 续 卖 票, 造 成 了 共 享 资 源 的 并 发 问 题 以 上 卖 票 的 操 作 被 称 为 原 子 操 作, 一 个 线 程 在 执 行 原 子 操 作 期 间, 应 该 采 取 措 施 使 得 其 他 线 程 不 能 操 作 共 享 资 源, 否 则 就 会 出 现, 共 享 资 源 被 重 复 操 作 的 问 题 12.8.1 同 步 代 码 块 为 了 保 证 每 个 线 程 能 正 常 执 行 原 子 操 作,Java 引 入 了 同 步 机 制, 具 体 做 法 是 在 代 表 原 子 操 作 的 程 序 代 码 前 加 上 synchronized 标 记, 这 样 的 代 码 被 称 为 同 步 代 码 块 第 286 页

class TicketSell implements Runnable{ // 有 100 张 票 int count=100; // 同 步 锁 Object o=new Object(); public void run(){ while(true){ synchronized(o){ if(count>0){ try{ Thread.sleep(10); catch(exception e){ System.out.println(Thread.currentThread().getName() +"="+count); count--; else{ break; 以 上 代 码 创 建 了 Object 对 象 o, 在 同 步 块 中,o 充 当 了 同 步 锁 的 作 用 每 个 Java 对 象 都 有 且 只 有 一 个 同 步 锁, 在 任 何 时 刻, 最 多 只 允 许 一 个 线 程 拥 有 这 把 锁 当 第 一 个 线 程 拥 有 了 这 个 同 步 锁, 执 行 同 步 块 里 的 代 码 时, 其 他 的 线 程 因 为 没 有 拥 有 这 把 锁, 就 不 能 执 行 同 步 块 里 的 代 码 即 使 该 线 程 睡 眠 了, 其 他 线 程 也 是 不 能 执 行 同 步 块 里 的 代 码 直 到 该 线 程 执 行 完 同 步 块 释 放 了 o 的 同 步 锁, 其 他 线 程 才 有 机 会 执 行 同 步 块 里 的 代 码 当 前 对 象 也 可 以 作 为 同 步 锁 使 用, 所 以 也 可 以 这 样 写 同 步 块 : synchronized(this){ 当 一 个 线 程 开 始 执 行 同 步 代 码 块 时, 并 不 意 味 着 以 不 中 断 的 方 式 运 行 进 入 同 步 代 码 的 线 程 也 可 以 执 行 Thread.sleep() 或 者 执 行 Thread.yield() 方 法, 此 时 它 并 没 有 释 放 锁, 只 是 把 运 行 机 会 让 给 了 其 他 的 线 程 12.8.2 同 步 方 法 功 能 使 用 synchronized 关 键 字 修 饰 的 方 法 为 同 步 方 法, 同 步 方 法 和 同 步 块 一 样 有 线 程 同 步 的 class TicketSell implements Runnable{ // 有 100 张 票 int count=100; // 同 步 锁 Object o=new Object(); 第 287 页

public void run(){ while(true){ if(count<1){ break; sale(); public synchronized void sale(){ if(count>0){ try{ Thread.sleep(10); catch(exception e){ System.out.println(Thread.currentThread().getName()+"="+count); count--; 同 步 方 法 中 使 用 当 前 对 象 this 作 为 同 步 锁, 所 以 不 需 要 额 外 声 明 同 步 锁 synchronized 声 明 不 会 被 继 承 如 果 一 个 用 synchronized 修 饰 的 方 法 被 子 类 覆 盖, 那 么 子 类 中 这 个 方 法 不 再 保 持 同 步, 除 非 也 用 synchronized 修 饰 12.8.3 同 步 与 并 发 同 步 是 解 决 共 享 资 源 竞 争 的 有 效 手 段 当 一 个 线 程 已 经 在 操 纵 共 享 资 源 时, 其 他 线 程 只 能 等 待, 只 有 当 已 经 在 操 纵 共 享 资 源 的 线 程 执 行 同 步 代 码 后, 其 他 线 程 才 有 机 会 操 纵 共 享 资 源 但 是, 多 线 程 的 同 步 与 并 发 是 一 对 此 消 彼 长 的 矛 盾 假 想 有 10 个 人 同 到 一 口 井 里 打 水, 每 个 人 都 要 打 10 桶 水, 人 代 表 线 程, 井 代 表 共 享 资 源 一 种 同 步 方 法 是 : 所 有 的 人 依 次 打 水, 只 用 当 前 一 个 人 打 完 10 桶 水 后, 其 他 人 才 有 机 会 打 水 当 一 个 人 在 打 水 期 间, 其 他 人 必 须 等 待 轮 到 最 后 一 个 打 水 的 人 肯 定 怨 声 载 道, 因 为 他 必 须 等 到 前 面 9 个 人 打 完 90 桶 水 后 才 能 打 水 为 了 提 高 并 发 性 能, 应 该 使 同 步 代 码 块 中 包 含 尽 可 能 少 的 操 作, 使 得 一 个 线 程 能 尽 快 释 放 锁, 减 少 其 他 线 程 等 待 锁 的 时 间 可 以 改 为 一 个 人 打 完 一 桶 水 后, 就 让 其 他 人 打 水, 大 家 轮 流 打 水, 直 到 每 个 人 都 打 完 10 桶 水 12.8.4 线 程 安 全 的 类 一 个 线 程 安 全 的 类 满 足 以 下 条 件 : 这 个 类 的 对 象 可 以 同 时 被 多 个 线 程 安 全 的 访 问 第 288 页

每 个 线 程 都 能 正 常 执 行 原 子 操 作, 得 到 正 确 的 结 果 在 每 个 线 程 的 原 子 操 作 都 完 成 后, 对 象 处 于 逻 辑 上 合 理 的 状 态 12.9 学 习 目 标 1. 掌 握 在 Java 中 创 建 线 程 的 两 种 方 式 ( 写 出 代 码 ) 2. 掌 握 线 程 状 态 转 移 的 结 构 3. 掌 握 线 程 调 度 的 方 法 4. 理 解 线 程 的 同 步 ( 为 什 么 需 要 线 程 的 同 步 ), 会 写 同 步 块 和 同 步 方 法 第 289 页

12.10 作 业 1. ( 选 择 题 ) 下 面 说 法 中 错 误 的 一 项 是 ( ) A. 线 程 就 是 程 序 B. 线 程 是 一 个 程 序 的 单 个 执 行 流 C. 多 想 成 用 于 实 现 并 发 D. 多 线 程 是 指 一 个 程 序 的 多 个 执 行 流 2. 下 列 哪 些 方 法 可 以 使 线 程 从 运 行 状 态 进 入 阻 塞 状 态 ( ) A. sleep B. wait C. yield D.start 3. 下 列 说 法 中 错 误 的 两 项 是 ( ) A. 一 个 线 程 是 一 个 Thread 类 的 实 例 B. 线 程 从 调 用 实 现 Runnable 接 口 的 实 例 的 run() 方 法 开 始 执 行 C. 新 建 的 线 程 调 用 start() 方 法 就 能 立 即 进 入 运 行 状 态 D. 在 Java 中, 高 优 先 级 的 可 运 行 线 程 会 抢 占 低 优 先 级 线 程 4. 下 列 关 于 Thread 类 提 供 的 线 程 控 制 方 法 的 说 法 中, 错 误 的 一 项 是 ( ) A. 在 线 程 A 中 执 行 线 程 B 的 join() 方 法, 则 线 程 A 等 待 直 到 B 执 行 完 成 B. 线 程 A 通 过 调 用 interrupt() 方 法 来 中 断 其 阻 塞 状 态 C. 若 线 程 A 调 用 方 法 isalive() 返 回 值 为 true, 则 说 明 A 正 在 执 行 中 D. currentthread() 方 法 返 回 当 前 线 程 的 引 用 5. 下 列 说 法 中, 错 误 的 一 项 是 ( ) A. 对 象 锁 在 synchronized 块 执 行 完 成 之 后 由 持 有 它 的 线 程 返 还 B. 对 象 锁 在 synchronized 块 中 出 现 异 常 时 有 持 有 它 的 线 程 返 还 C. 当 持 有 锁 的 线 程 调 用 了 该 对 象 的 wait() 方 法 时, 线 程 将 释 放 其 持 有 的 锁 D. 当 持 有 锁 的 线 程 调 用 了 该 对 象 的 构 造 方 法 时, 线 程 将 释 放 其 持 有 的 锁 6. 编 写 一 个 用 线 程 实 现 一 个 数 字 时 钟 的 应 用 程 序 该 线 程 类 要 采 用 休 眠 的 方 式, 把 绝 对 大 部 分 时 间 让 系 统 使 用 7. 创 建 一 个 线 程, 指 定 一 个 限 定 时 间 ( 如 60s), 线 程 运 行 时, 大 约 每 3s 输 出 1 次 当 前 所 剩 时 间, 直 至 给 定 的 限 定 时 间 用 完 (sleep 方 法 ) 8. 编 写 一 个 多 线 程 程 序, 其 中 一 个 线 程 完 成 对 某 个 对 象 的 int 成 员 变 量 的 增 加 操 作, 即 每 次 加 1, 另 一 个 线 程 完 成 对 该 对 象 的 成 员 变 量 的 减 操 作, 即 每 次 减 1, 同 时 要 保 证 该 变 量 的 值 不 会 小 于 0, 不 会 大 于 10, 该 变 量 的 初 始 值 为 0 第 290 页

13 网 络 编 程 13.1 基 本 概 念 13.1.1 计 算 机 网 络 计 算 机 网 络 是 相 互 连 接 的 独 立 自 主 的 计 算 机 集 合 最 简 单 的 网 络 形 式 是 由 两 台 计 算 机 组 成 的 13.1.2 ISO/OSI 七 层 参 考 模 型 OSI(Open System Interconnection) 参 考 模 型 将 网 络 的 不 同 功 能 划 分 为 7 层 : 第 291 页

通 信 实 体 的 对 等 层 之 间 不 允 许 直 接 通 信 各 层 之 间 是 严 格 的 单 向 依 赖 关 系 上 层 使 用 下 层 提 供 的 服 务 ----Service user 下 层 向 上 层 提 供 服 务 ----Service provider OSI 各 层 所 使 用 的 协 议 : 应 用 层 : 远 程 登 录 协 议 Telnet 文 件 传 输 协 议 FTP 超 文 本 传 输 协 议 HTTP 域 名 服 务 DNS 简 单 邮 件 传 输 协 议 SMTP 邮 局 协 议 POP3 等 传 输 层 : 传 输 控 制 协 议 TCP 用 户 数 据 报 协 议 UDP TCP: 面 向 连 接 的 可 靠 的 传 输 协 议 UDP: 是 无 连 接 的, 不 可 靠 地 传 输 协 议 网 络 层 : 网 际 协 议 IP Internet 互 联 网 控 制 报 文 协 议 ICMP Internet 组 管 理 协 议 IGMP 13.1.3 IP 地 址 IP 网 络 中 每 台 主 机 都 必 须 有 一 个 唯 一 的 网 络 地 址 IP 地 址 是 一 个 逻 辑 地 址 英 特 网 上 的 IP 地 址 具 有 全 球 唯 一 性 第 292 页