目录
一、继承概述
1.定义
继承描述的是事物之间的所属关系,这种关系是:is-a 的关系。例如,兔子属于食草动物,食草动物属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。
继承:就是子类继承父类的属性和行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
2.优点
- 提升代码的复用性(多个子类重复的代码抽取到父类中,减少代码冗余,相同代码重复利用)。
- 使类与类之间产生了关系、
- 子类可以在父类的基础上,增驾其他功能,使子类更加强大
3.格式
通过 extends关键字,可以声明一个子类继承另外一个父类,定义格式如下:
class 父类 {
...
}
class 子类 extends 父类 {
...
}
例如:
public class Student exends Person{
...
}
public class Teacher exends Person{
...
}
Student与Student称为子类(派生类),Person称为父类(基类或者超类)
4.使用
什么时候用继承?
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承来优化代码。
二、继承特点
Java只支持单继承,不支持多继承,但支持多层继承
1.单继承:一个子类智能继承一个父类
2.不支持多继承:子类不能同时继承多个父类
3.多层继承:子类A继承父类B,父类B可以继承父类C,其中C是A的间接父类,B是A的直接父类
事实上Java每个类都直接或者间接继承于Object,这是虚拟机自动给没有继承父类的子类加上的
三、继承可以继承的内容
子类可以继承父类的内容有:
我们接下来对构造方法、成员变量、成员方法分类讨论
1.构造方法是否可以被继承
因为构造方法要求与类的名称一致,所以父类的构造方法一定和父类类名一致,子类不可能与父类的类名一致,所以子类不能继承父类的构造方法,子类的构造方法必须手动写一遍
2.成员变量是否可以被继承
子类可以继承父类的非私有成员变量和私有成员变量,子类可以直接访问非私有变量,但是子类无法直接访问私有成员变量,可以通过getter/setter方法访问父类的private成员变量
3.成员方法是否可以被继承
最高级的父类会生成一个虚方法表存储一些常用的方法,这些方法不能用private、static、final修饰,最高级的父类会把虚方法表传递给次一级的父类,次一级的父类会在最高级父类的基础上在虚方法表上添加自己的虚方法,以此类推
如图,如果我们要方法A中调用方法C,如果方法C在A的虚方法表中,A就可以直接找到方法C并调用,如果方法C不在A的虚方法表中,则A会从自己的父类中逐级向上寻找直到找到方法C才能调用
因此,只有父类中的虚方法才会被子类继承
四、关于继承的内存图
(1)main函数在方法区生成字节码文件,接下来就是Zi生成字节码文件,此时虚拟机发现Zi有一个父类Fu,由此方法区也会生成Fu的字节码文件,事实上Object也会生成字节码文件
(2)进入main函数,第一行代码要求创建一个Zi对象。对内存空间会分成两块
(3)打印的是Z的地址值
(4)成员变量赋值过程中,先找子类的区域,如果子类没有这个成员变量,虚拟机会从父类里找
(5)main方法出栈,内存变垃圾值
可以看到有继承的Java代码内存图有两点不一样
- 加载字节码文件时,也会加载父类的字节码文件
- 在创建对象时,内存空间存储自己子类的成员变量的同时,也会存储从父类继承过来的成员变量
如果父类成员变量用private修饰
成员变量name先在子类的空间找,子类没有,再到父类的空间找,父类的name被private修饰,不能访问,此时代码报错,所以说父类私有变量虽然被子类继承下来了,但是子类不能使用
成员方法是否可以被继承
(1)Object自带五个虚方法,虚方法表传给Fu类,Fu类在虚方法表中添加fushow()方法,此时虚方法表有6个方法,然后再将表传给Zi类,以此类推
(2)fushow2()是私有的,虚方法表中并没有,调用会导致报错