封装、继承和多态性是面对对象程序设计语言的重要特性,想要理解面对对象程序设计思想避不开这三种特性的学习,这里来讨论一下继承和多态
继承
继承的解释
extend 继承 扩展
类是规则,用来制造对象的规则。我们不断地定义类,用定义的类制造一些对象。类定义了对象的属性和行为,就像图纸决定了房子要盖成什么样子。
一张图纸可以盖很多相同的房子,假如现在我们想盖一座新房子,和以前盖的房子很相似,但是稍微有点不同。任何一个建筑师都会拿以前盖的房子的图纸来,稍加修改,成为一张新图纸,然后盖这座新房子。所以一旦我们有了一张设计良好的图纸,我们就可以基于这张图纸设计出很多相似但不完全相同的房子的图纸来。
基于已有的设计创造新的设计,就是面向对象程序设计中的继承。在继承中,新的类不是凭空产生的,而是基于一个已经存在的类而定义出来的。通过继承,新的类自动获得了基础类中所有的成员,包括成员变量和方法,包括各种访问属性的成员,无论是public还是private。当然,在这之后,程序员还可以加入自己的新的成员,包括变量和方法。显然,通过继承来定义新的类,远比从头开始写一个新的类要简单快捷和方便。继承是支持代码重用的重要手段之一。
子类与父类的关系
- 除了构造方法。父类中仅有构造方法在子类中不存在。除此之外,子类继承得到了父类所有的成员。包括private的成员及方法
- 在继承中,public的成员直接成为子类的public的成员,protected的成员也直接成为子类的protected的成员。父类的private的成员在子类里仍然是存在的,只是子类中不能直接访问。访问修饰符
- 如果我们定义一个在父类中已经存在的成员变量,(注意不是类变量)那么子类中的这个变量与父类中的变量除了名字相同外完全无关,我们在子类中只能访问子类的这个变量,在父类的方法中访问父类的那个。尽管它们同名但是互不影响。(子类中的同名变量覆盖父类的变量)
- 如果我们定义一个在父类中已经存在的类变量,子类中的”新的”同名类变量无效。
继承的使用
- Java中只允许单继承和多层继承,使用接口间接实现多继承
- 在制造子类的对象时,会先自动调用父类的构造方法,然后调用子类的构造方法
- super的使用
1.使用super([参数])调用父类的构造方法
2.使用super方法名(),调用父类的普通方法
3.使用super.成员变量名,来调用父类中的成员变量
super与this使用方法类似,只能在构造方法的首行使用他们来调用其他的构造方法
实验验证的代码过于繁杂,这里读者自行试验
多态
变量多态性
- 一个变量可以保存其所声明的类型或该类型的任何子类型 / 子类的对象可以赋值给父类类型的变量 / 子类对象可以放进存放父类对象的容器中
class Item{
......
}
class CD extends Item{
......
}
class DVD extends CD{
......
}
public class Database{
ArrayList<Item> ItemList = new ArrayList<Item>();
public void add(Item item){//这里参数为Item类型
ItemList.add(item);
}
public static void main(String[] args){
Database database = new Database();
database.add(new CD());//正确 CD为Item的子类
database.add(new DVD());//正确 DVD为CD的子类
}
}
向上造型
Java变量拥有静态类型与动态类型
静态类型,及声明类型;动态类型,及程序当前运行时刻变量中实际保存的类型只能调用当前类型(动态类型)所具有的的方法 参见下方动态绑定
当将子类对象赋值给声明类型为其父类的对象变量时,及发生了向上造型
造型
一个类型的对象赋值给另一类型的变量,称为造型(cast)
class Vehicle{
......
}
class Car extends vehicle{
......
}
Vehicle v;
Car c = new Car();
v = c;//ok 等价于 v = (Vehicle) c; 因为是向上造型,(Vehicle)可省略
c = v;//error
c = (Car)v;//当 v 实际管理一个Car类型的对象时 可以 否则运行时异常
任何对象的赋值,都是使多个变量共同管理同一个对象
● 造型不同于类型转换
int i = (int)10.5;//i=10;类型转换可能使传递的值改变
Vehicle v = (Vehicle) new Car();//v此时的动态类型是Car v现在就被当做一个Car型变量
//此时可以 Car c = (Car) v; //向下造型
//造型使某个对象当做某种类型的变量看待
方法多态性
方法重载
方法重写(方法覆盖)
子类中写有与父类相同的方法,称作方法重写,有@override
标识
方法重写的访问权限需要大于等于原权限- 绑定
当调用一个方法时,究竟应该调用哪个方法,这件事情叫做绑定。绑定有两种:一种是早绑定,又称静态绑定,在编译的时候就根据变量的声明类型确定;另一种是晚绑定,即动态绑定。动态绑定在运行的时候根据变量当时实际所指的对象的类型动态决定调用的方法。Java缺省使用动态绑定。
(动态绑定)当子类的对象调用某个方法,执行的是子类自己的方法。
当父类的对象调用此方法时,调用的是父类中的方法。注意这里是对象,而不是变量,因为一个父类变量可能管理的是子类的对象- 在成员函数中调用其他成员函数,实际上通过this这个对象来调用,所以这种调用也是动态绑定
- 绑定
以上均可通过调试进行检验