Java 程 序 设 计 教 学 课 件 河 南 农 业 大 学 信 管 学 院 计 算 机 系 河 南 农 业 大 学 信 管 学 院 计 算 机 系 高 级 语 言 程 序 设 计 课 程 组
第 5 章 面 向 对 象 高 级 程 序 设 计
主 要 内 容 5.1 继 承 5.2 多 态 性 5.3 抽 象 类 和 抽 象 方 法 5.4 接 口 5.5 内 部 类 和 匿 名 类
5.1 继 承 5.1.1 创 建 子 类 5.1.2 成 员 变 量 的 隐 藏 和 方 法 的 重 写 5.1.3 super 5.1.4 对 象 的 上 转 型 对 象
5.1.1 创 建 子 类 继 承 是 一 种 由 已 有 的 类 创 建 新 类 的 机 制 利 用 继 承, 我 们 可 以 先 创 建 一 个 拥 有 共 同 属 性 的 一 般 类, 根 据 该 一 般 类 再 创 建 具 有 特 殊 属 性 的 新 类 由 继 承 而 得 到 的 类 称 为 子 类 (subclass), 被 继 承 的 类 称 为 父 类 ( 或 叫 超 类,superclass, superclass) 直 接 或 间 接 被 继 承 的 类 都 是 父 类 子 类 继 承 父 类 的 状 态 和 行 为, 同 时 也 可 以 修 改 父 类 的 状 态 或 重 写 父 类 的 行 为, 并 添 加 新 的 状 态 和 行 为 Java 中 不 支 多 重 继 承
5.1.1 创 建 子 类 通 过 在 类 的 声 明 中 加 入 extends 子 句 来 创 建 一 个 类 的 子 类, 其 格 式 如 下 : class SubClass extends SuperClass{ 上 面 的 代 码 把 SubClass 声 明 为 SuperClass 的 直 接 子 类 如 果 SuperClass 又 是 某 个 类 的 子 类, 则 SubClass 同 时 也 是 该 类 的 ( 间 接 ) 子 类 子 类 可 以 继 承 父 类 的 成 员 变 量 和 方 法 如 果 缺 省 extends 子 句, 则 该 类 为 java.lang.object 的 子 类 子 类 可 以 继 承 父 类 中 访 问 权 限 设 定 为 public protected protected defaultdefault 的 成 员 变 量 和 方 法 但 是 不 能 继 承 访 问 权 限 为 private 的 成 员 变 量 和 方 法
5.1.1 创 建 子 类
5.1.1 创 建 子 类
5.1.1 创 建 子 类 注 意,MammalClass, 类 拥 有 来 自 于 DogClass 和 CatClass 的 相 同 属 性, 包 括 了 name eyecolor eyecolor age 等 现 在 我 们 可 以 利 用 继 承 重 写 DogClass 和 CatClass public class DogClass extends MammalClass { boolean hastail; // name,eyecolor 已 经 从 父 类 继 承 public DogClass() { // 隐 式 调 用 super() name="chase"; eyecolor="black"; age=2; hastail=true;
5.1.1 创 建 子 类 例 5-1 继 承 的 简 单 例 子 class Father{ // 父 类 private int money; float weight,height; Weight,height,head, String head; Speak(); String speak(string s) { Hand,foot return s ; class Son extends Father{ // 子 类 String hand,foot;
5.1.1 创 建 子 类 例 5-1 继 承 的 简 单 例 子 public class TestExtend { public static void main(string args[]){ Son boy=new Son(); boy.weight=120f; boy.height=1.8f; boy.head=" 一 个 头 "; boy.hand=" 两 只 手 "; boy.foot=" 两 只 脚 "; System.out.println(" 我 是 儿 子 "); System.out.println(" 我 有 :"+boy.hand+" "+boy.foot+" "+boy.foot+" "+ boy.head +" 重 "+boy.weight+" 高 "+boy.height); 上 面 程 序 运 行 结 果 如 下 : 我 是 儿 子 我 有 : 两 只 手 两 只 脚 一 个 头 重 120.0 高 1.8
5.1.1 创 建 子 类 如 果 子 类 和 父 类 不 在 同 一 个 包 中, 那 么, 子 类 可 以 继 承 了 父 类 的 protected public public 修 饰 的 成 员 变 量 做 为 子 类 的 成 员 变 量, 并 且 也 可 以 继 承 了 父 类 的 protected public 修 饰 的 方 法 作 为 子 类 的 方 法 另 外 子 类 和 父 类 不 在 同 一 个 包 中, 则 子 类 不 能 继 承 父 类 的 default 变 量 ( 友 好 变 量 ) 和 default 方 法 ( 友 好 方 法 )
5.1.1 创 建 子 类 例 5-2 继 承 不 同 包 中 的 类 的 简 单 例 子 // HouseHold.java package xing.house; public class HouseHold { // 家 类 protected String address; // 地 址 public String surnname; // 姓 String givenname; // 名 public HouseHold(String add) { address =add; protected String getaddress(){return address; void setaddress(string newadd) {address=newadd; //void setaddress(string add){address=add;
5.1.1 创 建 子 类 // Mikey.java: package xing.friend; import xing.house.household; public class Mikey extends HouseHold { public Mikey(){ super("star flight street 110"); public static void main(string args[]){ Mikey mikey=new Mikey(); //mikey.givenname= Johnson ; // 非 法 mikey.surnname="math"; // 合 法. mikey.address="star flight street 110"; // 合 法. String m=mikey.getaddress(); // 合 法 //mikey.setaddress("star flight street 110"); // 非 法. System.out.println(mikey.address+":"+m);
5.1.1 创 建 子 类 程 序 编 译 和 运 行 过 程 如 下 :
5.1.2 成 员 变 量 的 隐 藏 和 方 法 的 重 写 当 我 们 在 子 类 中 定 义 的 成 员 变 量 和 父 类 中 的 成 员 变 量 同 名 时, 此 时 称 子 类 的 成 员 变 量 隐 藏 了 父 类 的 成 员 变 量 当 子 类 中 定 义 了 一 个 方 法, 并 且 这 个 方 法 的 名 字, 返 回 类 型, 参 数 个 数 以 及 类 型 和 父 类 的 某 个 方 法 完 全 相 同 时, 父 类 的 这 个 方 法 将 被 隐 藏, 这 时 我 们 说 重 写 了 父 类 的 方 法 子 类 通 过 成 员 变 量 的 隐 藏 和 方 法 的 重 写 可 以 把 父 类 的 状 态 和 行 为 改 变 为 自 身 的 状 态 和 行 为
5.1.2 成 员 变 量 的 隐 藏 和 方 法 的 重 写 例 如 下 面 的 这 段 程 序 就 是 这 样 的 情 况 : class SuperClass { // 父 类 int y; void sety(){ y=0; class SubClass extends SuperClass{ int y; // 父 类 变 量 y 被 隐 藏 void sety(){ // 重 写 父 类 的 方 法 sety() y=1;
5.1.3 super 5.1.3 super 子 类 在 隐 藏 了 父 类 的 成 员 变 量 或 重 写 了 父 类 的 方 法 后, 常 常 还 要 用 到 父 类 的 成 员 变 量, 或 在 重 写 的 方 法 中 使 用 父 类 中 被 重 写 的 方 法 以 简 化 代 码 的 编 写, 这 时 就 要 访 问 父 类 的 成 员 变 量 或 调 用 父 类 的 方 法,Java 中 通 过 super 来 实 现 对 父 类 成 员 的 访 问 我 们 知 道,this 用 来 引 用 当 前 对 象, 与 this 类 似,super 用 来 引 用 当 前 对 象 的 父 类 super 的 使 用 可 以 分 为 下 面 三 种 情 况 : 1) 用 来 访 问 父 类 被 隐 藏 的 成 员 变 量, 如 : super.variable 2) 用 来 调 用 父 类 中 被 重 写 的 方 法, 如 : super.method([paramlist]): 3) 用 来 调 用 父 类 的 构 造 方 法, 如 : super([paramlist]);
5.1.3 super 例 5-3 调 用 父 类 的 构 造 方 法 的 例 子 class A { // 类 A public int n; // 公 共 类 型 的 成 员 变 量 public A(){ public A(int n){ this.n = n; int method(){ return n; public class B extends A { // 类 B public B(){ super(15); public static void main(string args[]){ A ainstance = new B( ); int b=ainstance.method(); System.out.println(" 类 A 中 的 成 员 变 量 :"+b);
5.1.4 对 象 的 上 转 型 对 象 假 设 A 类 是 B 类 的 父 类, class b extends B{ 当 我 们 用 子 类 创 建 一 个 对 象, 并 把 这 个 对 象 的 引 用 放 到 父 类 的 对 象 中 时, 例 如 A a; A a=new B(); 或 A a; B b=new B(); a=b; 称 这 个 父 类 对 象 a, 是 子 类 对 象 b 的 上 转 型 对 象
5.1.4 对 象 的 上 转 型 对 象 对 象 的 上 转 型 对 象 的 实 体 是 子 类 负 责 创 建 的, 但 上 转 型 对 象 会 失 去 原 对 象 的 一 些 属 性 和 功 能. 上 转 型 对 象 具 有 如 下 特 点 : 1) 上 转 型 对 象 不 能 操 作 子 类 新 增 的 成 员 变 量 和 子 类 新 增 的 方 法 2) 上 转 型 对 象 可 以 操 作 子 类 继 承 或 重 写 的 成 员 变 量, 也 可 以 使 用 子 类 继 承 的 或 重 写 的 方 法 3) 如 果 子 类 重 写 了 父 类 的 某 个 方 法 后, 当 对 象 的 上 转 对 象 调 用 这 个 方 法 时 一 定 是 调 用 了 这 个 重 写 的 方 法, 因 为 程 序 在 运 行 时 知 道, 这 个 上 转 对 象 的 实 体 是 子 类 创 建 的, 只 不 过 损 失 了 一 些 功 能 而 已 不 要 将 父 类 创 建 的 对 象 和 子 类 对 象 的 上 转 型 对 象 相 混 淆 上 转 型 对 象 在 Java 编 程 中 是 常 见 的 可 以 将 对 象 的 上 转 型 对 象 再 强 制 转 换 到 一 个 子 类 对 象, 这 时, 该 子 类 对 象 又 具 备 了 子 类 所 给 的 所 有 属 性 和 功 能
5.1.4 对 象 的 上 转 型 对 象 例 5-5 上 转 型 对 象 的 使 用 class Mammal{ // 哺 乳 动 物 类 private int n=40; void cryspeak(string s) { System.out.println(s); public class Monkey extends Mammal{ // 猴 子 类 void computer(int aa,int bb) { int cc=aa*bb; System.out.println(cc); void cryspeak(string s) {System.out.println("**"+s+"**"); public static void main(string args[]){ Mammal mammal=new Monkey(); // mammal 是 Monkey 类 的 对 象 的 上 转 型 对 象. mammal.cryspeak("i love this game"); // mammal.computer(10,10); Monkey monkey=(monkey)mammal; // 把 上 转 型 对 象 强 制 转 化 为 子 类 的 对 象. monkey.computer(10,10);
5.1.4 对 象 的 上 转 型 对 象 上 述 程 序 的 运 行 结 果 为 : **I love this game** 100 在 上 述 例 子 中, 上 转 对 象 mammal 调 用 方 法 : mammal.cryspeak("i love this game"); 得 到 的 结 果 是 **I love this game**. 而 不 是 I love this game 因 为 mammal 调 用 的 是 子 类 重 写 的 方 法 cryspeak. 在 main() 中, 如 果 出 现 下 面 的 两 行 代 码, 那 将 是 错 误 的 : mammal.n=1000; // 因 为 子 类 本 来 就 没 有 继 承 n mammal.computer(10,10); // 因 为 computer 方 法 是 子 类 新 增 的 方 法
第 5 章 面 向 对 象 高 级 程 序 设 计 5.1 继 承 5.2 多 态 性 5.3 抽 象 类 和 抽 象 方 法 5.4 接 口 5.5 内 部 类 和 匿 名 类
5.2 多 态 性 多 态 (Polymorphism) 的 意 思 就 是 用 相 同 的 名 字 来 定 义 不 同 的 方 法 在 Java 中, 普 通 类 型 的 多 态 为 重 载, 这 就 意 味 着 可 以 使 几 个 不 同 的 方 法 使 用 相 同 的 名 字, 这 些 方 法 以 参 数 的 个 数 不 同 参 数 的 类 型 不 同 等 方 面 来 进 行 区 分, 以 使 得 编 译 器 能 够 进 行 识 别 也 可 以 这 样 讲, 重 载 是 同 一 个 方 法 具 有 不 同 的 版 本, 每 个 版 本 之 间 在 参 数 特 征 方 面 有 差 异 重 载 是 Java 实 现 多 态 性 的 方 式 之 一 例 如 :family(): 方 法 可 以 有 三 个 版 本, 如 下 : family() { family(string ch) { address=ch; family(string ch,float n) { address=ch; pay=n; 这 些 方 法 并 存 于 程 序 中, 编 译 时, 编 译 器 根 据 实 参 的 类 型 和 个 数 来 区 分 从 而 调 用 那 个 方 法 如 果 这 些 方 法 作 为 函 数 或 过 程 同 时 出 现 在 其 它 语 言 的 程 序 中, 如 C,, 那 将 导 致 灾 难 性 的 错 误
5.2 多 态 性 例 5-6 构 造 方 法 重 载 的 例 子 class person { String name="johnson"; // 姓 名 int age=45; // 年 龄 person(){ person(string a) {name=a; person(string a,int b) { name=a; age=b; public voiddisplay(){ System.out.println("Name="+ name+","+"age="+age); public class Poly{ public static void main(string[] args) { person ko1=new person(); person ko2=new person("mike"); person ko3=new person("willian",50); ko1.display(); ko2.display(); ko3.display();
5.2 多 态 性 在 Java 语 言 中, 多 态 性 主 要 体 现 在 两 个 方 面 : 由 方 法 重 载 实 现 的 静 态 多 态 性 ( 编 译 时 多 态 ) 和 方 法 重 写 实 现 的 动 态 多 态 性 ( 运 行 时 多 态 ), 如 下 : 1) 编 译 时 多 态 在 编 译 阶 段, 具 体 调 用 哪 个 被 重 载 的 方 法, 编 译 器 会 根 据 参 数 的 不 同 来 静 态 确 定 调 用 相 应 的 方 法 2) 运 行 时 多 态 由 于 子 类 继 承 了 父 类 所 有 的 属 性 ( 私 有 的 除 外 ), 所 以 子 类 对 象 可 以 作 为 父 类 对 象 使 用 程 序 中 凡 是 使 用 父 类 对 象 的 地 方, 都 可 以 用 子 类 对 象 来 代 替 一 个 对 象 可 以 通 过 引 用 子 类 的 实 例 来 调 用 子 类 的 方 法 如 果 子 类 重 写 了 父 类 的 方 法, 那 么 重 写 方 法 的 调 用 原 则 如 下 :Java 运 行 时 系 统 根 据 调 用 该 方 法 的 实 例, 来 决 定 调 用 哪 个 方 法 对 子 类 的 一 个 实 例, 如 果 子 类 重 写 了 父 类 的 方 法, 则 运 行 时 系 统 调 用 子 类 的 方 法 ; 如 果 子 类 继 承 了 父 类 的 方 法 ( 未 重 写 ), 则 运 行 时 系 统 调 用 父 类 的 方 法 另 外, 方 法 重 写 时 应 遵 循 的 原 则 如 下 : 改 写 后 的 方 法 不 能 比 被 重 写 的 方 法 有 更 严 格 的 访 问 权 限 改 写 后 的 方 法 不 能 比 被 重 写 的 方 法 产 生 更 多 的 异 常 进 行 方 法 重 写 时 必 须 遵 从 这 两 个 原 则, 否 则 编 译 器 会 指 出 程 序 出 错
5.2 多 态 性 例 5-7 方 法 重 写 的 例 子 class Parent{ public void function(){ System.out.println("I am in Parent!"); class Child extends Parent{ private void function(){ System.out.println("I am in Child!"); public class RTpolyTest{ public static void main(string args[]){ Parent pl=new Parent( ); Parent p2=new Child( ); p1.function( ); p2.function( );
5.2 多 态 性 编 译 过 程 如 下 : D:\user\chap05>Javac RTpolyTest.java RTpolyTest.java:8: function() in Child cannot override function() in Parent; attempting to assign weaker access privileges; was public private void function(){ ^ RTpolyTest.java:16: cannot find symbol symbol : variable p1 location: class RTpolyTest p1.function( ); ^ 2 errors 可 以 看 出, 该 程 序 中 实 例 p2 调 用 function() 方 法 时 会 导 致 访 问 权 限 的 冲 突
第 5 章 面 向 对 象 高 级 程 序 设 计 5.1 继 承 5.2 多 态 性 5.3 抽 象 类 和 抽 象 方 法 5.4 接 口 5.5 内 部 类 和 匿 名 类
5.3 抽 象 类 和 抽 象 方 法 Java 语 言 中, 用 abstract 关 键 字 来 修 饰 一 个 类 时, 这 个 类 叫 做 抽 象 类 一 个 abstract 类 只 关 心 它 的 子 类 是 否 具 有 某 种 功 能, 并 不 关 心 该 功 能 的 具 体 实 现, 功 能 的 具 体 行 为 由 子 类 负 责 实 现 的 例 如 : public abstract class Drawing { public abstract void drawdot(int x, int y); public void drawline(int x1, int y1,int x2, int y2) { 用 abstract 来 修 饰 一 个 方 法 时, 该 方 法 叫 做 抽 象 方 法 与 final 类 和 方 法 相 反,abstract 类 必 须 被 继 承,abstract 方 法 必 须 被 重 写
5.3 抽 象 类 和 抽 象 方 法 当 一 个 类 的 定 义 完 全 表 示 抽 象 的 概 念 时, 它 不 应 该 被 实 例 化 为 一 个 对 象 例 如 Java 中 的 Number 类 就 是 一 个 抽 象 类, 它 只 表 示 数 字 这 一 抽 象 概 念, 只 有 当 它 作 为 整 数 类 Integer 或 实 数 类 Float 等 的 父 类 时 才 有 意 义 定 义 一 个 抽 象 类 的 格 式 如 下 : abstract class abstractclass{ 由 于 抽 象 类 不 能 被 实 例 化, 因 此 下 面 的 语 句 会 产 生 编 译 错 误 : new abstractclass(); 抽 象 类 中 可 以 包 含 抽 象 方 法, 为 所 有 子 类 定 义 一 个 统 一 的 接 口, 对 抽 象 方 法 只 需 声 明, 而 不 需 实 现, 因 此 它 没 有 方 法 体 其 格 式 如 下 : abstrac returntype abstractmethod([paramlist]);
5.3 抽 象 类 和 抽 象 方 法 例 5-8 使 用 abstract 的 另 一 例 子 abstract class AA{ abstract void callme( ); void metoo( ){ System.out.println("Inside A's metoo() method"); class BB extends AA{ void callme( ){ System.out.println("Inside B's callme() method"); public class AAbstract{ public static void main(string args[]){ AA cc=new BB(); //cc 为 上 转 型 对 象 cc.callme(); cc.metoo();
第 5 章 面 向 对 象 高 级 程 序 设 计 5.1 继 承 5.2 多 态 性 5.3 抽 象 类 和 抽 象 方 法 5.4 接 口 5.5 内 部 类 和 匿 名 类
5.4 接 口 5.4.1 接 口 声 明 5.4.2 使 用 接 口 的 优 点
5.4.1 接 口 声 明 从 本 质 上 讲, 接 口 是 一 种 特 殊 的 抽 象 类, 这 种 抽 象 类 中 只 包 含 常 量 和 方 法 的 定 义, 而 没 有 变 量 和 方 法 的 实 现 通 过 接 口 使 得 处 于 不 同 层 次, 甚 至 互 不 相 关 的 类 可 以 具 有 相 同 的 行 为 接 口 其 实 就 是 方 法 定 义 和 常 量 值 的 集 合 它 的 优 点 主 要 体 现 在 下 面 几 个 方 面 : (1) 通 过 接 口 可 以 实 现 不 相 关 类 的 相 同 行 为, 而 不 需 要 考 虑 这 些 类 之 间 的 层 次 关 系 (2) 通 过 接 口 可 以 指 明 多 个 类 需 要 实 现 的 方 法 (3) 通 过 接 口 可 以 了 解 对 象 的 交 互 界 面, 而 不 需 了 解 对 象 所 对 应 的 类 接 口 把 方 法 的 定 义 和 类 的 层 次 区 分 开 来, 通 过 它 可 以 在 运 行 时 动 态 地 定 位 所 调 用 的 方 法 同 时 接 口 中 可 以 实 现 多 重 继 承, 且 一 个 类 可 以 实 现 多 个 接 口 正 是 这 些 机 制 使 得 接 口 提 供 了 比 多 重 继 承 ( 如 C++ 等 语 言 ) 更 简 单 更 灵 活 而 且 更 强 劲 的 功 能
5.4.1 接 口 声 明 Java 不 支 持 多 继 承 性, 即 一 个 类 只 能 有 一 个 父 类 单 继 承 性 使 得 Java 类 层 次 简 单, 易 于 程 序 的 管 理 为 了 克 服 单 继 承 的 缺 点,Java 使 用 了 接 口, 一 个 类 可 以 实 现 多 个 接 口 使 用 关 键 字 interface 来 定 义 一 个 接 口 接 口 的 定 义 和 类 的 定 义 很 相 似, 分 为 接 口 声 明 和 接 口 体 两 部 分 1 接 口 声 明 我 们 曾 使 用 class 关 键 字 来 声 明 类, 接 口 通 过 使 用 关 键 自 interface 来 声 明. 完 整 的 接 口 定 义 格 式 如 下 : [public] interface interfacename [extends listofsuperinterface]{ 其 中 public 修 饰 符 指 明 任 意 类 均 可 以 使 用 这 个 接 口, 缺 省 情 况 下, 只 有 与 该 接 口 定 义 在 同 一 个 包 中 的 类 才 可 以 访 问 这 个 接 口 接 口 声 明 中 的 extends 子 句 与 类 声 明 中 的 extends 子 句 基 本 相 同, 不 同 的 是 一 个 接 口 可 以 有 多 个 父 接 口, 用 逗 号 隔 开, 而 一 个 类 只 能 有 一 个 父 类 子 接 口 继 承 父 接 口 中 所 有 的 常 量 和 方 法 通 常 接 口 名 称 以 able 或 ible 结 尾, 表 明 接 口 能 完 成 一 定 的 行 为, 例 如 Runnable Serializable
5.4.1 接 口 声 明 2 接 口 体 接 口 体 中 包 含 常 量 定 义 和 方 法 定 义 两 部 分 其 中 常 量 定 义 部 分 定 义 的 常 量 均 具 有 public static 和 final 属 性 其 格 式 如 下 : returntype methodname([paramlist]); 接 口 中 只 能 进 行 方 法 的 声 明, 而 不 提 供 方 法 的 实 现, 所 以, 方 法 定 义 没 有 方 法 体, 且 用 分 号 (;) 结 尾, 在 接 口 中 声 明 的 方 法 具 有 public 和 abstract 属 性 另 外, 如 果 在 子 接 口 中 定 义 了 和 父 接 口 同 名 的 常 量, 则 父 接 口 中 的 常 量 被 隐 藏 例 如 : interface Summaryable { final int MAX=50; // MAX 具 有 public static final 属 性 void printone(float x); float sum(float x,float y); 上 面 这 段 程 序 可 以 以 Summaryable.java 来 保 存, 也 可 以 写 入 其 它 Java 程 序 中
5.4.1 接 口 声 明 3 接 口 的 使 用 一 个 类 通 过 使 用 关 键 字 implements 声 明 自 己 使 用 ( 或 实 现 ) 一 个 或 多 个 接 口 如 果 使 用 多 个 接 口, 用 逗 号 隔 开 接 口 名 如 class Calculate extends Computer implements Summary,Substractable{ 类 Calculate 使 用 了 Summary 和 Substractable 接 口, 继 承 了 Computer 类 如 果 一 个 类 使 用 了 某 个 接 口, 那 么 这 个 类 必 须 实 现 该 接 口 的 所 有 方 法, 即 为 这 些 方 法 提 供 方 法 体 需 要 注 意 的 如 下 : 1) 在 类 中 实 现 接 口 的 方 法 时, 方 法 的 名 字, 返 回 类 型, 参 数 个 数 及 类 型 必 须 与 接 口 中 的 完 全 一 致 2) 接 口 中 的 方 法 被 默 认 是 public, 所 以 类 在 实 现 接 口 方 法 时, 一 定 要 用 public 来 修 饰 3) 另 外, 如 果 接 口 的 方 法 的 返 回 类 型 如 果 不 是 void 的, 那 么 在 类 中 实 现 该 接 口 方 法 时, 方 法 体 至 少 要 有 一 个 return 语 句 如 果 是 void 型, 类 体 除 了 两 个 大 括 号 外, 也 可 以 没 有 任 何 语 句.
5.4.2 使 用 接 口 的 优 点 从 本 质 上 讲, 接 口 是 一 种 特 殊 的 抽 象 类, 这 种 抽 象 类 中 只 包 含 常 量 和 方 法 的 定 义, 而 没 有 变 量 和 方 法 的 实 现 通 过 接 口 使 得 处 于 不 同 层 次, 甚 至 互 不 相 关 的 类 可 以 具 有 相 同 的 行 为 接 口 其 实 就 是 方 法 定 义 和 常 量 值 的 集 合 它 的 优 点 主 要 体 现 在 下 面 几 个 方 面 : (1) 通 过 接 口 可 以 实 现 不 相 关 类 的 相 同 行 为, 而 不 需 要 考 虑 这 些 类 之 间 的 层 次 关 系 (2) 通 过 接 口 可 以 指 明 多 个 类 需 要 实 现 的 方 法 (3) 通 过 接 口 可 以 了 解 对 象 的 交 互 界 面, 而 不 需 了 解 对 象 所 对 应 的 类 接 口 把 方 法 的 定 义 和 类 的 层 次 区 分 开 来, 通 过 它 可 以 在 运 行 时 动 态 地 定 位 所 调 用 的 方 法 同 时 接 口 中 可 以 实 现 多 重 继 承, 且 一 个 类 可 以 实 现 多 个 接 口 正 是 这 些 机 制 使 得 接 口 提 供 了 比 多 重 继 承 ( 如 C++ 等 语 言 ) 更 简 单 更 灵 活 而 且 更 强 劲 的 功 能
5.4.2 使 用 接 口 的 优 点 例 5-9 使 用 多 重 接 口 的 例 子 // MultInterfaces.java interface I1 { abstract void test(int i); interface I2 { abstract void test(string s); public class MultInterfaces implements I1, I2 { public void test(int i) { System.out.println("In MultInterfaces.I1.test"); public void test(string s) { System.out.println("In MultInterfaces.I2.test"); public static void main(string[] a) { MultInterfaces t = new MultInterfaces(); t.test(42); t.test("hello");
第 5 章 面 向 对 象 高 级 程 序 设 计 5.1 继 承 5.2 多 态 性 5.3 抽 象 类 和 抽 象 方 法 5.4 接 口 5.5 内 部 类 和 匿 名 类
5.5 内 部 类 和 匿 名 类 5.5.1 内 部 类 的 定 义 5.5.2 内 部 类 特 性 5.5.3 匿 名 类
5.5.1 内 部 类 的 定 义 简 单 地 说, 一 个 类 被 嵌 套 定 义 于 另 一 个 类 中, 称 为 嵌 套 类 在 大 多 数 情 况 下, 嵌 套 类 ( 静 态 的 嵌 套 类 除 外 ) 就 是 内 部 类 (inner class) 包 含 内 部 类 的 类 称 为 外 部 类 与 一 般 的 类 相 同, 内 部 类 具 有 自 己 的 成 员 变 量 和 成 员 方 法 通 过 建 立 内 部 类 的 对 象, 可 以 存 取 其 成 员 变 量 和 调 用 其 成 员 方 法 例 如 下 面 的 例 子 : pubic class GroupOne{ int count; // 外 部 类 的 成 员 变 量 public class Student{ // 声 明 内 部 类 String name; // 内 部 类 的 成 员 变 量 public void output(){ // 内 部 类 的 成 员 方 法 System.out.println(this.name+" ");
5.5.1 内 部 类 的 定 义 实 际 上,Java 语 言 规 范 对 于 内 部 类 有 如 下 的 规 定 : 在 另 一 个 类 或 者 一 个 接 口 中 声 明 一 个 类 在 另 一 个 接 口 或 者 一 个 类 中 声 明 一 个 接 口 在 一 个 方 法 中 声 明 一 个 类 类 和 接 口 声 明 可 嵌 套 任 意 深 度 从 上 面 的 规 定 中 我 们 可 以 看 出, 内 部 类 的 定 义 是 非 常 灵 活 的
5.5.2 内 部 类 特 性 内 部 类 有 如 下 特 性 : 一 般 用 在 定 义 它 的 类 或 语 句 块 之 内, 在 外 部 引 用 它 时 必 须 给 出 完 整 的 名 称 名 称 不 能 与 包 含 它 的 类 名 相 同 可 以 使 用 包 含 它 的 外 部 类 的 静 态 成 员 变 量 和 实 例 成 员 变 量, 也 可 以 使 用 它 所 在 方 法 的 局 部 变 量 可 以 定 义 为 abstract 可 以 声 明 为 private 或 protected 若 被 声 明 为 static, 就 变 成 了 顶 层 类, 不 能 再 使 用 局 部 变 量 若 想 在 内 部 类 中 声 明 任 何 static 成 员, 则 该 内 部 类 必 须 声 明 为 static Java 将 内 部 类 作 为 外 部 类 的 一 个 成 员, 就 如 同 成 员 变 量 和 成 员 方 法 一 样 因 此 外 部 类 与 内 部 类 的 访 问 原 则 是 : 在 外 部 类 中, 通 过 一 个 内 部 类 的 对 象 引 用 内 部 类 中 的 成 员 ; 反 之, 在 内 部 类 中 可 以 直 接 引 用 它 的 外 部 类 的 成 员, 包 括 静 态 成 员 实 例 成 员 及 私 有 成 员
5.5.2 内 部 类 特 性 例 5-10 内 部 类 和 外 部 类 之 间 的 访 问 本 例 的 类 GroupTwo 中 声 明 了 成 员 变 量 count 内 部 类 Student 实 例 方 法 output 和 main 方 法, 在 内 部 类 Student 中 声 明 了 构 造 方 法 和 output 方 法, 构 造 方 法 存 取 了 外 部 类 GroupTwo 的 成 员 变 量 count 程 序 运 行 结 果 : Johnson count=1 本 例 演 示 嵌 套 的 两 个 类 之 间 的 访 问 规 则, 即 在 外 部 类 GroupTwo 中, 通 过 一 个 内 部 类 Student 的 对 象 s1 可 以 引 用 内 部 类 中 的 成 员 ; 反 之, 在 内 部 类 Student 中 可 以 直 接 引 用 它 的 外 部 类 的 成 员, 如 count 本 例 的 外 部 类 GroupTwo 中 有 实 例 方 法 output(), 内 部 类 Student 中 也 有 实 例 方 法 output(), 两 者 虽 然 同 名, 却 表 达 不 同 含 义 使 用 时, 外 部 类 GroupTwo 的 对 象 调 用 GroupTwo 的 output, 如 g2.output(), 内 部 类 Student 的 对 象 调 用 Student 的 output, 如 s1.output()
5.5.2 内 部 类 特 性 public class GroupTwo{ // 例 5-10 private int count; // 外 部 类 的 私 有 成 员 变 量 public class Student { // 声 明 内 部 类 String name; public Student(String n1) { name=n1; count++; // 存 取 其 外 部 类 的 成 员 变 量 public void output(){ System.out.println(this.name); public void output(){ // 外 部 类 的 实 例 成 员 方 法 Student s1=new Student("Johnson"); // 建 立 内 部 类 对 象 " s1.output(); // 通 过 s1 调 用 内 部 类 的 成 员 方 法 System.out.println("count="+this.count); public static void main(string args[]){ GroupTwo g2=new GroupTwo(); g2.output();
5.5.2 内 部 类 特 性 例 5-11 内 部 类 访 问 外 部 静 态 变 量 例 5-12 静 态 公 用 内 部 类 例 5-13 抽 象 内 部 类 例 5-14 内 部 接 口 例 5-15 局 部 内 部 类
5.5.3 匿 名 类 匿 名 类 是 不 能 有 名 称 的 类, 所 以 没 办 法 引 用 它 们 必 须 在 创 建 时, 作 为 new 语 句 的 一 部 分 来 声 明 它 们 要 采 用 另 一 种 形 式 的 new 语 句, 如 下 所 示 : new < 类 或 接 口 > < 类 的 主 体 > 这 种 形 式 的 new 语 句 声 明 一 个 新 的 匿 名 类, 它 对 一 个 给 定 的 类 进 行 扩 展, 或 者 实 现 一 个 给 定 的 接 口 它 还 创 建 那 个 类 的 一 个 新 实 例, 并 把 它 作 为 语 句 的 结 果 而 返 回 要 扩 展 的 类 和 要 实 现 的 接 口 是 new 语 句 的 操 作 数, 后 跟 匿 名 类 的 主 体 从 技 术 上 说, 匿 名 类 可 被 视 为 非 静 态 的 内 部 类, 所 以 它 们 具 有 和 方 法 内 部 声 明 的 非 静 态 内 部 类 一 样 的 权 限 和 限 制 有 关 匿 名 类 的 使 用 详 见 本 书 第 12 章 本 分 内 容 内 部 和 匿 名 类 是 Java 为 我 们 提 供 的 两 个 出 色 的 工 具 它 们 提 供 了 更 好 的 封 装, 结 果 就 是 使 代 码 更 容 易 理 解 和 维 护, 使 相 关 的 类 都 能 存 在 于 同 一 个 源 代 码 文 件 中 ( 这 要 归 功 于 内 部 类 ), 并 能 避 免 一 个 程 序 产 生 大 量 非 常 小 的 类 ( 这 要 归 功 于 匿 名 类 )