抽象类与接口Java.ppt_第1页
抽象类与接口Java.ppt_第2页
抽象类与接口Java.ppt_第3页
抽象类与接口Java.ppt_第4页
抽象类与接口Java.ppt_第5页
已阅读5页,还剩78页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章 抽象类与接口 讲师: 200906 08,目 标,当完成本章后,你应该能够: 理解抽象方法 理解抽象类 从抽象类继承 理解并使用接口 实现接口 从接口继承,抽象类,从形状开始 抽象方法 抽象类,从形状开始,要开发一个图形系统 首先要定义相关的图形类 主要有: 三角形 平行四边形 矩形 正方形 ,父类,根据继承的知识 以及形状之间的关系 设计了所有形状类的父类 类 Shape 该类的方法在继承时需要被覆盖 Shape.java,父类 Shape,未定义成员变量 成员方法如下: public Shape(); public double getPerimeter(); public double getArea(); public void draw();,周长和面积,这是任何形状都有的属性 返回类型是 double 由于 Shape 是所有形状的父类 并不是具体的形状 那么这两个方法的方法体能否为空呢? 答案是不能为空 因为方法的返回类型是 double 这两个方法必须返回一个 double 类型的值 否则产生编译错误,不能通过编译,编译错误,把两句 return 0.0; 注释后重新编译程序 srcShape.java:9: 缺少返回语句 srcShape.java:13: 缺少返回语句 2 错误,子类 Triangle,设计并实现子类三角形 Triangle Triangle.java 成员: private double a; private double b; private double c; public Triangle(); public Triangle(double a, double b, double c); public double getPerimeter(); public double getArea(); public void draw();,子类 parallelogram,设计并实现子类平行四边形 parallelogram Parallelogram.java 成员: private double a; private double b; private double theta; public Parallelogram(); public Parallelogram(double a, double b, double theta); public double getA(); public double getB(); public double getPerimeter(); public double getArea(); public void draw();,Math.sin(theta),小问题 但影响最终计算结果 经常使用角度 但该方法使用的是 弧度 角度 转换为 弧度,子类 Rectangle,设计并实现子类矩形 rectangle Rectangle.java 该类从 Parallelogram 而非 Shape 进行继承 成员: public Rectangle(); public Rectangle(double a, double b); public void draw();,子类 Rectangle,构造器的编写 通过 super 来调用父类的构造器 角度的赋值 计算周长和面积 通过构造器已经完成了成员变量的赋值 因此该类不需要覆盖父类的这两个方法,子类 Square,设计并实现子类正方形 square Square.java 该类从 Rectangle 进行继承 成员: public Square(); public Square(double a); public void draw();,子类 Square,构造器的写法 与其父类 Rectangle 类似 该类不需要覆盖计算周长和面积的方法,类图,可能的副作用,成员的继承 包括成员变量和成员方法 父类的修改对于子类的影响 子类对于父类有较强的依赖性 耦合,coupling 原则: 低耦合,高内聚,分析,父类 Shape 两个方法的方法体没有任何实际意义 但是为了编译能够通过 不能删去返回语句 可是返回的值又没有任何实际意义 两难境地 What can we do?,解决办法,可以告诉编译器 压根儿就没想实现这两个方法 因为即使定义了方法体 也没有任何实际用处 那还不如根本就别定义方法体 不想实现的方法 只有方法头部,没有方法体 抽象方法,抽象方法,不需要实现的方法 之后方法的头部 没有方法体 用分号;代替正常的一对大括号 语法: public double getPerimeter(); public double getArea(); 重新编译 Shape.java,编译错误,srccnpetershapeShape.java:9: 缺少方法主体,或声明抽象 public double getPerimeter(); srccnpetershapeShape.java:11: 缺少方法主体,或声明抽象 public double getArea(); 2 错误,抽象方法,必须把方法声明为抽象的 使用 Java 语言的关键字 abstract 改成如下形式: public abstract double getPerimeter(); public abstract double getArea(); public abstract void draw(); 重新编译 Shape.java,编译错误,srccnpetershapeShape.java:4: cn.peter.shape.Shape 不是抽象的,并且未覆盖 cn.peter.shape.Shape 中的抽象方法 getArea() public class Shape 1 错误,抽象类,如果一个类中有一个或多个的抽象方法,则该类必须声明为抽象的,成为抽象类 方法: public abstract class Shape 重新编译 Shape.java,编译错误,srccnpetershapeShape.java:17: cn.peter.shape.Shape 是抽象的 无法对其进行实例化 Shape s = new Shape(); 1 错误,原因分析,因为抽象类中可能有抽象方法,而抽象方法没有方法体,是不完整的 因此不允许创建抽象类的实例 抽象类不能实例化 new 后面不能出现抽象类 把类 Shape 的 main() 方法体注释 重新编译 Shape.java 重新编译其它子类的文件 javac -d classes srccnpetershape*.java,类图 (抽象类版本),抽象方法,如果一个方法用 abstract 修饰 成为抽象方法 则该方法不能用以下修饰符修饰: private final static,抽象方法,没有方法体的方法 用分号; 代替了一对大括号 该方法在其所属的类被继承时由其子类实现 即 方法覆盖 称 实现父类的抽象方法,抽象类,如果一个类中有一个或多个抽象方法 则该类必须声明为抽象类 否则产生编译错误,不能通过编译 抽象类不能实例化 不能创建抽象类的对象 new 后不能出现抽象类的名称,抽象类,抽象类不能实例化,不能创建对象 那有什么用呢? 专职工作: 父类 与 final 类恰好相反 final 类不能被继承,不能做父类 而抽象类不能实例化,只能做父类,抽象类的子类,一个类如果从抽象类来继承 那么该类有两种选择: (1) 实现其父类所有的抽象方法 从而可以不声明为抽象类 (2) 如果至少有一个抽象方法没有实现 那么该子类也必须声明为抽象类 否则产生编译错误,不能通过编译,抽象类的好处,如果一个类从其父类 (抽象类) 继承 而该类不想作为抽象类 那么它必须实现其父类所有的抽象方法 如果有一个方法忘记实现 同时该类又没有声明为抽象类 则产生编译错误,不能通过编译,抽象类的好处,通过编译器强制必须实现指定的方法 例如,抽象父类 Shape 有以下抽象方法: public abstract double getPerimeter(); public abstract double getArea(); public abstract void draw(); 那么,该类的所有直接子类或间接子类 必须实现这三种方法 否则,该子类就必须声明为抽象类,实现父类的抽象方法,不一定每一个直接或间接子类 都必须由自己来亲自实现这三个方法 例如,类 Parallelogram 实现了这三个方法 而类 Rectangle 和类 Square 直接或间接从类Parallelogram 继承 这二者只覆盖了 draw() 方法 从其父类继承了 getPerimeter() 方法和 getArea() 方法,抽象类的句柄,虽然不能创建抽象类的对象 但是依然可以声明抽象类的句柄 例如 Shape s = new Triangle(); 一个类的句柄 可以引用其所有直接或间接子类的对象 这是由继承的语义得到的 这一点非常重要,也非常普遍 在多态中会详细讨论,抽象类例子,类 java.lang.Number 即为一个抽象类 其抽象方法有: public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue();,非抽象方法,同时还有非抽象方法: public byte byteValue() return (byte) intValue(); public short shortValue() return (short) intValue(); 这说明 在抽象类中,非抽象方法可以调用抽象方法,Number 的子类,该抽象类的子类有: java.lang.Byte java.lang.Short java.lang.Integer java.lang.Long java.lang.Float java.lang.Double java.math.BigInteger java.math.BigDecimal java.util.concurrent.atomic.AtomicInteger java.util.concurrent.atomic.AtomicLong,特殊的抽象类,如果一个类没有任何抽象方法 那么,该类也可以声明为抽象类 结果,该类同样不能实例化 不能创建对象 这种情况比较少见 例子 java.awt.event.MouseAdapter,MouseAdapter,该类的成员方法: public void mouseClicked(MouseEvent e) public void mousePressed(MouseEvent e) public void mouseReleased(MouseEvent e) public void mouseEntered(MouseEvent e) public void mouseExited(MouseEvent e) 目的: 程序员不能直接创建该类的对象 必须从该类继承后再实例化 继承时可覆盖该类的 05 个方法 一般情况覆盖其中的 12 个方法,抽象类,包含抽象方法的类必须声明为 抽象类 抽象类也可以没有任何抽象方法 抽象类不能实例化 抽象类主要作为父类被继承 在设计类的层次结构时抽象类很有用,抽象类,Java 语言只支持单继承 一个类最多也只能有一个直接父类 在定义类时经常会遇到下列情况 一个类 C 具有多方面的特征 既是一个 A,同时又是一个 B 可是 Java 又不支持多重继承 怎么办呢? 解决方法:使用 接口,interface,接口,父类的选择 接口 接口的继承 接口的例子,抽象类,一个抽象类中可能有抽象方法 该抽象方法被延迟到 子类继承该抽象类时实现 从抽象类继承,父类的选择,在定义类时经常会遇到下列情况 一个类 C 具有多方面的特征 既是一个 A,同时又是一个 B 可是 Java 又不支持多重继承 只支持单继承 一个类最多也只能有一个直接父类 对 C 而言,A 和 B 只能选择一个作为父类 怎么办呢?,例子,文具管理系统 要定义 铅笔 Pencil 橡皮 Rubber 橡皮铅笔 RubberPencil 涂改液 CorrectionFluid,铅笔,打包 cn.peter.stationery Pencil.java 成员: private String type; public Pencil(); public Pencil(String type); public String getType(); public void setType(); public void write(String s);,橡皮,打包 cn.peter.stationery Rubber.java 成员: public Rubber(); public void erase(String s);,橡皮铅笔,打包 cn.peter.stationery RubberPencil.java 父类的选择 Pencil 或 Rubber 二者最多只能选一个,橡皮铅笔,一种不得已的办法: 选择 Pencil 作为父类 同时实现类 Rubber 的方法 主要和次要 主要:铅笔 Pencil 次要:橡皮 Rubber,橡皮铅笔,成员: public RubberPencil(); public RubberPencil(String type); public void write(String s); public void erase(String s); 其中方法 write(String) 覆盖了父类的方法 同时从父类 Pencil 继承得到成员方法: public String getType(); public void setType();,涂改液,打包 cn.peter.stationery CorrectionFluid.java 成员: public CorrectionFluid(); public void erase(String s);,类图,改进方案,由类图可以看出 类 Rubber 与类 CorrectionFluid 有共同的方法 erase(String) 可以定义一个新的类 Eraser 唯一的成员是一个抽象方法: public void erase(String s); 同时类 Eraser 声明为抽象类 类 Rubber、CorrectionFluid 均从该抽象类继承,类图 (抽象类版本),问题,类 Rubber 与类 CorrectionFluid 继承了抽象类 Eraser 并实现了方法 erase(String) 但是 RubberPencil 与上述类仍然毫无关系 因此,如果该类没有实现 erase(String) 方法 也不会导致编译错误 这是因为该类只是从类 Pencil 继承 与抽象类 Eraser 无关,问题,但是 类 RubberPencil 的确实现了抽象类 Eraser的唯一抽象方法 erase(String) 但由于只能有一个直接父类 类 RubberPencil 选择了 Pencil 而对于类 Eraser 则只能忍痛割爱 能否有两全其美的办法呢?,解决办法,使用 接口,interface,接口,使用关键字 interface 进行定义 把抽象类 Eraser 改成接口 抽象类: public abstract class Eraser public abstract void erase(String s); 接口: public interface Eraser void erase(String s); ,接口的特点,接口中的方法 默认都是 public abstract 接口中不允许存在非抽象方法 即有方法体的方法 接口中的成员变量 默认都是 public static final,修改原有程序,Eraser 从抽象类变成接口后 原有程序要做哪些修改呢? 抽象类 因为抽象类 Eraser 不存在了 因此不能从该抽象类继承了,类与接口,类与类:继承,extends 类与接口:实现,implements 修改原抽象类 Eraser 的子类 Rubber 及 CorrectionFluid 把 extends Eraser 修改为 implements Eraser,区别,一个类从其父类继承 与实现一个接口 有什么区别呢? 一个类实现一个接口的同时 还可以从另外一个类来继承 可以达到多重继承的效果 同时又不违背单继承的原则,橡皮铅笔,该类 RubberPencil 则修改为: public class RubberPencil extends Pencil implements Eraser public RubberPencil(); public RubberPencil(String type); public void write(String s); public void erase(String s); 唯一的变化是增加了 implements Eraser,原有问题的解决,抽象类版本的程序 如果类 RubberPencil 忘记实现了方法 erase(String) 则不会产生编译错误 当然,前提是 main() 中没有调用该方法 接口版本的程序 由编译器强制保证类 RubberPencil 一定要实现方法 erase(String),类实现接口,一个类如果实现了某个接口 就必须实现该接口的所有方法 除非该类声明为抽象类 这些方法则被延迟到该类的子类来实现 由于类 RubberPencil 没有声明为抽象类 因此必须实现接口 Eraser 的方法 否则产生编译错误,不能通过编译 把类 RubberPencil 的 erase(String) 方法和 main() 方法注释,重新编译,编译错误,srccnpeterstationeryRubberPencil.java:4: cn.peter.stationery.RubberPencil 不是抽象的,并且未覆盖 cn.peter.stationery.Eraser 中的抽象方法 erase(java.lang.String) public class RubberPencil extends Pencil 1 错误,类图 (接口版本),类的定义,一个类 最多只能有一个直接父类 但同时可实现若干个接口 即实现接口的数量没有限制,接口的继承,一个接口的主要作用是被类来实现 同时也能被另外一个接口来继承 即,接口可以继承 父接口、子接口 关键字 类继承父类: extends 类实现接口: implements 接口继承接口:extends,接口的继承,使用关键字 extends 语法 public interface A extends B / 方法列表 如果某个类实现了接口 A 那么该类必须实现接口 A 及其父接口 B 所有的方法 除非该类声明为抽象类,接口的例子,字符序列 java.lang.CharSequence 代表一个字符序列,可从中进行读取 成员: int length(); char charAt(int index); CharSequence subSequence(int start, int end); public String toString(); 实现该接口的类: String StringBuffer StringBuilder,接口的例子,可比较的 java.lang.Comparable 该接口只有一个方法 public int compareTo(T o);

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论