# 类的继承
[TOC]
## 概述
继承是面向对象的三大特性之一,也是软件实现复用的重要手段之一
Java中的继承是单继承,每个子类都只有一个直接父类,有时候我们也把父类叫做基类或超类。
但是Java中存在**多层继承**,常用的比如每个子类只有一个直接父类,但是该父类依然存在其自身的父类。另外我们也可以通过内部类或者接口来实现多层继承。
**注意**:虽然类继承可以实现代码的复用,但是如果继承的结构过多,也会造成代码段的阅读困难,一般不建议继承的结构超过3层。
## 继承的特点
>[info] 父类和子类是一种一般和特殊的关系。例如水果和苹果,苹果是一种特殊的水果
在Java中定义子类继承父类的语法为:
~~~
[修饰符] class SubClass extends SuperClass {
}
~~~
示例:
~~~
public class Animal {
String sex;
int age;
String type;
}
/继承
public class Dog extends Animal {
}
~~~
extends字面意思解释扩展,其实就是子类除了拥有父类的所有成员变量和方法外,还具备自己的特殊属性。
>[danger] 在子类中是不能够访问父类中通过private修饰的相关成员变量和方法的,这也符合private的使用方式
## 重写父类方法
在子类中包含与父类相同的方法签名的现象称之为【方法重写(override)】,有时也称之为方法覆盖。我们可以说子类重写了父类的方法,子类覆盖了父类的方法。
子类重写方法的意义:子类继承父类之后,调用父类的方法,就不需要重复写,可以节省代码量。
如果使用条件变更,父类的方法不能满足使用需求,那么就需要重写方法,把父类的方法给覆盖掉。重写,也能实现代码的多样性。就好比父亲和儿子的关系,儿子会继承父亲的所有特性,但是儿子呢也会自己发展。
>[info] 重写父类方法需要遵循的规则:
> 返回值和访问控制修饰符可以不一样,但要符合“两同两小一大”的原则
> 两同:方法名和参数列表必须相同(方法签名相同)
> 两小:子类的返回值类型和抛出的异常类要比父类的返回值类型和抛出的异常类更小。这里说的返回值类型小指的是子类和父类的关系。
> 一大:子类的访问权限要比父类的访问权限要大或相等
**注意**:子类重写父类的方法,实际上也是方法的多态性的表现;
## super限定
super的使用和this很相似。
如果需要在子类中使用父类被覆盖的方法,可以使用super关键字。
同样我们也可以使用super.fun()来调用没有别覆盖的方法,但是这样写没有什么意义,因为在子类中就可以直接调用,无需使用super关键字。
~~~
//父类中
protected void say() {
System.out.println("吼,嘶鸣");
}
//子类中
@Override
protected void say() {
String type = super.type;
String sayWang = this.sayWang;
System.out.println("汪汪汪");
}
public void fatherSay() {
super.say();
}
~~~
## 关于继承的几点说明
子类能够继承父类的信息包括:
* 没有使用private 修饰符修饰的成员变量和方法,子类都能够继承
* 子类重写父类的方法,则父类的方法会被隐藏,隐藏的方法或者成员变量可以通过super关键字访问
* 引入super关键字的原因是可以使用被隐藏的成员变量和方法,而且super只能在子类的方法中定义使用
## 调用父类的构造器
> 在Java的世界里,所有类都是Object类的子类
> 在子类的构造器中 ,无论如何在第一行语句中都会调用一次父类的构造器
> 如果没有显式的调用,那么会调用父类的没有参数的构造器,如果父类没有定义空参数的构造器,那么此时就会无法编译。
> 对象创建的过程就是调用对象类的构造器的过程。
~~~
[修饰符] 类名 {
super(...) //调用父类的构造器,如果没有则会调用父类的无参构造器
}
~~~
super()必须出现在第一行,而且只能有一个。
this()和super()在同一构造器中只可能出现一个。
**子类构造器调用父类的构造器可能出现的情况有**
>[info] 1. 子类构造器执行体的第一行显式的使用super调用父类的构造器,此时系统将根据super(params)去调用对应的构造器。
> 2. 子类构造器在执行体的第一行显式的使用this调用重载的构造器,系统将会根据this(params) 调用对应 的重载构造器,本类中的对应的构造器再去调用父类的构造器
> 3. 子类构造器中既没有super有没有this,那么子类在执行构造器语句的时候会去执行父类的无参构造器。
> 4. 无论如何子类都会调用一次父类的构造器
**在实际的开发过程中,我们都会保证一个类中有一个无参的构造器存在。因为如果在其子类中没有定义构造器,或定义了构造器没有显示的去调用父类的构造器,子类也能够编译成功。**
## super,this,super(),this()
| | super | this | super() | this() |
| --- | --- | --- | --- | --- |
| 用处 | super可以用在子类的成员方法中 | this可以用在本类中的成员方法中 | super()可以用在子类的构造器中 | this()可以用在本类的构造器中 |
| 目的 | 调用父类非私有(no private)的成员变量或方法 | 调用本类的成员变量或方法 | 调用父类的构造器 | 调用本类的构造器 |
>[danger] super和this可以同时出现的,而super()和this()不能同时出现在一个构造器中