100
第 6 章 继 承 第 6 章 继 承 继 承 是 面 向 对 象 编 程 的 重 要 特 征 之 一 顾 名 思 义, 继 承 就 是 在 现 有 类 的 基 础 上 构 建 新 类 以 满 足 新 的 要 求 在 继 承 过 程 中, 新 的 类 继 承 原 来 的 方 法 和 实 例 变 量, 并 且 能 添 加 自 己 的 方 法 和 实 例 变 量 在 本 章 中 主 要 讲 解 的 内 容 包 括 派 生 类 的 创 建 使 用 方 法 覆 写 抽 象 类 的 创 建 和 使 用 多 态 和 动 态 绑 定 以 及 Object 类 6.1 派 生 类 面 向 对 象 语 言 的 一 个 重 要 特 性 就 是 继 承 继 承 是 指 声 明 一 些 类, 可 以 再 进 一 步 声 明 这 些 类 的 子 类, 而 子 类 具 有 父 类 已 经 拥 有 的 一 些 方 法 和 属 性, 这 跟 现 实 中 的 父 子 关 系 是 十 分 相 似 的, 所 以 面 向 对 象 把 这 种 机 制 称 为 继 承, 子 类 也 称 为 派 生 类 6.1.1 继 承 的 使 用 继 承 是 在 已 有 类 的 基 础 上 构 建 新 的 类 已 有 的 类 称 为 超 类 父 类 或 基 类, 产 生 的 新 类 称 为 子 类 或 派 生 类 在 动 物 种 类 中 可 以 包 括 老 虎 大 象 和 猴 子 等 多 种 动 物, 这 里 通 过 这 个 为 原 型 来 学 习 继 承 例 如, 可 以 构 建 一 个 Animal 类, 如 下 所 示 class Animal String type; // 种 类 String name; // 名 字 int age; // 年 龄 int weight; // 体 重 void eat() // 吃 饭 方 法 System.out.println("anmal eat"); void breath() // 呼 吸 方 法 System.out.println("animal breath"); void sleep() // 睡 觉 方 法 System.out.println("animal sleep"); 在 Animal 类 中, 有 种 类 名 字 年 龄 体 重 这 些 实 例 变 量 描 述 动 物, 以 及 呼 吸 吃 饭 睡 觉 这 些 方 法 表 示 动 物 的 动 作 下 面 在 Animal 的 基 础 上 构 建 一 个 类 Tiger 来 表 示 老 虎 // 声 明 Tiger 类 继 承 Animal 类 class Tiger extends Animal String tigertype; String from; void tigerrun() System.out.println("the tiger run"); 101
Java 从 入 门 到 精 通 注 意 Tiger 类 的 第 一 行 class Tiger extends Animal, 表 示 Tiger 类 继 承 自 Animal 类 通 过 继 承, 新 生 成 的 老 虎 类 不 仅 继 承 了 Animal 类 的 所 有 实 例 变 量 和 方 法, 还 有 自 己 的 独 有 的 字 段 tigertype from 和 方 法 tigerrun Tiger 类 的 使 用 如 下 所 示 public class TigerDemo public static void main(string args[ ]) // 构 建 一 个 Tiger 对 象 Tiger tiger = new Tiger(); // 对 tiger 的 属 性 进 行 赋 值 tiger.type = "Tiger"; tiger.name="huhu"; tiger.age=12; tiger.weight=120; tiger.tigertype=" 东 北 虎 "; tiger.from=" 长 白 山 "; // 打 印 出 属 性 值 System.out.println("Animal 属 性 : 种 类 ="+tiger.type); System.out.println("Animal 属 性 : 名 字 ="+tiger.name); System.out.println("Animal 属 性 : 年 龄 "+tiger.age); System.out.println("Animal 属 性 : 体 重 "+tiger.weight); System.out.println("Tiger 属 性 : 老 虎 种 类 ="+tiger.tigertype); System.out.println("Tiger 属 性 : 产 地 ="+tiger.from); // 使 用 tiger 调 用 方 法 System.out.println("Animal 方 法 : 呼 吸 "); tiger.breath(); System.out.println("Animal 方 法 : 吃 饭 "); tiger.eat(); System.out.println("Animal 方 法 : 睡 觉 "); tiger.sleep(); System.out.println("Tiger 方 法 : 奔 跑 "); tiger.tigerrun(); 可 以 看 到 Tiger 类 继 承 了 Animal 类 的 所 有 属 性 和 方 法, 并 有 自 己 特 有 的 属 性 和 方 法 程 序 的 运 行 结 果 如 下 Animal 属 性 : 种 类 =Tiger Animal 属 性 : 名 字 =huhu Animal 属 性 : 年 龄 12 Animal 属 性 : 体 重 120 Tiger 属 性 : 老 虎 种 类 = 东 北 虎 Tiger 属 性 : 产 地 = 长 白 山 Animal 方 法 : 呼 吸 animal breath Animal 方 法 : 吃 饭 anmal eat Animal 方 法 : 睡 觉 animal sleep Tiger 方 法 : 奔 跑 the tiger run 102
第 6 章 继 承 6.1.2 子 类 对 象 的 构 建 在 上 一 章 中 已 经 学 习 了 如 何 创 建 类 的 对 象 继 承 也 是 对 类 进 行 操 作 既 然 继 承 可 以 这 么 方 便 的 使 用, 子 类 对 象 的 创 建 过 程 是 怎 么 样 的 呢? 答 案 是 从 最 顶 层 的 基 类 开 始 往 下 一 层 层 的 调 用 默 认 构 造 函 数 示 例 如 下 class A A() System.out.println(" 调 用 A 的 构 造 函 数 "); // 类 B 继 承 A class B extends A B() System.out.println(" 调 用 B 的 构 造 函 数 "); //C 继 承 B class C extends B C() System.out.println(" 调 用 C 的 构 造 函 数 "); // 通 过 该 类 演 示 对 象 的 构 造 过 程 public class CallConstructor public static void main(string[ ] args) C c = new C(); 程 序 的 运 行 结 果 如 下 调 用 A 的 构 造 函 数 调 用 B 的 构 造 函 数 调 用 C 的 构 造 函 数 在 程 序 中 定 义 了 3 个 类 A B C, 其 中 B 继 承 自 A,C 继 承 自 B, 当 创 建 一 个 C 类 的 对 象 时 候, 会 自 动 调 用 父 类 的 无 参 构 造 函 数 如 果 想 调 用 父 类 的 有 参 构 造 函 数, 需 要 使 用 super 关 键 字, 调 用 父 类 的 构 造 函 数 的 语 句 要 放 在 所 在 方 法 的 第 一 个 语 句 中 修 改 上 面 的 程 序 如 下 class A A() //A 类 的 无 参 构 造 器 System.out.println(" 调 用 A 的 构 造 函 数 "); A(int i) //A 类 的 有 参 构 造 器 System.out.println(" 调 用 A 的 有 参 构 造 函 数 "); class B extends A // 让 B 类 继 承 A 类 B() //B 类 的 无 参 构 造 器 System.out.println(" 调 用 B 的 构 造 函 数 "); 103
Java 从 入 门 到 精 通 B(int i) //B 类 的 有 参 构 造 器 super(5); // 调 用 父 类 的 有 参 构 造 器 System.out.println(" 调 用 B 的 有 参 构 造 函 数 "); class C extends B // 让 C 类 继 承 B 类 C() //C 类 无 参 构 造 器 System.out.println(" 调 用 C 的 构 造 函 数 "); C(int i) //C 类 的 有 参 构 造 器 super(5); // 调 用 父 类 也 就 是 B 类 的 有 惨 构 造 器 System.out.println(" 调 用 C 的 有 参 构 造 函 数 "); public class CallConstructor2 public static void main(string[ ] args) C c = new C(); // 创 建 C 类 对 象 C c0=new C(5); // 创 建 C 类 的 具 有 参 数 对 象 给 每 个 类 都 加 上 有 参 数 的 构 造 函 数, 在 有 参 数 的 构 造 函 数 中, 通 过 super 关 键 字 调 用 其 父 类 构 造 函 数 在 CallConstructor 中 构 建 两 个 不 同 的 对 象, 通 过 程 序 的 输 出 可 以 看 出 这 两 个 对 象 的 构 建 过 程 程 序 的 执 行 结 果 如 下 调 用 A 的 构 造 函 数 调 用 B 的 构 造 函 数 调 用 C 的 构 造 函 数 调 用 A 的 有 参 构 造 函 数 调 用 B 的 有 参 构 造 函 数 调 用 C 的 有 参 构 造 函 数 在 C++ 中, 一 个 类 是 可 以 有 多 个 父 类 的, 这 样 会 使 语 言 变 的 非 常 复 杂, 而 且 多 重 继 承 不 是 必 须 的 Java 改 进 了 C++ 的 这 一 点, 不 支 持 多 继 承, 一 个 类 的 直 接 父 类 只 能 有 一 个 6.1.3 方 法 的 覆 写 方 法 覆 写 (overload) 与 方 法 的 重 载 非 常 相 似, 它 在 Java 的 继 承 中 也 有 很 重 要 的 应 用 写 程 序 可 能 会 碰 到 下 面 的 情 况, 在 父 类 中 已 经 实 现 的 方 法 可 能 不 够 精 确, 不 能 满 足 子 类 的 需 求 例 如 在 前 面 的 Animal 类 中,breath 方 法 就 过 于 简 单, 对 于 鱼 类 动 物 是 用 腮 呼 吸 的, 而 对 于 哺 乳 动 物 则 是 用 肺 呼 吸 的, 如 何 实 现 呢,Java 提 供 的 方 法 覆 写 就 是 解 决 这 方 面 的 问 题 在 下 面 的 程 序 中 首 先 定 义 了 一 个 父 类 Animal, 然 后 定 义 Animal 的 3 个 子 类 Tiger Fish 和 Dog, 在 父 类 中 提 供 了 3 个 方 法 eat breath sleep, 在 两 个 子 类 Tiger 和 Fish 中 重 新 定 义 了 breath 方 法, 在 Dog 类 中 什 么 都 没 做 在 OverloadDemo 中, 创 建 了 一 个 Fish 对 象 一 个 Tiger 对 象 和 一 个 Dog 对 象, 分 别 调 用 breath 方 法 104 class Animal String type; // 种 类
第 6 章 继 承 String name; // 名 称 int age; // 年 龄 int weight; // 体 重 void eat() // 吃 饭 方 法 System.out.println(" 动 物 爱 吃 饭 "); void breath() // 呼 吸 方 法 System.out.println(" 动 物 呼 吸 "); void sleep() // 睡 觉 方 法 System.out.println(" 动 物 在 睡 觉 "); //Tiger 类 继 承 Animal 类 class Tiger extends Animal String tigertype; // 老 虎 种 类 String from; // 定 义 老 虎 独 有 变 量 //Tiger 自 己 的 方 法 void tigerrun() // 老 虎 的 奔 跑 方 法 System.out.println(" 老 虎 在 奔 跑 "); void breath() // 继 承 来 的 呼 吸 方 法 System.out.println(" 老 虎 是 用 肺 呼 吸 的 "); //Fish 继 承 Animal 类 class Fish extends Animal String fishtype; //Fish 自 己 的 方 法 void swim() System.out.println(" 鱼 在 游 泳 "); void breath() System.out.println(" 鱼 是 用 腮 呼 吸 的 "); class Dog extends Animal public class OverloadDemo public static void main(string[ ] args) // 声 明 三 个 不 同 的 对 象 Tiger tiger=new Tiger(); Fish fish=new Fish(); Dog dog=new Dog(); // 都 调 用 breath 方 法 tiger.breath(); fish.breath(); dog.breath(); 程 序 的 运 行 结 果 如 下 老 虎 是 用 肺 呼 吸 的 105
鱼 是 用 腮 呼 吸 的 动 物 呼 吸 Java 从 入 门 到 精 通 方 法 被 覆 写 后 如 果 又 需 要 调 用, 可 以 使 用 super 关 键 字 来 实 现, 示 例 如 下 class Animal String type; String name; int age; int weight; void eat() System.out.println(" 动 物 爱 吃 饭 "); void breath() System.out.println(" 动 物 呼 吸 "); class Tiger extends Animal String tigertype; String from; void breath() // 通 过 super 关 键 字 调 用 父 类 的 breath 方 法 super.breath(); // 调 用 动 物 类 的 呼 吸 方 法 System.out.println(" 老 虎 是 用 肺 呼 吸 的 "); public class SuperDemo public static void main(string args[ ]) Tiger tiger=new Tiger(); tiger.breath(); 在 Animal 的 子 类 Tiger 中, 在 breath 方 法 中, 使 用 语 句 super.breath(); 调 用 父 类 的 breath 方 法 程 序 的 运 行 结 果 如 下 动 物 呼 吸 老 虎 是 用 肺 呼 吸 的 super 关 键 字 主 要 有 以 下 两 个 用 途 在 子 类 构 造 函 数 中 调 用 父 类 构 造 函 数 在 子 类 中 调 用 父 类 的 方 法 6.1.4 多 态 与 动 态 绑 定 多 态 是 面 向 对 象 语 言 的 又 一 重 要 特 性 多 态 是 指 同 一 个 方 法 根 据 上 下 文 使 用 不 同 的 定 义 的 能 力 从 这 一 点 看, 上 一 节 讲 的 方 法 覆 写 以 及 前 面 的 方 法 重 载 都 可 被 看 做 是 多 态 但 是 Java 的 多 态 更 多 的 是 跟 动 态 绑 定 放 在 一 起 理 解 的 动 态 绑 定 是 一 种 机 制, 通 过 这 种 机 制, 对 一 个 已 经 被 重 写 的 方 法 的 调 用 将 会 发 生 在 运 行 时, 而 不 是 在 编 译 时 解 析 下 面 的 程 序 演 示 了 动 态 绑 定, 定 义 父 类 Animal 和 子 类 Tiger 以 及 106
第 6 章 继 承 Fish 如 下 class Animal String type; String name; int age; int weight; void eat() System.out.println(" 动 物 爱 吃 饭 "); void breath() System.out.println(" 动 物 呼 吸 "); void sleep() System.out.println(" 动 物 在 睡 觉 "); class Tiger extends Animal String tigertype; String from; void tigerrun() System.out.println(" 老 虎 在 奔 跑 "); void breath() System.out.println(" 老 虎 是 用 肺 呼 吸 的 "); class Fish extends Animal String fishtype; void swim() System.out.println(" 鱼 在 游 泳 "); void breath() System.out.println(" 鱼 是 用 腮 呼 吸 的 "); 演 示 程 序 如 下 public class DynamicMethodDemo public static void main(string args[ ]) Animal [ ]animal=new Animal[3]; // 创 建 不 同 的 对 象, 但 是 都 存 入 Animal 的 引 用 中 animal[0]=new Animal(); animal[1]=new Tiger(); animal[2]=new Fish(); animal[0].breath(); animal[1].breath(); animal[2].breath(); 程 序 定 义 一 个 存 放 Animal 对 象 的 数 组,animal 数 组 的 3 个 元 素 分 别 存 放 一 个 Animal 对 象 一 个 Tiger 对 象 一 个 Fish 对 象, 然 后 对 这 3 个 对 象 调 用 breath 方 法 程 序 的 执 行 结 果 如 下 107
Java 从 入 门 到 精 通 动 物 呼 吸 老 虎 是 用 肺 呼 吸 的 鱼 是 用 腮 呼 吸 的 在 Java 中, 对 象 是 多 态 的, 定 义 一 个 Animal 对 象, 它 既 可 以 存 放 Animal 对 象, 也 可 以 存 放 Animal 的 子 类 Tiger Fish 的 对 象 存 放 在 Animal 数 组 中 的 Tiger 对 象 和 Fish 对 象 在 执 行 breath 方 法 时 会 自 动 地 调 用 原 来 对 象 的 方 法 而 不 是 Animal 的 breath 方 法, 这 就 是 动 态 绑 定 需 要 注 意 一 点 的 是, 通 过 数 组 元 素 访 问 方 法 的 时 候 只 能 访 问 在 Animal 中 定 义 的 方 法, 对 于 Tiger 类 和 Fish 中 定 义 的 方 法 时 却 不 能 调 用, 例 如 语 句 animal[2].swim(); 就 是 不 正 确 的 当 需 要 访 问 这 些 方 法 时 需 要 用 到 类 型 转 换, 演 示 程 序 如 下 public class DynamicMethodDemo2 public static void main(string args[ ]) Animal [ ]animal=new Animal[3]; animal[0]=new Animal(); animal[1]=new Tiger(); animal[2]=new Fish(); DynamicMethodDemo2 dm=new DynamicMethodDemo2(); dm.move(animal[0]); dm.move(animal[1]); dm.move(animal[2]); void move(animal animal) // 进 行 对 象 类 型 的 判 断 if(animal instanceof Tiger) ((Tiger)animal).tigerRun(); else if(animal instanceof Fish) ((Fish)animal).swim(); else animal.sleep(); 主 要 看 move 方 法,move 方 法 首 先 判 断 animal 对 象 是 哪 个 类 的 对 象, 由 判 断 执 行 不 同 的 方 法 在 判 断 过 程 使 用 了 instanceof 运 算 符, 它 是 用 来 判 断 对 象 类 型 的 一 个 运 算 符 当 判 断 出 它 的 类 型 之 后, 再 对 其 进 行 类 型 转 换, 得 到 原 始 类 型 后 就 可 以 调 用 它 的 类 所 特 有 的 方 法 了 程 序 的 运 行 结 果 如 下 动 物 在 睡 觉 老 虎 在 奔 跑 鱼 在 游 泳 6.1.5 final 关 键 字 编 写 程 序 时 可 能 需 要 把 类 定 义 为 不 能 继 承 的, 即 最 终 类, 或 者 是 有 的 方 法 不 希 望 被 子 类 继 承, 这 时 候 就 需 要 使 用 final 关 键 字 来 声 明 把 类 或 方 法 声 明 为 final 类 或 final 方 法 的 方 法 很 简 单, 在 类 前 面 加 上 final 关 键 字 即 可 108 final class 类 名 extends 父 类 // 类 体
第 6 章 继 承 方 法 也 可 以 被 声 明 为 final 的, 形 式 如 下 修 饰 符 final 返 回 值 类 型 方 法 名 () // 方 法 体 例 如 : public final void run() // 方 法 体 需 要 注 意 的 是, 实 例 变 量 也 可 以 被 定 义 为 final, 被 定 义 为 final 的 变 量 不 能 被 修 改 被 声 明 为 final 的 类 的 方 法 自 动 地 被 声 明 为 final, 但 是 它 的 实 例 变 量 并 不 是 final 6.2 抽 象 类 抽 象 类 是 指 在 类 中 定 义 方 法, 但 是 并 不 去 实 现 它, 而 在 它 的 子 类 中 去 具 体 的 实 现 定 义 的 抽 象 方 法 不 过 是 一 个 方 法 占 位 符 继 承 抽 象 类 的 子 类 必 须 实 现 父 类 的 抽 象 方 法, 除 非 子 类 也 被 定 义 成 一 个 抽 象 类 6.2.1 抽 象 类 的 定 义 对 抽 象 类 有 了 基 本 了 解 后, 就 来 看 一 下 如 何 定 义 抽 象 类 定 义 抽 象 类 是 通 过 abstract 关 键 字 实 现 的 抽 象 类 的 一 般 形 式 如 下 修 饰 符 abstract 类 名 // 类 体 抽 象 方 法 的 定 义 形 式 如 下 修 饰 符 abstract 返 回 值 类 型 方 法 名 (); 注 意 : 在 抽 象 类 中 的 方 法 不 一 定 是 抽 象 方 法, 但 是 含 有 抽 象 方 法 的 类 必 须 被 定 义 成 抽 象 类 这 里 利 用 抽 象 类 的 方 法 对 前 面 的 Animal Tiger Fish 类 重 新 定 义 // 抽 象 类 的 声 明 abstract class Animal String type; String name; int age; int weight; void eat() System.out.println(" 动 物 爱 吃 饭 "); abstract void breath(); void sleep() System.out.println(" 动 物 在 睡 觉 "); 109
Java 从 入 门 到 精 通 //Tiger 继 承 抽 象 类 Animal class Tiger extends Animal String tigertype; String from; void tigerrun() System.out.println(" 老 虎 在 奔 跑 "); void breath() System.out.println(" 老 虎 是 用 肺 呼 吸 的 "); class Fish extends Animal String fishtype; void swim() System.out.println(" 鱼 在 游 泳 "); void breath() System.out.println(" 鱼 是 用 腮 呼 吸 的 "); 程 序 把 Animal 定 义 为 抽 象 类, 里 面 的 breath 方 法 被 定 义 为 抽 象 方 法, 而 后 面 定 义 的 Animal 的 子 类 Tiger 和 Fish 都 实 现 了 breath 方 法 6.2.2 抽 象 类 的 使 用 定 义 完 抽 象 类 后, 就 可 以 使 用 它 但 是 抽 象 类 和 普 通 类 不 同, 抽 象 类 不 可 以 实 例 化, 如 语 句 Animal animal =new Animal(); 是 无 法 通 过 编 译 的, 但 是 可 以 创 建 抽 象 类 的 对 象 变 量, 只 是 这 个 变 量 只 能 用 来 指 向 它 的 非 抽 象 子 类 对 象 示 例 如 下 public class UseAbstract public static void main(string[ ] args) Animal animal1=new Fish(); animal1.breath(); Animal animal2=new Tiger(); animal2.breath(); 程 序 中 定 义 了 两 个 Animal 对 象 变 量, 一 个 存 放 Fish 对 象, 另 一 个 存 放 Tiger 对 象, 分 别 调 用 这 两 个 对 象 的 breath 方 法 由 于 根 本 不 可 能 构 建 出 Animal 对 象, 所 以 存 放 的 对 象 仍 然 是 Tiger 对 象, 它 会 动 态 绑 定 正 确 的 方 法 进 行 调 用 需 要 注 意 的 是, 尽 管 animal 存 放 的 是 Tiger 对 象 或 是 Fish 对 象, 但 是 不 能 直 接 调 用 这 些 子 类 的 方 法, 语 句 animal.swim; 和 animal2.tigerrun(); 都 是 不 正 确 的 调 用 这 项 方 法 的 时 候 仍 然 需 要 进 行 类 型 转 换, 正 确 的 使 用 方 法 如 下 ((Fish) animal1).swim(); ((Tiger) animal2).tigerrun(); 110
第 6 章 继 承 6.3 Object 类 Java 中 存 在 一 个 非 常 特 殊 的 类 Object 类, 它 是 所 有 类 的 祖 先 类 在 Java 中 如 果 定 义 了 一 个 类 并 没 有 继 承 任 何 类, 那 么 它 默 认 继 承 Object 类 而 如 果 它 继 承 了 一 个 类, 则 它 的 父 类, 甚 至 父 类 的 父 类 必 然 是 继 承 自 Object 类, 所 以 说 任 何 类 都 是 Object 类 的 子 类 6.3.1 Object 对 象 由 于 Object 类 的 特 殊 性, 所 以 在 实 际 开 发 中, 经 常 会 使 用 到 它 在 本 节 中 就 来 简 单 地 介 绍 一 下 如 何 使 用 Object 类 和 如 何 使 用 类 中 的 两 个 重 要 方 法 定 义 一 个 Object 对 象, 根 据 前 面 继 承 的 知 识, 它 可 以 存 放 任 何 类 型, 示 例 如 下 public class Test public static void main(string[ ] args) // 创 建 一 个 存 放 Object 数 据 的 数 组 Object [ ]object=new Object[3]; Animal animal1 = new Fish(); Animal animal2 = new Tiger(); // 将 上 边 创 建 的 对 象 存 数 Object 数 组 object[0]=animal1; object[1]=animal2; object[2]=new String("String"); // 取 出 对 象 后 需 要 进 行 类 型 转 换 才 能 调 用 相 应 类 型 的 方 法 ((Fish) object[0]).swim(); 示 例 中 用 到 的 Animal 类 Fish 类 和 Tiger 类 都 在 上 一 节 中 定 义 过 了 可 以 把 3 个 不 同 的 对 象 放 进 Object 数 组 中, 但 是 放 进 去 后 对 象 的 类 型 被 丢 弃 了, 取 出 后 要 进 行 类 型 转 换 当 然 类 型 转 换 不 像 程 序 中 这 么 简 单, 可 能 要 使 用 到 类 型 判 断, 即 用 instanceof 运 算 符 实 现 6.3.2 equals 方 法 和 tostring 方 法 在 Object 类 中 也 定 义 了 一 系 列 的 方 法, 读 者 可 以 阅 读 API 自 己 查 看 其 中 比 较 重 要 的 两 个 方 法 就 是 equals() 方 法 和 tostring() 方 法 在 Object 类 中 equals 方 法 的 定 义 形 式 如 下 public boolean equals(object obj) return (this == obj); 当 且 仅 当 两 个 对 象 指 向 同 一 个 对 象 的 时 候 才 会 返 回 真 值 程 序 要 想 进 行 详 细 的 判 断, 必 须 自 己 进 行 equals 方 法 的 覆 写 在 前 面 的 内 容 中, 介 绍 了 String 类 equals 方 法 的 实 现 public boolean equals(object anobject) 111
112 Java 从 入 门 到 精 通 if (this == anobject) return true; if (anobject instanceof String) String anotherstring = (String)anObject; int n = count; if (n == anotherstring.count) char v1[ ] = value; char v2[ ] = anotherstring.value; int i = offset; int j = anotherstring.offset; while (n--!= 0) if (v1[i++]!= v2[j++]) return false; return true; return false; 程 序 首 先 判 断 两 个 对 象 是 否 指 向 同 一 个 对 象, 如 果 是 的 话 当 然 返 回 true, 如 果 不 是 继 续 判 断 提 供 的 对 象 是 否 是 String 类 型, 如 果 不 是 的 话 返 回 false, 是 的 话 再 进 一 步 判 断 ; 取 出 两 个 String 类 的 每 一 个 位 置 的 字 符 进 行 判 断, 如 果 有 一 个 不 等 则 返 回 false 其 实 这 是 equals 方 法, 这 里 模 仿 String 的 equals 方 法 的 实 现 提 供 一 个 Animal 的 equals 方 法, 其 实 这 是 一 种 比 较 标 准 的 equals 方 法 编 写 方 式 public boolean equals(object ob) boolean bool = false; if (this == ob) bool= true; if (ob == null) bool= false; if (ob instanceof Animal) bool= ((Animal) ob).age == this.age && ((Animal) ob).name == this.name && ((Animal) ob).type == this.type && ((Animal) ob).weight == this.weight; return bool; 编 写 测 试 类 如 下 public class Testequals public static void main(string[ ] args) // 声 明 三 个 对 象 Animal animal1 = new Fish(); Animal animal2 = new Tiger(); Animal animal3=new Fish(); // 对 对 象 属 性 赋 值 animal1.age=12; animal1.name="dingding"; animal1.type="dog"; animal1.weight=12; animal2.age=12;
第 6 章 继 承 animal2.name="dingding"; animal2.type="dog"; animal2.weight=12; animal3.age=12; animal3.name="dongdogn"; animal3.type="dog"; animal3.weight=12; // 进 行 比 较, 并 打 印 出 结 果 System.out.println(animal1.equals(animal2)); System.out.println(animal1.equals(animal3)); 程 序 的 执 行 结 果 如 下 true false 测 试 成 功 其 实 Java 的 源 代 码 都 是 经 过 仔 细 斟 酌 的, 读 者 有 时 间 可 以 多 学 习 一 下 Java 源 码 对 于 tostring() 方 法,Object 类 是 这 样 实 现 的 public String tostring() return getclass().getname() + "@" + Integer.toHexString(hashCode()); 其 中 getclass 方 法 是 Object 类 提 供 的 一 个 方 法 public final native Class<?> getclass(); 它 返 回 一 个 Class 类 型, 然 后 调 用 Class 类 的 getname 方 法, 请 读 者 查 看 API 中 getname 的 实 现 下 面 编 写 一 个 Animal 的 tostring 方 法 public String tostring() String returnstring = null; returnstring = " 名 字 :" + this.name + "\n" + " 种 类 :" + this.type + "\n" + " 年 龄 :" + this.age + "\n" + " 体 重 :" + this.weight; return returnstring; 把 这 段 代 码 加 入 Animal 类 中, 测 试 代 码 如 下 public class TesttoString public static void main(string[ ] args) Animal animal1 = new Fish(); animal1.age = 12; animal1.name = "dingding"; animal1.type = "dog"; animal1.weight = 12; System.out.println(animal1.toString()); 程 序 的 运 行 结 果 如 下 名 字 :dingding 种 类 :dog 113
Java 从 入 门 到 精 通 年 龄 :12 体 重 :12 6.4 小 结 本 章 首 先 讲 解 了 Java 继 承 的 实 现 及 方 法 的 覆 写, 读 者 要 注 意 跟 方 法 重 载 的 区 别 ; 然 后 讲 解 了 多 态 和 动 态 绑 定 以 及 final 关 键 字 的 使 用 ; 接 着 讲 解 了 抽 象 类 的 使 用 ; 最 后 讲 解 了 Object 类, 其 中 equals 方 法 借 鉴 了 String 类 中 equals 方 法 的 实 现 114