java语言程序设计 李元朝 第7章 类的继承和多态机制
7.1 类的继承
7.1.1 继承的基本概念
由一个已有类定义一个新类,称为新类继承了已有类。被继承 的已有类称为父类或超类,所定义的新类称为子类或派生类。
在 Java 中,类是一个层次结构,其中Object为超类或基类,所有类都直接或间接地继承自Object类;
子类继承父类的属性和方法,同时也可以修改父类的属性或重载父类的方法,以及在父类的基础上添加新的属性和方法。因此,
父类和子类之间反映的是“一般与特殊”的关系。
在类的继承中,被继承的类称为父类,继承而来的类则称为子类。有多个子类共同继承一个父类,那么这个父类就是多个类的基类。
Java语言只支持单继承,如果要定义多继承,可以使用将要讲解的接口
7.1.2 继承的实现
1.定义子类
定义子类的形式为:
[访问权限:public abstract final] class 类名 extends 父类名
{
类体
}
新定义的类称为子类,它可以从父类那里继承属性和方法。
一个类只能继承一个父类,称为单重继承。
2.继承原则:
1.子类继承父类的成员变量和方法
2.子类不能继承父类的构造函数
3.子类可以重新定义父类成员
3.访问权限:
子类对父类的private成员没有访问权限。
子类对父类的public和protected成员具有访问权限。
子类对父类的缺省权限成员访问权限分2种情况:对于同一包中父类的缺省权限成员具有访问权限,对其它包中父类的缺省权限成员没有访问权限
例7-1 在子类访问父类成员package example7_1; public class Person1 { private String name; protected int age; public void setName(String na) { name=na; } public void setAge(int ag) { age=ag; } public String getName() { return name; } public int getAge() { return age; } public void print_p() { System.out.println("Name:"+name+" Age:"+age); } }package example7_1; public class Teacher1 extends Person1{ protected String department; public Teacher1(String na, int ag, String de) { setName(na); setAge(ag); department=de; } public void print_s() { print_p(); System.out.println("Department:"+department); } public static void main(String arg[]) { Teacher1 t; t=new Teacher1("Wang",40,"Computer Science"); t.print_s(); t.setName("Wang Gang"); t.age=50; //直接访问父类中protected成员变量age,但不能访问其 //private成员变量name t.print_s(); } }程序运行结果如下:
Name:Wang Age:40
Department:Computer Science
Name:Wang Gang Age:50
Department:Computer Science
7.1.3 super和htis 引用
在子类中可以声明与父类同名的成员变量及成员方法,为了指胆是引用父类中的成员可以使用super关键字,为了指明是引用子类成员可以使用this关键字
可以使用super引用父类成员变量
super.成员变量名
调用父类成员方法
super.成员方法名(参数表)
调用父类构造方法
super(参数表)
例7-2 利用super访问父类成员public class Person2 {
protected String name;
protected int age;
public Person2(String na, int ag)
{
name=na;
age=ag;
}
public void print()
{
System.out.println("Parent:Name="+name+" Age="+age);
}
}public class Teacher2 extends Person2{
String department, name;
public Teacher2(String na, int ag, String de, String na1)
{
super(na,ag);
department=de;
name=na1;
}
public void setName_p(String na)
{
super.name=na;
}
public void setName_s(String na1)
{
name=na1;
}
public void print()
{
super.print();
System.out.println("Son:Name="+name+" Department="+department);
}
public static void main(String arg[])
{
Teacher2 t;
t=new Teacher2("Wang",40,"Computer Science","Gu");
t.print();
t.setName_p("Wang Qiang");
t.setName_s("Gu Li");
t.print();
}
}程序运行结果如下:Parent:Name=Wang Age=40
Son:Name=Gu Department=Computer Science
Parent:Name=Wang Qiang Age=40
Son:Name=Gu Li Department=Computer Science
7.2 类的多态性
指同一名字的方法可以有多种实现,即不同的方法体。
多态是通过方法的重载和覆盖来实现
7.2.1 方法重载
在同一类中,多个方法具有相同的方法名,但采用不同的形式参数列表,包括形参的个数、类型或顺序不同
以下是正确的重载方法头:
public double area(double r)
public double area(int a, double b)
public double area(double a, int b)
以下的方法头则不是正确的重载方法:
public int volume(int a, int b)
public void volume(int x, int y)
例7-4 方法重载举
public class Distance_P {
public double distance(double x, double y)
{
return Math.sqrt(x*x+y*y);
}
public double distance(double x, double y, double z)
{
return Math.sqrt(x*x+y*y+z*z);
}
}public class Measure {
public static void main(String[] args)
{
Distance_P d2, d3;
d2=new Distance_P();
d3=new Distance_P();
System.out.println("Two dimensional distance="+d2.distance(2,2));
System.out.println("Three dimensional distance="+d3.distance(2,2,2));
}
}程序运行结果如下:
Two dimensional distance=2.8284271247461903
Three dimensional distance=3.4641016151377544
方法重载也可以出现在父类与之类之间,即子类中可以声明与父类中具有相同方法名,但具有不同参数表的成员方法。
7.2.2 方法覆盖
覆盖是指子类重定义了父类中的同名方法。覆盖表现为父类与子类之间方法的多态性
程序运行时,根据调用方法的对象所属的类决定执行父类中的方法还是子类中的同名方法。寻找执行方法的原则是:首先从对象所属类开始,寻找匹配的方法;
如果当前类中没有匹配的方法,则依此在父类、祖先类寻找匹配方法
7-5 方法覆盖举例
public class CCircle {
protected double radius;
public CCircle(double r)
{
radius=r;
}
public void show()
{
System.out.println("Radius="+radius);
}
}public class CCoin extends CCircle{
private int value;
public CCoin(double r, int v)
{
super(r);
value=v;
}
public void show()
{
System.out.println("Radius="+radius+" Value="+value);
}
public static void main(String[] args)
{
CCircle circle=new CCircle(2.0);
CCoin coin=new CCoin(3.0,5);
circle.show();
coin.show();
}
}程序运行结果如下:
Radius=2.0
Radius=3.0 Value=5
7.3 final类和final成员
Java中,有一个非常重要的关键字final,用它可以修饰类及类中的成员变量和成员方法。用final修饰的类不能被继承,用final修饰的成员方法不能被覆盖,
用final修饰的成员变量不能被修改。
什么时候用final类呢?
出于安全性考虑,有些类不允许被继承,称为final类。在下列情况下,通常将类定义为final类:
具有固定作用,用来完成某种标准功能的类。(系统类string 、Byte和Double)
类的定义已经很完美,不需要再生成其子类
例7-6 继承final类
final class C1 {
int i;
public void print()
{
System.out.println("i="+i);
}
}
public class C2 extends C1{
double x;
public double getX()
{
return x;
}
}程序编译时的错误信息如下:
无法从最终 C1 进行继承
public class C2 extends C1
1 错误