继承与多态
一、什么是类的继承
1.继承的概念
Java的继承是指在一个现有类的基础上去构建一个新类,现有类叫父类,而基于现有类构建出的新类叫子类,子类可以拥有父类中的成员。 2.子类的设计 创建类的语法格式如下:[修饰符] class <类名> { 各种成员变量的定义; 各种成员方法的定义; }
在Java 中,往往在声明一个类的同时需要继承另一个类,这时就需要使用extends关键字来指明其父类。创建类的完整的语法格式如下:
[修饰符] class <类名> [extends 父类名][implement 接口列表]{ 各种成员变量的定义; 各种成员方法的定义; }
3.继承中的protectd
在上一个模块的学习中,我们知道, 一个类中的成员变量和成员方法的修饰符可以是public、protected、private。 其中,被public修饰的属性可以被子类继承,而被private修饰的则不能被子类继承。那被protected修饰的成员方法和成员变量呢?如果父类和子类在同一个包中,那么protected 等价于public,,如父类和子类不在同一个包中, 那么 protected 等价于private。 4.继承的使用原则 子类可以继承父类中所有可被子类访问的成员变量和成员方法, 但必须遵循以下原则。 (1)子类可以继承父类中被声明为public、protected(父类和子类在同一个包中)的成员变量和成员方法,但是不能继承被private修饰过的成员变量和成员方法。 (2)如果子类声明了一个与父类同名的成员变量, 则子类不能继承父类的成员变量,因为此时,子类中的成员变量隐藏了父类的同名成员变量。 (3)同理,如果子类声明了一个与父类同名的成员方法,则子类不能继承父类的成员方法, 因为此时,子类中的成 员方法隐藏了父类的同名成员方法。 5.super关键字的使用 使用super关键字用来在子类中访问父类中被子类隐藏的成员方法和成员变量。super关键字的用法主要有以下两种: (1)使用super关键字访问父类的构造方法 子类调用父类的构造方法,其具体语法格式如下:super [参数列表];
(2)使用super关键字访问父类中与子类同名的成员方法和成员变量
其具体语法格式如下:super. 成员变量; super. 成员方法[参数列表];
二、final关键字
1.final修饰变量
final修饰的变量(包括成员变量和局部变量)会变成常量,只能赋值一次。 2.final修饰类 被 final修饰的类,不能被继承, 即该类不能有子类。 3.final修饰方法 被final修饰的方法,不能被重写,即该类的子类不能重写该方法。 三、什么是多态 1.多态的概念 所谓多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使同一个属性或方法在父类及其各个子类中具有不同的含义, 面向对象的多态性提高了程序可复用性、 可扩充性和可维护性。 对面向对象来说, 继承是多态得以实现的基础, 而多态的行为主要包括方法的重载和向上转型。 方法的重载: 指在同一个类中,根据参数列表的不同来区分同名的方法。 向上转型: 指在有继承关系的类中,将子类的引用赋给父类对象,即子类的对象是父类类型。 2.构造方法的重裁 在一个类中,可以定义多个构造方法,这些构造方法的方法名虽然相同,但是它们的参数类型或者参数个数是不同的, 在创建对象时,可以根据参数的类型或个数来选择调用相应的构造方法。 3.成员方法的重裁 在一个类中,可以定义多个同名的成员方法, 虽然方法名相同,但是它们的参数类型或者参数个数是不同的,Java 在执行具有重载关系的方法, 可以根据参数的类型或个数来选择调用相应的成员方法。 4.对象的类型转换 所谓对象的类型转换,就是指向上转型或者向下转型。即 将子类的对象当作父类类型使用, 或者将父类的对象当作子类类型使用,它是多态性的另外一种表现形式。 四、设计工资管理系统 1.任务描述 实现一个名为Person的类和它的子类Employee, 再设计Manager类, 它是Employee 的子类, 最后设计一个类Add()用于涨工资, 普通员工一次能涨 10%, 经理能涨20%. 2.任务目标 (1)学会分析“工资管理系统”子任务实现的逻辑思路。 (2)能够独立完成“工资管理系统”程序的源代码编写、 编译及运行。 (3)实理现解思继路承和多态的相关概念及使用。 3.实现思路 (1)首先设计 Person类, 该类中的属性有: 姓名name String(类型)、 地址address(String类型)、 定义该类的构造方法。 (2)然后设计Employee 类, 该类中的属性有: 工号 ID(String类型)、 工资wage(double类型)、 工龄(int 型)、 定义该类的构造方法。 (3)接着设计 Manger类, 该类中的属性有: 级别 level(String类型)、 定义该类的构造方法。 (4)最后代编码写一个测试类,产生一个员工和一个经理, 给该员工和经理涨工资。 4.实现代码 (1)定义Person类public class Person { private String name=""; private String address=""; //定义构造方法 public Person ( String name, String address) { this. name = name; this. address = address; } }
(2)定义Employee类并继承Person类。
//继承Person类 public class Employee extends Person{ private String ID = ""; private double wage = 0; private int age = 0; public Employee(String name, String address, String ID, double wage, int age){ super(name, address); //调用父类的构造方法 this. ID = ID; this. wage = wage; this. age = age; } public double add (String position){ //判断职位 if(position = = "0" ) wage = wage *1.2; } else{ wage = wage * 1.1; } return wage; } //设置 get/set方法 public double getWage(){ return wage; public void set Wage (double wage){ this. wage = wage; } }
(3)定义Manger并继承Employee 类。
public class Manager extends Employee{ private String level = ""; //1为普通员工,0为经理 public Manager( String name, String address, String ID, double wage, int age, String level) { super( name, address, ID, wage, age); this. level = level; //设置get/set方法 public String getLevel (){ return level; public void setLevel ( String level){ this. level = level; } }
(4)定义测试类Test, 完成相应的操作。
public class Test { public static void main( String[] args){ //新建对象 Manager normal = new Manager( "wsl", "jit" , " 12" , 1000, 2, "1"); Manager manager = new Manager(" ctl" , "jitt" , " 123" , 5000, 10, "0"); //传入职位,Manager类型的对象没有add()方法,所以自动搜寻其父类,调用add()方法 normal. add( normal. getLevel()) ; manager. add (manager. getLevel()); System. out. println ("TT资:" +normal. get Wage()); System. out. println ("经理的T资:" +manager. getWage()); } }
5.运行结果
抽象类与接口
一、什么是抽象类
1.抽象类的定义
在面向对象的概念中,所有的对象都是通过类来描绘的。但是反过来, 并不是所有的类都是用来描绘对象的, 如果一个类中没有包含足够的信息来描绘一个具体的对象, 这样的类就是抽象类。 简单来说,在Java 中, 如果一个类中包含了抽象方法(只包括方法声明, 而不包含方法体)。则该类就必须定义成抽象类,抽象方法的具体实现则由抽象类派生出的各子类来完成。这使程序的功能描述和功能实现得以分离,此外, 由于一个抽象类可派生多个子类。 因此, 抽象类中的一个抽象方法可以在多个子类中有多种实现方式,这也实现了程序的多态性。
(1)抽象类的定义的语法格式
public abstract class 类名 // 声明抽象类 } { // 声明抽象类成员 }
(2)抽象类成员组成
a. 成员变量。 b.成员常量。 c.构造方法,有构造方法,但是不能实例化,构造方法用于子类访问父类数据的初始化。 d.成员方法,可以包含限定子类必须完成某些动作的抽象方法(除非子类也是抽象类。否则抽象方法必须在子类中重写), 也可以包含提高代码复用性的非抽象方法。 (3)抽象类的特点 a.抽象类和抽象方法必须使用 abstract关键字修饰。 b.抽象类是不能实例化的,也就是说,不能基于抽象类来创建对象,抽象方法不能有方法体。 c.抽象类的子类要么重写抽象类中所有的抽象方法,要么是抽象类。 2.抽象类的使用 抽象类与抽象方法的使用方法,其中,分别定义抽象类 Animal及两个子类,子类分别覆盖抽象类中的Bark( ) 抽象方法,从而使程序能够用一种方法实现不同动物的叫声。 二、什么是接口 1.接口的定义 如果一个抽象类中的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。 和抽象类的作用类似, 接口也可以把“做什么”和“怎么做”, 即程序的功能和实现分离开来。Java 语言是单一继承语言,即一个类只能直接继承一个父类,这就使 Java的继承结构形成一个树状结构, 这种单一继承关系从某种程度上使Java的继承逻辑变得简单、 清晰。 降低了编程难度,但同时也有了一些局限,可以利用接口弥补这个不足, 即一个子类可以实现多个接口。 (1)抽象类定义的语法结构[public] interface 接口名 [extend 接口1,接口2......] //声明接口 { //声明接口成员 }由于接口中的方法都是抽象的,因此不能通过创建实例化对象的方式来调用接口中的方法, 此时, 还需要一个类通过implements关键字来实现接口中的所有方法,接口的实现类声明格式如下:
[修饰符] class<类名> [extends <父类名>] [implement接口名]
(2)接口成员组成
a.成员常量, 接口中只有常量,并且默认为静态。 b.构造方法,,接口中不能有构造方法. c.成员方法,只能包含限定子类必须完成某些动作的抽象方法。 (3)接口特点 a.接口中只能定义抽象方法,不能定义非抽象方法。 b.类和接口之间不能继承(extends),只能实现(implements)。 c.接口不能实例化,只能对实现接口的子类进行实例化。 d.类可以不重写接口的所有抽象方法,则该类必须定义为抽象类。 2.接口的一对多实现 由于 Java支持接口的多继承, 因此可以在implements后面列出要实现的多个接口, 这些接口名称之间应以逗号分隔, 例如:[修饰符] class <类名> [extends <父类名>] [implements <接口1>,<接口2>......]
3.接口的使用
接口的定义和使用很容易, 但要注意一点,由于系统要求继承接口的类中必须实现接口的全部方法, 因此, 一旦修改了接口内容,很可能会导致相关类变成抽象类,而抽象类是不能实例化的。
三、设计学生管理系统
1.任务描述
学生管理系统主要用于学生信息的处理和存储,实现学生信息管理的系统化、 科学化、规范化和自动化,其主要功能是对学生各种信息进行日常管理。 如查询、 修改、 增加、 删除等,本案例较为简单地实现了三个类及一个接口,分别是: 学生类、 教师接口、 教师接口实现类、 运行类。训练学生对继承和多态的理解运用,为以后开发功能更加完善的学生管理系统打下良好的基础。2.任务目标
进一步掌握继承和多态的实现方式。3.实现思路
本程序设计一个学生类,包括学生姓名、 电话、 年龄等信息。再设计一个教师接口, 规范教师所能做的操作, 最后设计一个子类来实现教师接口, 完成教师对学生信息的录入和查看。4.实现代码
(1)定义一个学生类
package studentsystem; public class Stu{ //基本属性 public String name, tel, age; public boolean sex; public static int i=0; //人数总和 private Stu[] s=new Stu[5]; //创建学生表, //返回表 public Stu[] TheStuArrar() { return s;} public Stu(){ } //有参构造方法用来向表添加学生 public Stu( String a, String b, String c, boolean d){ name=a; age=b; tel=c; sex=d; } //相关属性的get/set方法 public String getName(){ return name; } public void setName(String name) { this. name = name; } public String getTel(){ return tel; } public void setTel(String tel){ this, tel = tel; } public String getAge() { return age; } public void setAge (String age){ this. age = age; } public boolean getSex(){ return sex; } public void setSex( boolean sex){ this. sex = sex; } }
(2)定义一个教师接口
package studentsystem; public interface Teacher1{ //教师拥有对表的操作权限 abstract public void jiemian (Stu [] st) ; //初始界面,选择操作 abstract public void set ( Stu [] st); //存储 abstract public void ShowStu(Stu [] st) ; //查看 }
(3)定义一个具体教师类来实现教师接口
package studentsystem; import java. util. Scanner; public class TeacherCan implements Teacher1{ //界面 public void jiemian(Stu[] st) //参数是执行的对象 } System. out. println(" --------学生管理系统-------"); int a; Scanner sc = new Scanner( System. in); //一直执行操作,直到某些情况满足就break退出循环 for(;;){ System. out. println (" 1. 查看生信息"); System. out. println("2. 存储生信息"); System. out. println("按数字0退出系统"); a = sc. nextlnt(); if(a= =0) break; //用switch判断用户的选择,非法输入无效 switch (a){ case 1:ShowStu(st); break; case 2:set(st); break; default: System. out. println("输入无效! In"); } } } //查看 public void ShowStu(Stu[] st){ System. out. println("序号"+" \t 姓名:"+" \t年龄:"+ "\t性别:"+" \t电话:"); //过滤掉空的元素,这里不用成员变量i,所以不担心变量名重复 //doo用来展示序号,i遍历st数组 for( int i=0, doo = 0; i<st. length; i++, doo++){ if(st[i] = =null) | doo--; continue; } System. out. println( (doo+1)+" \t "+st[i]. getName() +" \t "+st[i]. getAge() +" \t" +st[i]. getSex()+" \t "+st[i]. getTel() +" \t "); } } //存储 public void set(Stu[] st) { Scanner s= new Scanner( System. in); String a,b,c,f; boolean d; int e; //往数组的空元素插入数据 //条件设置成<=,是为了在内存用完后继续增加时提示空间不足 for( int it=0; it<= st. length; it++) { //控制语句,当内存10个用完了时还调用该方法增加人员,提示并退出 if(Stu. i>=st. length){ System. out. println("e不足,对象内存(" +st. length+" )已用完! \n"); break; } if(st[it] = = null) | System. out. println("第"+(Stu. i+1) +"个学生的信息:"); System. out. print("名:"); a=s. nextLine(); System. out. println (":"); b=s. nextLine(); System. out. println("电话:"); c=s. nextLine(); System. out. println(": (true, false女生)"); d=s. nextBoolean(); //往空元素插入新学生 st[ it] = new Stu(a,b,c,d); //人数标记+1 Stu. i++; System. out. println("写入成功!按数字0退出,按1继续"); e=s. nextInt(); if(e==0) break; else s. nextLine(); //这里会产生回车残留,需要用nextLine()吸收 } } } }
(4)定义类Run,完成相应的操作
public class Run{ public static void main ( String [] args){ teacherCan t1 = new teacherCan() ; //new老师 stu st= new stu() ; //new学生表 t1. jiemian(st. TheStuArrar()) ; //老师进行操作 } }
5.运行结果