实验4 继承、多态、抽象类、接口_第1页
实验4 继承、多态、抽象类、接口_第2页
实验4 继承、多态、抽象类、接口_第3页
实验4 继承、多态、抽象类、接口_第4页
实验4 继承、多态、抽象类、接口_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

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

文档简介

实验4 继承、多态、抽象类、接口注意:有些程序由于Word的关系,复制后,tab缩位可能会变成其它符号。需要你去调整一下,删除缩位,重新Tab一、实验目的1二、实验要求1三、实验内容21. 类的继承与覆盖练习21.0 父类的哪些成员可以被继承?21.1 父类Student(学生)与子类HiStudent(大学生)21.2 实例方法为什么需要覆盖41.3 验证成员方法的覆盖方式51.4 this、super和super()的使用61.5 变量、静态方法的隐藏。91.6隐藏与覆盖的综合性实例102. 类的多态性练习112.1 普通方法的重载(实验3,本实验略)112.2 构造方法的重载(实验3,本实验略)112.3 运行时多态与动态绑定113. 抽象类134. 接口14一、实验目的通过编程和上机实验理解Java语言的面向对象特性,了解类的继承性和多态性的作用,掌握它们的实现方法,了解数据域和静态方法的隐藏,了解抽象类和接口的作用。二、实验要求1、 编写体现类的继承性(成员变量、成员方法、成员变量隐藏)的程序;2、 编写体现类的多态性的程序;3、 编写体现抽象类和接口功能的程序。三、实验内容1. 类的继承与覆盖练习例如,圆是一种形状。圆类Circle是形状类Shape的子类。父类也叫基类、超类,子类也叫次类、扩展类、派生类。子类可从父类中产生,保留父类的成员变量和方法,并可根据需要对它们加以修改。新类还可添加新的变量和方法。这种现象就称为类的继承。当建立一个父类时,不必写出全部成员变量和成员方法。只要简单地声明这个类是从一个已定义的类继承下来的,就可以引用被继承类的全部成员。Java 提供了一个庞大的类库让开发人员继承和使用。设计这些类是出于公用的目的,因此,很少有某个类恰恰满足你的需要。你必须设计自己的能处理实际问题的类,如果你设计的这个类仅仅实现了继承,和父类一样,那样没什么用。所以,通常要对父类进行扩展,即添加新的属性和方法。这使得子类要比父类大,但更具特殊性,代表着一组更具体的对象。继承的意义就在于此。1.0 父类的哪些成员可以被继承?可以访问的成员才能被继承。具体分2种情况: * 当父类和子类在同一个包时,子类可以继承父类中的public/protected/无修饰 级别的变量和方法; * 当父类和子类不在同一个包时,且父类是public的,那么子类可以继承父类的public/protected 级别的变量和方法。如果父类前没有public,那么子类无法访问父类,更谈不上继承的问题。1.1 父类Student(学生)与子类HiStudent(大学生)(1) Student.java程序源代码如下。public class Student /学生类protected String xm; /姓名protected int xh; /学号void setData(String m,int h) /设置姓名和学号xm =m;xh = h;public void print() /输出姓名和学号System.out.println(xm+, +xh); (2) HiStudent.java的描述和代码如下程序功能:通过Student类产生子类HiStudent,其不仅具有父类的成员变量xm(姓名)、xh(学号),还定义了新成员变量xy(学院)、xi(系)。在程序中调用了父类的print方法,同时可以看出子类也具有该方法。程序源代码如下public class HiStudent extends Student /大学生类继承自学生类protected String xy;/所在学院或大学名称protected String xi;/所在系的名称public static void main(String args)Student s1 = new Student();s1.setdata(李四,12321) ;s1.print();HiStudent s2 = new HiStudent() ;s2.setdata(张三,12345); /调用父类的成员方法s2.xy=XX大学; /访问本类的成员变量s2.xi=计算机系; /访问本类的成员变量s2.print();/调用父类的方法,就象调用它自己的一样System.out.print(s2.xm+, +s2.xy+, +s2.xi); (3)编译并运行,结果如下图所示。1.2 实例方法为什么需要覆盖上例中,s2.print();语句调用父类的方法,只能输出父类的数据(姓名和学号)。如果想用函数输出姓名、学号、学院、系,需要在子类中另外添加一个函数。如果这个函数也叫print(),(嗯,这样好记),并且如果形参、返回类型都一样,并且其可见性修饰符和父类print()方法的一样甚至更开放,并且它们都不是静态的,并且它所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类,或者什么也不抛出,那么,我们可以说子类的print()方法覆盖(override)了父类的print()方法。子类中添加的print()可以这样写:public void print() /输出姓名、学号、学院、系System.out.println(xm+, +xh+, +xy+, +xi);可见,子类的覆盖方法重写(修改)了父类的被覆盖方法。实现了不同的功能。当然,父类的被覆盖方法仍然存在,在子类中可以用super.print()来引用。嗯,如果参数不一样,那也叫重载。如果返回类型不一样,或者一个静态一个非静态,或者子类方法的开放性比父类被覆盖方法的更低,都会编译错。如果两个方法其它一样,又都是静态的,这没问题,叫做隐藏,而非覆盖。另外,父类中用final修饰的方法不能被覆盖。再重复一下方法覆盖的概念:如果在子类中定义一个方法,其名称、返回类型及参数签名正好与父类中某个方法的名称、返回类型及参数签名相匹配,那么可以说,子类的方法覆盖了父类的方法。覆盖的说明: 子类的方法名称返回类型及参数签名 必须与父类的一致 子类方法不能缩小父类方法的访问权限 子类方法不能抛出比父类方法更多的异常 方法覆盖只存在于子类和父类之间,同一个类中只能重载 父类的静态方法不能被子类覆盖为非静态方法 子类可以定义于父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法(满足覆盖约束), Java虚拟机把静态方法和所属的类绑定,而把实例方法和所属的实例绑定。 父类的非静态方法不能被子类覆盖为静态方法 父类的私有方法不能被子类覆盖 父类的抽象方法可以被子类通过两种途径覆盖(即实现和覆盖) 父类的非抽象方法可以被覆盖为抽象方法1.3 验证成员方法的覆盖方式方法覆盖为子类提供了修改父类实例方法的能力。例如,Object类的toString方法返回的字符串是“类名随机码”这样的。子类可以修改层层继承下来的Object 根类的toString 方法,让它输出一些更有用的信息。下面的程序显示了在子类Circle 中添加toString 方法,用来返回圆半径和圆面积信息。(1) 编写Circle类,覆盖Object 类的toString方法,Circle类和Test类源代码如下。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 Math.PI*radius*radius;public String toString() /覆盖继承自Object的toString()方法return 圆半径:+getRadius()+ 圆面积:+area();public class Testpublic static void main(String args) Circle c=new Circle(10);System.out.println(c.toString();1.4 this、super和super()的使用(1) 程序功能:说明this.、this()、super. 和super()的用法。程序首先定义Point(点)类,然后创建点的子类Line(线)。Line继承了Point的点,它自己又定义了一个点。最后通过Test类输出线段的长度。Line对象程序中通过super(a,b)调用父类Point 的构造方法为父类的x和y赋值。在子类Line 的setLine方法中,因为参数名和成员变量名相同,为给成员变量赋值,使用this 引用,告诉编译器是为当前类的成员变量赋值。在length 和toString 方法中使用父类成员变量时,使用super 引用,告诉编译器使用的是父类的成员变量。(2) 程序源代码如下。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;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;public double length() int x1=super.x, y1=super.y, x2=this.x, y2=this.y;/this.可省略return Math.sqrt(x2-x1) * (x2-x1) + (y2-y1) * (y2-y1);public String toString() return 直线端点: + super.x + , + super.y + +x + , + y + 直线长度: + this.length();public class Testpublic static void main(String args) Line line=new Line(50, 50);System.out.println(line.toString();说明:这个例子只为验证super(),super.,this.等的用法。当然,线并不是一种点,所以用Line继承Point不合适。用聚合的形式更合适些。例如可以如下修改:class Point protected int x, y;Point(int x, int y) setPoint(x, y);public void setPoint(int x, int y) this.x = x;this.y = y;class LinePoint a, b;public double length() return Math.sqrt(a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y);public Line()public Line(Point a, Point b)this.a = a;this.b = b;public Line(int x1, int y1, int x2, int y2)a = new Point(x1, y1);b = new Point(x2, y2);public class Testpublic static void main(String args) Line line=new Line(1,1,2,0);System.out.println(直线端点: + line.a.x + , + line.a.y + - +line.b.x + , + line.b.y + 直线长度: +line.length();1.5 变量、静态方法的隐藏。父类和子类定义了同名的变量,或者相同的静态方法。(1)父类和子类有相同的变量。父类变量被隐藏。将B类中的x所在行屏蔽起来或者不屏蔽,比较输出结果有何变化。class Aint x=1;class B extends A/int x = 2;void printX()/输出父类对象的x值System.out.println(super.x);/如果B类没有声明x,那么super.可省略。但如果B类也声明了变量x,那么父类的x被隐藏,要访问父类对象的成员,super.不能省略public class Testpublic static void main(String s)B p = new B();System.out.println(p.x);p.printX();/System.out.println(p.super.x);/语法错误。要用super.x引用B类的父类对象的成员,可以在B类中进行(2)父类和子类有相同的静态方法。父类静态方法被隐藏。下面B类中的print()方法,屏蔽或不屏蔽,输出结果有何不同?class Astatic void print()System.out.println(A);class B extends A/*static void print()System.out.println(B);*/public class Testpublic static void main(String s)B p = new B();p.print();【说明】上面A、B两类中的print()方法都是static的,称为静态方法隐藏。如果都是非静态的,则称为覆盖。如果其中一个是静态的,另一个非静态,则编译错,提示“无法覆盖”。1.6 隐藏与覆盖的综合性实例注意看蓝色或红色的注释。其中,红色的注释是容易出错的地方。class Aint x = 1;/被隐藏void print()/被覆盖System.out.println(这里是父类方法,x=+x);/父类A的方法中访问的变量必然是A类或A的父类的,不可能访问B类的。m();/父类A的方法中调用的实例方法m()是子类B的,由于发生了覆盖void m()/被覆盖System.out.println(这里是父类的实例方法m();static void m2()/被隐藏System.out.println(这里是父类的静态方法m2();class B extends Aint x = 2; void print()System.out.println(这里是子类方法,x=+x);/子类方法访问的变量是子类对象的(当然条件是子类中声明了这个变量)System.out.println(这里是子类方法,super.x=+super.x);/super.x是父类对象的super.print();/调用父类的print()方法m();/调用本对象的m()方法void m()System.out.println(这里是子类的实例方法m();static void m2()System.out.println(这里是子类的静态方法m2();public class Testpublic static void main(String s)A p = new B();System.out.println(p.x);/通过引用变量p来访问变量或静态方法,要看p的声明类型。所以x是A类的。p.m2();/同上。静态方法m2()是A类的。p.print();/通过引用变量p来访问实例方法,要看p指向的对象的实际类型。由于覆盖,调用的print()方法是子类的。2. 类的多态性练习c+允许多重继承(多个直接父类),功能强大,但复杂的继承关系也给c+开发者带来了很大麻烦。为了规避风险,java只允许单重继承,即,只能有一个直接父类,所以继承关系简单明了。但在功能上又给开发者提出了难题。因此,Java用多态性、抽象类、接口的概念来弥补此项不足。多态性: 在程序中同一符号或名字在不同情况下具有不同解释 编译时多态性: 指在程序编译阶段即可确定下来的多态性。重载发生时,编译器根据方法签名来确定未来会调用哪个方法。 运行时多态性: 指必须等到程序动态运行时才可确定的多态性,JVM根据引用变量指向的实际对象来绑定方法。2.1 普通方法的重载(参考实验3,本实验略)2.2 构造方法的重载(参考实验3,本实验略)2.3 运行时多态与动态绑定一组方法,在多个类中都有定义。由于继承与覆盖,到底调用哪个方法,需要根据不同的对象来进行动态绑定。因此结果呈现多态性。如果A是父类,B是子类,那么A p = new B();是合法的。p的类型被声明成A类型,但p实际上指向一个B类对象。(1) 如果A、B两类中都有实例方法m(),那么p.m()调用的是B中的m()。(2) 如果A中有而B中没有,那么p.m()调用的是B类对象从A继承而来的m()方法。这是动态绑定。(3)如果A中没有m()方法,则无论B中有没有,都会编译错。因为编译并非执行,编译器发现p是A类型的,而A类型以及A的父类都没有m()方法,也就是说,A类没有这个方法,也没有通过继承获得这个方法。另外,关于静态方法:(1)如果m()方法在A、B两个类中,一个静态一个非静态,则编译错。(无法覆盖)(2)如果m()方法在A中是静态的,在B中没有,或者也是静态的,那么p.m()调用的是A类的静态方法。编译的时候就把p.m()换成A.m()。读1.6隐藏与覆盖的综合性实例。(3)如果A中没有静态方法m(),那么编译器要看A的父类有没有。静态方法虽然无法覆盖,但也可继承。如果其父类也没有,则会编译错。下面的程序,Test类中函数showInformation的形参是Person类型的引用变量x。实参如果是其子类对象,那么就是让x指向子类对象,这和A p = new B()的原理是一样的。/代码Test.javaclass Personprotected String name; /姓名Person()Person(String name) = name;String information()return 类Person: +name;class Student extends Person /学生类protected int id; /学号Student()Student(String name, int id)super(name);this.id = id;/*String information()return 类Student: +name+id;*/class HiStudent extends Student /大学生类继承自学生类protected String school;/大学名称protected String department;/系的名称HiStudent()HiStudent(String name, int id, String school, String department)super(name, id);this.school = school;this.department = department;String information()return 类HiStudent: +name+id+school+department; public class Testpublic static void main(String as)showInformation(new Person(张三);showInformation(new Student(张三, 201122);/Student类没有information方法,因此showInformation将调用Student对象继承来的information方法。这是动态绑定。showInformation(new HiStudent(张三, 201122, 西南大学, 计科系);static void showInformation(Person x)System.out.println(rmation();问题:1、如果在Student类中,将对information()方法的屏蔽取消,结果有何变化?2、Test类showInformation方法的形参类型是Person。将其改为Object,编译能通过吗?3. 抽象类将父类设计得非常抽象,让它包含所有子类的共同属性、方法,以至于它没有具体的实例。如果子类不是抽象类,就必须实现(覆盖)抽象父类中的所有抽象方法。这其实也就规定了子类必须实现的的共同行为。abstract class GeometricShape/几何形状类public abstract double getArea();/不知道具体形状,无法计算,只能定义为抽象方法public abstract double getPerimeter();class Circle extends GeometricShapeprivate double radius;public Circle(double radius)this.radius = radius;public double getArea()return Math.PI*radius*radius;public double getPerimeter()return 2*Math.PI*radius;class Rect extends GeometricShapeprivate double width, height;public Rect(double w, double h)width = h;height = h;public double getArea()return width*height;public double getPerimeter()return 2*(width+height);public class Testpublic static void main(String s)GeometricShape g1 = new Circle(5);GeometricShape g2 = new Rect(5, 3);System.out.println(面积相同吗? + equalArea(g1,g2);printGeometricShape(g1);printGeometricShape(g2);public static boolean equalArea(GeometricShape g1, GeometricShape g2)return g1.getArea()=g2.getArea();public static void printGeometricShape(GeometricShape x)System.out.println();if(x instanceof Circle)System.out.println(这是一个圆);else if(x instanceof Rect)System.out.println(这是一个矩形);elsereturn;System.out.println(面积是 + x.getArea();System.out.println(周长是 + x.getPerimeter();问:如果将抽象类GeometricShape中的抽象方法删除,编译能通过吗?下面是关于抽象类的说明:l 注意: 1 抽象类前需加修饰符abstr

温馨提示

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

最新文档

评论

0/150

提交评论