第9讲 Java的继承与多态(一) 类的继承 子类的创建 方法覆盖
目标 理解继承的概念 掌握通过父类创建子类的方法 理解子类和父类构造方法的执行顺序 掌握实现方法覆盖的方法
面向对象特性概述 继承、封装、多态是面向对象程序设计的3个重要特性。 通过继承,以既有类为基础,派生出新类,达到代码重用的目的; 通过封装,对类对象的数据成员进行访问控制,起到数据保护的作用; 通过多态,程序能够动态的匹配同名方法,使程序更加灵活。
继承的基本概念 继承是一种由已有的类创建新类的机制。利用继承,可以先创建一个公有属性的一般类,根据一般类再创建一个具有特殊属性的新类。 新类继承一般类的状态和行为,并根据需要增加它为自己的新的状态和行为。 由此继承而得到的类为子类,被继承的类为父类(超类)。JAVA不支持多继承(子类只能有一个父类)。
人 学生 教师 教辅人员 外语系学生 计算机系学生 旅游系学生 计算机网络专业学生 软件技术专业学生 计算机多媒体专业学生 计算机教育专业学生
class Person // 定义Person类 { protected String name; protected String sex; protected int age; ……Person类的方法 } 通过Person类派生出Student类。Student类继承自Person类,拥有Person类的所有方法和属性。 class Student extends Person { private String department;//系别 private String specialty;//专业 ……Student类的方法 } 通过关键字extends实现继承
Person类的定义 // Ex6_1.java class Person // 定义Person类 { protected String name; //姓名 protected String sex; //性别 protected int age; //年龄 public void register(String n,String s,int a) //设置数据成员 { name=n; sex=s; age=a; } String getName()//获取姓名 { return name; } String getSex()//获取性别 { return sex; } int getAge()//获取年龄 { return age; } public void showMe()//显示人员信息 { System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age); } }
通过extends关键字,由Person类派生出Student类 class Student extends Person { //定义Student类,是Person类的子类。 private String department;//系别 private String specialty;//专业 public void studentRegister(String n,String s,int a,String dep,String spe) { //设置数据成员 register(n,s,a); department=dep; specialty=spe; } String getDepartment()//获取学生所在系 { return department; } String getSpecialty()//获取学生所学专业 { return specialty; } public void showStudent()//显示学生类数据成员 { System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age+",系别:"+department+",专业:"+specialty); 通过extends关键字,由Person类派生出Student类
姓名:张三,性别:男,年龄:18,系别:计算机,专业:软件开发 public class Ex6_1 { public static void main(String args[]) Student student1=new Student(); student1.studentRegister("张三","男",18,"计算机","软件开发"); student1.showStudent(); } 运行结果: 姓名:张三,性别:男,年龄:18,系别:计算机,专业:软件开发 程序分析: 本例中的Person类是父类,它派生出子类Student类。Student类继承了Person类的name属性,sex属性,age属性,GetName()方法,GetSex(),ShowMe()方法等。同时,Student类对Person类进行了功能扩展,又增加了department,specialty属性和GetDepartment()、GetSpecialty()、ShowStudent()等方法。
说明 继承能够使子类拥有(继承)父类的非私有属性和方法(即可以继承public、protected和默认访问属性的成员),而不需要在子类定义时重新定义父类中的这些同名属性和方法。当修改父类中的某个属性和方法时,子类中也会同样得到修改。这样,就可以省去重复定义成员的烦琐,实现代码重用,同时提高了代码的可维护性。 一个父类可以有多个子类,这些子类都是父类的特例,父类描述了这些子类的公共属性和方法。一个子类可以继承它的父类(或祖先类)中的属性和方法,这些属性和方法在子类中不必定义,子类中还可以定义自己的属性和方法。
创建子类的语法格式 [访问权限] class 子类名 extends 父类名 { 类体定义; } “访问权限”是指public,private,protected等;子类名和父类名通过关键字extends联系在一起,形成继承关系
构造方法的继承 通常在定义一个新类的时候,会定义一个相应的构造方法,用来对数据成员进行一些初始化。 构造方法是在创建对象时自动调用,并执行构造方法的内容,构造方法不需从程序直接调用,而是在对象产生时自动执行。 构造方法没有返回值,名称必须与类的名称相同之外。 假如在一个类中定义了构造方法,而由这个类派生出来的子类也定义了构造方法,那生成新的子类对象的时候,构造方法是怎样执行的呢?
Person类的构造方法,输出了字符串“Person() constructor is called!” // Ex6_2.java class Person // 定义Person类 { protected String name; //姓名 protected String sex; //性别 protected int age; //年龄 public Person() System.out.println("Person() constructor is called!"); } public void register(String n,String s,int a)//设置数据成员 name=n; sex=s; age=a; public void showMe()//显示人员信息 System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age); Person类的构造方法,输出了字符串“Person() constructor is called!”
子类Student类的构造方法,用于输出“Student() constructor is called!” class Student extends Person //定义Student类,是Person类的子类 { private String department;//系别 private String specialty;//专业 public Student()//定义学生类的构造方法 System.out.println("Student() constructor is called!"); } public void studentRegister(String n,String s,int a,String dep,String spe) register(n,s,a); department=dep; specialty=spe; public void showStudent()//显示学生类数据成员 System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age+",系别:"+department+",专业:"+specialty); 子类Student类的构造方法,用于输出“Student() constructor is called!”
public class Ex6_2{ public static void main(String args[]){ Student student1=new Student(); student1.studentRegister("张三","男",18,"计算机","软件开发"); student1.showStudent(); } 运行结果: Person() constructor is called! Student() constructor is called! 姓名:张三,性别:男,年龄:18,系别:计算机,专业:软件开发 Person类定义了一个无参构造方法,输出“Person() constructor is called!”。通过Person类派生出了Student类,Student类中也定义了一个无参构造方法,将输出“Student() constructor is called! ”。通过输出结果,明显看出,创建Student对象时,在执行Student类的构造方法之前,调用了Person类的构造方法。这样的执行顺序可以保证子类对象从父类对象继承得到的成员能够进行正确的初始化。
覆盖 覆盖是指在子类中,利用完全相同的方法名,返回类型和参数,重新实现父类的某一成员方法。 当需要对象响应同样的方法,但与超类中原来的方法有不同行为时,需要超越(抑制)该方法。用新的方法体取代原来的方法,但使用相同的方法名 在Ex6_1.java中,Person类通过showMe()方法显示人员信息,而子类Student类通过showStudent()方法显示人员信息。 这两个方法都是用来显示人员信息,只是显示的项目不同而已。实际上,在定义Student类方法的时候,可以定义showMe()方法将父类的showMe()方法覆盖。
覆盖示例 class Person { // 定义Person类 protected String name; //姓名 protected String sex; //性别 protected int age; //年龄 public Person() { } //构造方法 public Person(String n,String s,int a) { name=n; sex=s; age=a; } public void showMe() { //显示人员信息 System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age); 覆盖示例 父类Person中定义了showMe()方法,用来输入类对象基本信息
覆盖示例(续) 由Person类派生出的Student类中重新定义了showMe()方法,覆盖了父类Person类的showMe()方法。 class Student extends Person { //定义Person的子类:Student private String department;//系别 private String specialty;//专业 public Student(String n,String s,int a,String dep,String spe) { name=n; sex=s; age=a; department=dep; specialty=spe; } public void showMe() {//显示学生类数据成员 System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age+",系别:"+department+",专业:"+specialty); 由Person类派生出的Student类中重新定义了showMe()方法,覆盖了父类Person类的showMe()方法。
覆盖示例(续) public class Ex6_3 { public static void main(String args[]) { Person person1=new Person("王兰","女",16); person1.showMe(); Student student1=new Student(“张三”,“男”,18,“计算机”,“网络"); student1.showMe(); } 运行结果: 姓名:王兰,性别:女,年龄:16 姓名:张三,性别:男,年龄:18,系别:计算机,专业:网络 子类中所定义的showMe()方法覆盖了父类的showMe()方法。例6.1中,Person类对象和Student类对象分别调用showMe()和showStudent()方法才能显示各自信息。本例中,两者都可使用showMe()方法显示信息。 利用“覆盖”技术,在子类中可定义和父类中的名称、参数个数与数据类型均完全相同的方法,用以取代父类中原有的方法。
作业 习题6 ——7题、8题、 实验 实验三 类的简单应用