什么是继承
把一些类的具有共性的东西剥离出来形成一个新的类,然后各个其他类保留自己独有的特性,并用关键字extends继承这个剥离出来的新的类,可以最终达到各类原始相同效果,但是在每个类中,单用一个“extends 新类” 就可以减少新类里差不多相同量级的代码量。
继承的格式
class 类1 extends 新类{}
其中新类就是剥离出的有共同特性的类。
继承的适用场景
存在“is a”的关系时,例如猫is a 动物,狗is a 动物。
继承的特点
- Java中类只支持单继承
- Java中可以多层继承,即多重的继承体系,A extends B, B extends C, 则A实质上也是extends了B,C
- 子类不能继承父类的私有成员和方法
- 子类不能继承父类的构造方法,但是可以通过super去访问。
继承的好处
- 提高了代码的复用性
- 简化了代码的维护工作
- 是构造多态的基础
继承的坏处
- 不符合低耦合高内聚的思想,让类与类的关系更紧密,类与类的关系复杂
- 打破了封装性
封装的好处在只能从类暴露的方法去访问私有变量,但是继承则可以从子类方法通过继承的父类方法间接去访问父类的私有成员。
另外,如果要想让子类继承共性的属性(成员变量),则不能进行封装,因为private的成员变量和方法都不能被继承,这构成了冲突。
继承中的成员关系
成员变量
子类的成员变量名称和父类中的成员变量名称不一样,直接可以从名字区分;
子类的成员变量名称和父类中的成员变量名称一样,通过this和super来区分,this.成员变量是子类的,super的成员变量是父类的(非private时)
总之,在子类的方法中访问变量时,如果不用this和super来明确区分,则查找的顺序如下:
a. 在子类方法的局部范围找,有就使用。
b. 在子类的成员范围找,有就使用。
c. 在父类的成员范围找,有就使用。
d. 找不到,就报错。
构造方法
子类的构造方法默认会去访问父类的无参构造方法, 这是为了子类访问父类数据的初始化,如果父类中如果没有无参构造方法,
1. 需要子类通过super去明确调用带参构造方法,不然则报错。
2. 子类通过this调用本身的其他构造,但是最终一定会有一个去访问了父类的构造。
3. 让父类提供无参构造。
成员方法
子类的成员方法和父类中的成员方法名称不一样,可以直接用名字来区分;
子类的成员方法和父类中的成员方法名称一样,通过super和this来明确区分,例如this.function() or super.function();
如果没有用this和super来明确区分,最后通过子类对象访问一个方法的查找顺序为:
a. 在子类中找,有就使用
b. 在父类中找,有就使用
c. 找不到,就报错
继承中的方法重写(override)
子类和其继承的父类有一模一样的方法,从返回值到参数列表都是一模一样的,修饰符没有苛刻要求一样;
重写的特征:
1. 方法重写的要求子类重写方法的访问修饰符范围必须大于或者等于父类对应方法的访问修饰符范围,例如父类是public,则子类不能为protected。
2. 子类重写方法的返回值类型必须和父类方法一致
3. 重写方法的参数必须和父类方法一致
和重载(overload)的区别:
1. 重载是发生在一个类中,方法名相同,参数列表不同,但是修饰符和返回值类型没有要求,因为在调用时无法通过修饰符和返回值类型来区分不同函数。
2. 重写发生在继承中,要求方法名,参数列表,返回值类型完全一样,修饰符访问范围不低于父类。重写的目的在与覆盖父类方法,其他的要求完全可以用重载在子类中去做。
继承中的super关键字
1. super代表父类对象;
2. 通过super.变量名访问父类非私有成员变量,通过super.成员方法来访问父类非私有成员方法;
3. 通过super()或者super(参数)来调用父类构造方法,且在子类构造方法中默认调用了super();