第七章 继承与多态
了解继承
在设计继承的时候,你会把共同的程序代码放在某个类中,然后告诉其他类说此类是它们的父类。当某个类继承另一个类的时候,也就是子类继承自父类。
以java的方式说,这是“子类继承父类”。继承的关系意味着子类继承了父类的方法。当我们提及“类的成员”时,成员的意思就是实例变量和方法。
举例来说Cat类是Feline类的子类,则Cat类
会自动继承Feline的实例变量和方法。但Cat也可以加入自己的方法和实例变量,也可以覆盖掉继承自Feline的方法。
使用extends来表示继承:
class Feline{ //猫科动物类
String bark = "miaomiao";
}
class Cat extends Feline{ //猫是猫科动物的一员
//这里即使不写也会继承父类的 String bark = "miaomiao"; 当然这样写是不严谨的,老虎并不会喵喵叫。
}
继承就是类和类的共性提取出来,单独进行描述,只要让有相同共性描述的类和这个类有关系(比如老虎类也可以继承猫科动物类),就可以了。
继承的优点:1. 提高了代码的复用性。
2. 让类与类之间产生了关系,有了这个关系,才有了多态的特性。
注意:千万不要为了获取其他类的功能,只是为了简化代码而继承,必须是类与类之间有所属关系才可以继承。
java语言只支持单继承,不支持多继承,因为多继承容易带来安全隐患。所以每个类都只能继承一个类;不过每个类可以被多个类所继承。
多态
若要观察多态是如何运行的,我们就要先退回去看一般声明的引用和创建对象的方法。
//对象声明、创建与赋值的三个步骤:
Dog myDog = new Dog();
//1. Dog myDog 是要求java虚拟机分配空间给引用变量,并将此变量命名为myDog。此引用变量将永远被固定为Dog类型。
//2. new Dog() 要求java虚拟机分配堆空间给新建立的Dog对象
//3. 将新的Dog赋值给myDog这个引用变量
重点在于引用类型与对象的类型必须相符(前面是Dog,后面new的也是Dog)。但在多态下引用与对象可以是不同的类型,以上面猫科动物的例子来说就可以这样:
Feline fc = new Cat();
多态的扩展性
父类引用指向了自己的子类对象,或者说,父类的引用也可以接受自己的子类对象。
语法:父类名 对象名 = new 子类名(); //父类名换成接口名也可以
多态的前提: 必须是类与类之间有关系,要么继承过其他类,要么实现过接口。
多态的利弊: 多态提高了扩展性,但只能使用父类的引用,访问父类中的成员,因为使用的是父类的引用。
但是如果想调用子类特有的方法时,要如何操作?可以强制将父类的引用转成子类类型,向下转型。
//语法:子类名 对象名 = (子类名) 父类名
//还是以上面的Feline类为例:
Feline fc = new Cat();
Cat c = (Cat) Feline;
千万不要有将父类对象转成子类类型的情况。
在多态中,成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有,编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边
在多态中,成员变量的特点:
无论是编译还是运行,都参考引用型变量所属的类(左边的)。
在多态中,静态成员函数的特点: //静态后面会讲到
无论是编译还是运行,都参考引用型变量所属的类(左边的)。
方法的覆盖
覆盖的规则:当你要覆盖父类的方法时,你就得同意要履行合约。比如这个合约表示“我没有参数且返回布尔值”。因此,你所覆盖的方法就必须没有参数且返回布尔值。方法就是合约的标志。
当覆盖方法时,参数类型,个数,顺序要与父类保持一致,返回值类型必须要兼容。而且不可以降低方法的存取权限(比如public不可以变成private)。
方法的重载
重载的意义是两个方法的名称相同,但参数不同。所以,重载与多态毫无关系。
重载版的方法只是刚好有相同名字的不同方法,它与继承或多态无关。重载的方法与覆盖方法不一样。
重载可以有同一种方法的多个不同参数版本以方便调用。比如某个方法需要int,调用方就得将double转换成int然后才能调用。但若你有个重载版本取用double参数,则这样对调用方来说就简单多了。
因为重载方法不是用来满足定义在父类的多态合约,所以重载的方法比较有扩展性。
方法重载的规则:1. 返回值类型可以不同: 你可以任意的改变重载方法的返回类型,只要所有的覆盖使用不同的参数即可。
2. 不能只改变返回类型: 如果只有返回类型不同,但参数一样,这是不允许的。编译器不会让这样的事情过关。就算是重载,也要让返回类型是父类版返回类型的子类(多态)。重载的条件是要使用不同的参数,此时返回类型可以自由的定义。
3. 可以更改存取权限
重载是在同一个类中发生的事情。
重载的合法范例:
class Overloads{
public int addNums(int a,int b){
}
public double addNums(double a,double b){ //返回值类型不同也可以
}
}