admon
Uploaded by
49 SLIDES
764 VUES
490LIKES

第 5 章 类的继承性与多态性

DESCRIPTION

第 5 章 类的继承性与多态性. 主要任务 : 介绍类的继承性和多态性,以及一些 相关问题。. 本章主要内容. 1. 类的继承 2. 类的多态. 5.1 类的继承. 什么是类的继承? 新类可从现有的类中产生,将保留现有类的状态属性和方法并可根据需要加以修改。新类还可添加新的状态属性和方法,这些新增功能允许以统一的风格处理不同类型的数据。这种现象就称为类的继承。. 5.1.1 父类和子类.

1 / 49

Télécharger la présentation

第 5 章 类的继承性与多态性

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第5章 类的继承性与多态性 主要任务: 介绍类的继承性和多态性,以及一些 相关问题。

  2. 本章主要内容 • 1.类的继承 • 2.类的多态

  3. 5.1 类的继承 • 什么是类的继承? • 新类可从现有的类中产生,将保留现有类的状态属性和方法并可根据需要加以修改。新类还可添加新的状态属性和方法,这些新增功能允许以统一的风格处理不同类型的数据。这种现象就称为类的继承。

  4. 5.1.1 父类和子类 • 当建立一个新类时,不必写出全部成员变量和成员方法。只要简单地声明这个类是从一个已定义的类继承下来的,就可以引用被继承类的全部成员。被继承的类称为父类或超类(superclass),这个新类称为子类。

  5. 在类的声明语句中加入extends关键字和指定的类名即可实现类的继承,例如:在类的声明语句中加入extends关键字和指定的类名即可实现类的继承,例如: public class MyApplet extends java.applet.Applet public class MyApplication extends Frame public class MyApp1 extends Object public class MyApp2 • 第一条语句声明子类MyApplet的父类是Applet,并指明Applet的层次结构;第二条语句声明子类MyApplication的父类是Frame;第三条语句声明子类MyApp1的父类是Object,但编程中通常会省略extends Object子句;第四条语句在字面上没有extends,但实际上等价于public class MyApp2 extends Object。

  6. 类的继承的模拟图

  7. 图反映了什么? • 图5.1反映了Java类的层次结构。最顶端的类是Object,它在java.lang中定义,是所有类的始祖。一个类可以有多个子类,也可以没有子类,但它必定有一个父类(Object除外)。 • 子类不能继承父类中的private成员,除此之外,其它所有的成员都可以通过继承变为子类的成员。另一方面,对继承的理解应该扩展到整个父类的分支,也就是说,子类继承的成员实际上是整个父系的所有成员。例如,toString这个方法是在Object中声明的,被层层继承了下来,用于输出当前对象的基本信息。

  8. 结论: • 子类只能有一个父类。如果省略了extends,子类的父类是Object。子类继承了父类和祖先的成员,可以使用这些成员。在需要的时候,子类可以添加新的成员变量和方法,也可以隐藏父类的成员变量或覆盖父类的成员方法。

  9. 5.1.2 成员变量的继承和隐藏 • 1.成员变量的继承 • 2.成员变量的隐藏

  10. 例5.1 下面的三个程序说明从点Point类扩展到线Line类和圆Circle类的方法,这是三个公共类,不能放在同一个文件中。它们都没有输出语句,如果运行看不到什么结果。 public class Point { protected int x, y; Point(int a, int b) {setPoint(a, b);} public void setPoint(int a, int b) { x=a; y=b; } public int getX() {return x;} public int getY() {return y;} }

  11. public class Line extends Point { protected int x, y, endX, endY; Line(int x1, int y1, int x2, int y2) {setLine(x1, y1, x2, y2);} public void setLine(int x1, int y1, int x2, int y2) { x=x1; y=y1; endX=x2; endY=y2; }

  12. public int getX() {return x ;} public int getY() {return y ;} public int getEndX() {return endX;} public int getEndY() {return endY;} public double length() { return Math.sqrt((endX-x) * (endX-x) + (endY-y) * (endY-y)); } }

  13. public class Circle extends Point { protected int radius; Circle(int a, int b, int r) { super(a, b); setRadius(r); } public void setRadius(int r) {radius=r;} public int getRadius() {return radius;} public double area() {return 3.14159*radius*radius;} }

  14. Point 的成员 x, y // 受保护的成员变量,代表点的坐标 Point // 点的构造方法 setPoint // 设定点的坐标值的方法 getX, getY // 返回坐标x和y的值的方法

  15. Line 的成员 x, y, endX, endY // 子类受保护的成员变量,代表线的两个端点坐标 Line // 线的构造方法 setLine // 设定线的两个端点坐标值的方法 getX, getY // 返回起点坐标x和y的值的方法 getEndX, getEndY // 返回终点坐标endX和endY的值的方法 length // 返回线的长度的方法 x, y // 继承父类的受保护成员变 量,但被子类隐藏 setPoint // 继承父类的方法 getX, getY // 继承父类的方法,但被子类覆盖

  16. Circle 的成员 radius // 子类受保护的成员变量,代表圆的半径 Circle // 圆的构造方法 setRadius // 设定半径值的方法 getRadius // 返回半径值的方法 area // 返回圆面积的方法 x, y // 继承父类的受保护成员变量 setPoint // 继承父类的方法 getX, getY // 继承父类的方法

  17. 2.成员变量的隐藏 • 所谓隐藏是指子类重新定义了父类中的同名变量,如子类Line重新定义了x为x1,y为y1,隐藏了父类Point中的两个成员变量x和y。子类执行自己的方法时,操作的是子类的变量,子类执行父类的方法时,操作的是父类的变量。在子类中要特别注意成员变量的命名,防止无意中隐藏了父类的关键成员变量,这有可能给你的程序带来麻烦。 • Line还覆盖了Point的两个方法getX和getY。

  18. 5.1.3 成员方法的覆盖 • 已知通过继承子类可以继承父类中所有可以被子类访问的成员方法,但如果子类的方法与父类方法同名,则不能继承,此时称子类的方法覆盖了父类的那个方法,简称为方法覆盖。方法的覆盖(override),为子类提供了修改父类成员方法的能力。例如,子类可以修改层层继承下来的toString方法,让它输出一些更有用的信息。下面的例子显示了在子类Circle中添加toString方法,用来返回圆半径和圆面积信息。

  19. 例5.2 对Object的toString方法的覆盖。结果如图所示。

  20. class Circle { private int radius; Circle(int r) {setRadius(r);} public void setRadius(int r) {radius=r;} public int getRadius() {return radius;} public double area() {return 3.14159*radius*radius;} public String toString() { return "圆半径:"+getRadius()+" 圆面积:"+area(); } }

  21. public class O1 { public static void main(String args[]) { Circle c=new Circle(10); System.out.println("\n"+c.toString()); } } • 程序中改写了上一节介绍的Circle,添加了toString方法并修改了它的返回值。由于toString和继承下来的方法名相同、返回值类型相同,因此就覆盖了父类中的toString方法。而父类Point中的toString方法尽管没有显示出来,它仍然存在,它是从Object中继承下来的。

  22. 方法覆盖时要特别注意: • 用来覆盖的子类方法应和被覆盖的父类方法保持同名、同返回值类型,以及相同的参数个数和参数类型。如果被覆盖的方法没有声明抛出异常,子类的覆盖方法可以有不同的抛出异常子句。 • 有时,可能不需要完全覆盖一个方法,可以部分覆盖一个方法。部分覆盖是在原方法的基础上添加新的功能,即在子类的覆盖方法中添加一条语句:super.原父类方法名,然后加入其它语句。

  23. 5.1.4 this和super • 例5.3 this和super的使用。运行结果如图所示。

  24. class Point { protected int x, y; Point(int a, int b) {setPoint(a, b);} public void setPoint(int a, int b) { x=a; y=b; } }

  25. class Line extends Point { protected int x, y; Line(int a, int b) { super(a, b); setLine(a, b); } public void setLine(int x, int y) { this.x=x+x; this.y=y+y; }

  26. public double length() { int x1=super.x, y1=super.y, x2=this.x, y2=this.y; return Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)); } public String toString() { return "直线端点:[" + super.x + "," + super.y + "] [" + x + "," + y + "] 直线长度:" + this.length(); } }

  27. public class ThisDemo { public static void main(String args[]) { Line line=new Line(50, 50); System.out.println("\n"+line.toString()); } }

  28. this和super 的作用: (1)this实际代表的是当前类或对象本身。 • 在一个类中,this表示对当前类的引用,在使用类的成员时隐含着this引用,尽管可以不明确地写出,例如length和toString中对x和y的使用。当一个类被实例化为一个对象时,this就是对象名的另一种表示。通过this可顺利地访问对象,凡在需要使用对象名的地方均可用this代替。

  29. (2)super代表着父类 • 如果子类的变量隐藏了父类的变量,使用不加引用的变量一定是子类的变量,如果使用父类的变量,就必须加上super引用。同样道理,如果有方法覆盖的发生,调用父类的方法时也必须加上super引用。

  30. 例5.4 了解下面两个类中super的使用。运行结果如图所示。

  31. (3)super() 可用来调用父类的构造方法。 • 这也是唯一由程序员间接调用类的构造方法的途径,因为Java规定类的构造方法只能由new操作符调用,程序员不能直接调用。同理,this() 也可用来间接调用当前类或对象的构造方法。 • 类的构造方法是不能继承的,因为构造方法不是类的成员,没有返回值,也不需要修饰符。又由于父类的构造方法和父类同名,在子类中继承父类的构造方法肯定和子类不同名,这样的继承是无意义的。

  32. 5.2 类的多态 • 类的继承发生在多个类之间,而类的多态只发生在同一个类上。在一个类中,可以定义多个同名的方法,只要确定它们的参数个数和类型不同。这种现象称为类的多态。 • 多态使程序简洁,为程序员带来很大便利。在OOP中,当程序要实现多个相近的功能时,就给相应的方法起一个共同的名字,用不同的参数代表不同的功能。这样,在使用方法时不论传递什么参数,只要能被程序识别就可以得到确定的结果。 • 类的多态性体现在方法的重载(overload)上,包括成员方法和构造方法的重载。

  33. 5.2.1 成员方法的重载 • 方法的重载是指对同名方法的不同使用方式。 • 看下面这个例子。

  34. 例5.5 对不同的数进行排序输出,运行结果见图。

  35. import java.awt.Graphics; import java.applet.Applet; class IntSort { public String sort(int a, int b) { if (a>b) return a+" "+b; else return b+" "+a; }

  36. public String sort(int a, int b, int c) { int swap; if (a<b) { swap=a; a=b; b=swap; } if (a<c) { swap=a; a=c; c=swap; }

  37. if (b<c) { swap=b; b=c; c=swap; } return a+" "+b+" "+c; } public String sort(int arr[]) { String s=" "; int swap;

  38. for (int i=0; i<arr.length; i++) for (int j=0; j<arr.length-1; j++) if (arr[j]>arr[j+1]) { swap=arr[j]; arr[j]=arr[j+1]; arr[j+1]=swap; } for (int i=0; i<arr.length; i++) s=s+arr[i]+" "; return s; } }

  39. public class Class2 extends Applet { IntSort s=new IntSort(); public void paint(Graphics g) { int a=30, b=12, c=40; int arr[]={34,8,12,67,44,98,52,23,16,16}; g.drawString("两个数的排序结果:"+s.sort(a,b),30,30); g.drawString("三个数的排序结果:"+s.sort(a,b,c),30,60); g.drawString("数组的排序结果:"+s.sort(arr),30,90); } }

  40. 程序中调用了IntSort类的构造方法,但这个构造方法并没有在IntSort中出现,它是怎么来的呢?程序中调用了IntSort类的构造方法,但这个构造方法并没有在IntSort中出现,它是怎么来的呢? • 每一个类都有一个缺省的构造方法,这就是和类同名的无参构造方法。它实际上是父类的构造方法,创建子类时由父类自动提供。因此,每个类的对象都可以使用这种方式来初始化对象。如同为变量声明数据类型一样,可为对象声明类的类型。如果在初始化对象时需要对象具有更多的特性,可重载构造方法。

  41. 5.2.2 构造方法的重载 • 重载构造方法的目的: 提供多种初始化对象的能力,使程序员可以根据实际需要选用合适的构造方法来初始化对象。

  42. 例5.6 构造方法的重载。运行结果如图所示.

  43. class RunDemo { private String userName, password; RunDemo() { System.out.println("All is null!"); } RunDemo(String name) { userName=name; } RunDemo(String name, String pwd) { this(name); password=pwd; check(); }

  44. void check() { String s=null; if (userName!=null) s="用户名:"+userName; else s="用户名不能为空!"; if (password!="ThisWord") s=s+" 口令无效!"; else s=s+" 口令:********"; System.out.println(s); } }

  45. public class D1 { public static void main(String[] args) { new RunDemo(); new RunDemo("Bill"); new RunDemo(null,"Bill"); new RunDemo("Bill","ThisWord"); } }

  46. 习 题 1.什么是类的继承性?子类和父类有什 么关系? 2.什么是类的多态性? 3.何为隐藏、覆盖、重载? 4.this和super类有什么作用? 5.什么是构造方法? 6.构造方法有何特点和作用?

  47. 7.分析下面这段程序,指出父类、子类以及它们的成员,成员的作用是什么?7.分析下面这段程序,指出父类、子类以及它们的成员,成员的作用是什么? class Point { int x, y; Point(int a, int b) {setPoint(a,b);} public void setPoint(int a, int b) {x=a; y=b;} } class Circle extends Point { int radius; Circle(int a, int b, int r) {super(a,b); setRadius(r);} public void setRadius(int r) {radius=r;} public double area() {return 3.14159*radius*radius;} }

  48. 8.给出下面的代码: • class Person { •       String name,department; •       public void printValue(){ •          System.out.println("name is "+name); •          System.out.println("department is "+department); •       } •    } •    public class Teacher extends Person { •       int salary; •       public void printValue(){ •          ———————— •          System.out.println("salary is "+salary); •       } •    } • 下面的哪些表达式可以加入到Teacher类的 printValue()方法中?为什么?(D) • A. printValue(); • B. this.printValue(); • C. person.printValue(); • D. super.printValue().

  49. 9.创建一个Fraction类执行分数运算。要求如下:9.创建一个Fraction类执行分数运算。要求如下: ⑴ 用整型数表示类的private成员变量:f1和f2。 ⑵ 提供构造方法,将分子存入f1,分母存入f2。 ⑶ 提供两个分数相加的运算方法,结果分别存入f1和f2。 ⑷ 提供两个分数相减的运算方法,结果分别存入f1和f2。 ⑸ 提供两个分数相乘的运算方法,结果分别存入f1和f2。 ⑹ 提供两个分数相除的运算方法,结果分别存入f1和f2。 ⑺ 以a/b的形式打印Fraction数。 ⑻ 以浮点数的形式打印Fraction数。 ⑼ 编写主控程序运行分数运算。

More Related