七、继承
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成继承关系。
-
-
提高代码的扩展性。
-
类与类之间产生了关系,是学习多态的前提。例如:学生 is - a 人。
【修饰符】 class 父类 {
...
}
【修饰符】 class 子类 extends 父类 {
...
}
1、Java只支持单继承,每一个子类只有一个直接父类
2、Java支持多层继承,父类还可以有父类
3、子类会继承父类所有特征,包括成员变量、成员方法,哪怕是私有的,私有的在子类中无法直接使用。
4、子类不会继承父类的代码块、构造器等。
5、但是子类一定会调用父类的实例初始化方法。
-
-
子类虽会继承父类私有(private)的成员,但子类不能对继承的私有成员直接进行访问,可通过继承的get/set方法进行访问。如图所示:
我们说父类的所有成员变量都会继承到子类中,那么如果子类出现与父类同名的成员变量会怎么样呢?
结论:
(1)当父类的成员变量私有化时,在子类中是无法直接访问的,所以是否重名不影响,如果想要访问父类的私有成员变量,只能通过父类的get/set方法访问;
格式:super.父类成员变量名,但是前提条件,这个成员变量没有私有化。
说明:虽然我们可以区分父子类的重名成员变量,但是实际开发中,我们不建议这么干。
我们说父类的所有方法子类都会继承,但是当某个方法被继承到子类之后,子类觉得父类原来的实现不适合于子类,该怎么办呢?
1.@Override:写在方法上面,用来检测是不是有效的正确覆盖重写。这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。建议保留
2.必须保证父子类之间方法的名称相同,参数列表也相同。
注意:如果返回值类型是基本数据类型和void,那么必须是相同
4.子类方法的权限必须【大于等于】父类方法的权限修饰符。
5.几种特殊的方法不能被重写
-
静态方法不能被重写
-
私有等在子类中不可见的方法不能被重写
-
final方法不能被重写
小贴士:重写时,用到super.父类成员方法,表示调用父类的成员方法。
当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?
-
所以子类是无法继承父类构造方法的。
-
构造方法的作用是初始化实例变量的,而子类又会从父类继承所有成员变量
所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个
super()
,表示调用父类的实例初始化方法,父类成员变量初始化后,才可以给子类使用。
如果父类没有无参构造怎么办?
解决办法:在子类构造器中,用super(实参列表),显示调用父类的有参构造解决。
结论:
子类对象实例化过程中必须先完成从父类继承的成员变量的实例初始化,这个过程是通过调用父类的实例初始化方法来完成的。
-
super():表示调用父类的无参实例初始化方法,要求父类必须有无参构造,而且可以省略不写;
-
super(实参列表):表示调用父类的有参实例初始化方法,当父类没有无参构造时,子类的构造器首行必须写super(实参列表)来明确调用父类的哪个有参构造(其实是调用该构造器对应的实例初始方法)
-
super()和super(实参列表)都只能出现在子类构造器的首行
表示这个类不能被继承,没有子类
2、修饰方法
表示这个方法不能被子类重写
3、声明常量
如果某个成员变量用final修饰后,没有set方法,并且必须初始化(可以显式赋值、或在初始化块赋值、实例变量还可以在构造器中赋值)
当修饰的是数组变量时,数组的地址值不可以改变但数组元素可以改变。
this代表当前对象的引用(地址值),即对象自己的引用。
-
-
this用于实例方法中:表示调用该方法的对象,即谁在调用,this就代表谁。
1、this.成员变量名
2、this.成员方法
调用当前对象自己的成员方法时,都可以加"this.",也可以省略,实际开发中都省略
3、this()或this(实参列表)
当需要调用本类的其他构造器时,就可以使用该形式。
要求:
如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了"this(【实参列表】)",否则会发生递归调用死循环
在子类中访问父类的成员变量,特别是当子类的成员变量与父类的成员变量重名时。
(3)super()或super(实参列表)
在子类的构造器首行,用于表示调用父类的哪个构造器(本质上是该构造器对应的实例初始化方法)
super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。
this()和this(实参列表) 与 super()或super(实参列表) 不能同时出现
-
没有super和this
-
在构造器、代码块、方法中如果出现使用某个变量,先查看是否是当前块声明的局部变量,
-
-
如果当前类中没有找到,会往上找父类的(非private,跨包还不能是缺省的)
-
-
this :代表当前对象的引用。
-
通过this找成员变量和成员方法时,先从当前类中找,没有的会往上找父类的(非private,跨包还不能是缺省的)。
-
但是this()或this(实参列表)只会在本类中找
-
-
super :代表父类的存储空间标识(可以理解为父类的引用)。
-
通过super找成员变量和成员方法时,直接从父类空间(包含父类的父类继承的)找
-
super()或super(实参列表)只能从直接父类找
-
通过super只能访问父类在子类中可见的(非private,跨包还不能是缺省的)
-
this一定是从当前类的成员开始找
即没有this又没有super,一定是从局部变量开始找
注意:super和this都不能出现在静态方法和静态代码块中,因为super和this都是存在与对象中的
(1)静态类成员变量的显式赋值语句
(2)静态代码块中的语句
整个类初始化只会进行一次,如果子类初始化时,发现父类没有初始化,那么会先初始化父类。
结论:
每一个类都有一个类初始化方法
实例初始化方法的方法体,由四部分构成:
(1)super()或super(实参列表) 这里选择哪个,看原来构造器首行是哪句,没写,默认就是super()
(2)非静态实例变量的显示赋值语句
(3)非静态代码块
(4)对应构造器中的代码
特别说明:其中(2)和(3)是按顺序合并的,(1)一定在最前面(4)一定在最后面
执行特点:
-
创建对象时,才会执行,
-
调用哪个构造器,就是指定它对应的实例初始化方法
-
创建子类对象时,父类对应的实例初始化会被先执行(父类的clinit<>(有参或无参)方法执行完后再执行子类的init<>(有参或无参)方法),执行父类哪个实例初始化方法,看用super()还是super(实参列表)
结论:
类初始化肯定优先于实例初始化。
类初始化只做一次。
实例初始化是每次创建对象都要进行。