Java程序设计 第9章 继承和多态
学习目标 理解类继承的概念以及父类和子类的关系 理解super关键字 掌握方法覆盖 理解多态性、动态绑定和对象的强制类型转换 理解数据字段和静态方法的隐藏 掌握修饰符:protected、final 了解ArrayList类
Employee和Manager public class Employee { public String name; public double salary; public Date birthDate; public String getDetails() {...} } public class Manager { public String name; public double salary; public Date birthDate; public String department; public String getDetails() {...} }
继承 public class Employee { public String name; public double salary; public Date birthDate; public String getDetails() {...} } Employee + name salary birthDate : String : double : Date getDetails () Manager department public class Manager extends Employee { public String department; }
父类和子类 语法 如果class C1 extends C2,则称C1为子类(subclass),C2为父类(superclass)。 class ClassName extends Superclass { class body } 如果class C1 extends C2,则称C1为子类(subclass),C2为父类(superclass)。 子类继承了父类中可访问的数据和方法,子类也可添加新的数据和方法, 子类不继承父类的构造函数。 一个类只能有一个直接父类。 继承 Manager Employee Employee的数据 Employee的方法 Manager的数据 Manager的方法
例 几何对象类 编写程序,父类GeometricObject,两个子类Circle和Rectangle。 Example:v1/Circle.java, v1/Rectangle.java, v1/TestCircleRectangle.java
super关键字 调用父类的构造函数 调用父类的成员 super(parametersopt)调用父类的的构造函数。 必须是子类构造函数的第一条语句。 如果子类中没有显式地调用父类的构造函数,那么将自动调用父类不带参数的构造函数。 父类的构造函数在子类构造函数之前执行。 调用父类的成员 super.data super.method(parameters) Example: ConstructorDemo.java
方法覆盖 如果子类重新定义了从父类中继承的实例方法,称为方法覆盖(method override)。 仅当方法是可访问的实例方法时,才能被覆盖,即私有方法不能被覆盖。 静态方法不能被覆盖,如果静态方法在子类中重新定义,那么父类方法将被隐藏。 一旦父类中的方法被覆盖,则不能从子类外部访问被覆盖的方法。在子类中可以使用super引用被覆盖的方法。 Example:v2/Circle.java, v2/Rectangle.java, v2/TestCircleRectangle.java OverrideTest.java
覆盖与重载 public class Test { public static void main(String[] args) { A a = new A(); a.p(10); } class B { public void p(int i) { class A extends B { System.out.println(i); public class Test { public static void main(String[] args) { A a = new A(); a.p(10); } class B { public void p(int i) { class A extends B { public void p(double i) { System.out.println(i);
Object类 java.lang.Object类是所有类的父类。如果一个类在声明时没有指定父类,那么这个类的父类是Object类。 equals方法:用于测试两个对象是否相等。Object类的默认实现是比较两个对象是否引用同一个对象。 toString方法:返回代表这个对象的字符串。Object类的默认实现是返回由类名、@和hashCode组成。
多态性、动态绑定 当调用实例方法时,由Java虚拟机动态地决定所调用的方法,称为动态绑定(dynamic binding) 或为多态(polymorphism)。 假定对象o是类C1的实例,C1是C2的子类,C2是C3的子类,…,Cn-1是Cn的子类。也就是说,Cn是最一般的类,C1是最特殊的类。在Java中,Cn是Object类。如果调用o的方法p,Java虚拟机按照C1、C2、…、Cn的顺序依次查找方法p的实现。一旦找到一个实现,将停止查找,并执行找到的第一个实现。 Cn Cn-1 … C2 C1 Object 查找方法p的顺序 对象o
通用编程 父类变量可以引用子类对象,针对父类对象设计的任何代码都可以应用于子类对象。 多态性允许方法使用更通用的类作为参数类型。 如果方法参数是父类,那么这个参数可以接受任何子类对象作为实参。当调用这对象的方法时,将动态绑定方法的实现。 Example:poly/PolymorphismDemo.java
类型转换 类型转换(type casting)可以将一个对象的类型转换成继承结构中的另一种类型。 从子类到父类的转换是合法的,称为隐式转换。 m(new Student()); Object o = new Student(); m(o); 从父类到子类必须显式转换,被转换的变量所指向的对象的类型必须是转换类或它的子类。 Student s = (Student)o; o所指向的对象必须是Student或Student子类的对象
instanceof操作符 可以用instanceof操作符判断一个对象是否是一个类的实例。表达式返回boolean值。 语法 referenceVariable instanceof TypeName
例 强制类型转换 编写程序,创建两个几何对象:圆和矩形。调用displayObject来显示结果。 如果对象是圆,显示半径和面积 如果对象是矩形,显示面积 Example:v2/TestPolymorphismCasting.java
隐藏数据字段和静态方法 如果子类中声明的数据字段和静态方法与父类中的名称相同,那么父类中的将被隐藏(hide)。 成员访问 通过super关键字访问被隐藏的数据字段和静态方法。 通过父类型的变量访问被隐藏的数据字段和静态方法。 成员访问 实例方法根据变量所引用的对象的实际类型进行访问。 数据字段和静态方法根据变量的声明类型进行访问。 A x = new B(); Example:HideDemo.java
protected修饰符 protected修饰符用于修饰数据和方法,可以被同一个包中的任何类或不同包中的子类访问。 P1 P2 C1 C4 public int x protected int y int z private int u C5 C1 c1 = new C1() C2 C2中的代码可以访问x,y,z C3中的代码可以访问c1对象中的x,y,z C4中的代码可以访问x,y C5中的代码可以访问c1对象中的x C3 C1 c1 = new C1()
访问控制符 类成员的访问控制符 类的访问控制符 public:类可以被任何包中的类访问 无(package):只有同一个包中的类可以访问 √ 成员修饰符 同一个类 相同包中的类 子类 不同包中的类 public √ protected 无(package) private
final修饰符 final数据:常量,数据初始化后不能再修改。 final方法:最终方法,子类不能覆盖。 String, StringBuffer final局部变量:数据初始化后不能再修改。
ArrayList java.util.ArrayList类表示一个内部以数组存储的线性表。 Example:TestArrayList.java, TestArrayListGeneric.java