面向对象三大特性之一:继承—java语言

为什么要有继承

直接上例子(下面图片中的代码为省略代码,建议写成标准的javabean类)

有一个学生类,学生的属性有 姓名和年龄,行为有吃饭,学习,睡觉。
在这里插入图片描述

有一个老师类,老师的属性有 姓名和年龄,行为有吃饭,教书,睡觉。
在这里插入图片描述

有一个班主任类,班主任的属性有 姓名和年龄,行为有吃饭,教书,管纪律,睡觉。
在这里插入图片描述

这些类都有相同的内容,比如 有着共同的属性:姓名和年龄,有着共同的行为:吃饭和睡觉。

这种重复的信息会导致需要写大量重复的代码,而程序员最烦这一点,它们会绞尽脑汁的“偷懒”。

那么可不可以将这些共同的内容提取出来呢?答案当然是可以的,利用继承。

在java中,我们可以将这些内容的共性提取到一个类中,然后将刚才的学生类、老师类、班主任类都继承它。


继承的格式

在刚才的例子中,共性的属性有:姓名和年龄,共性的行为有:吃饭和睡觉。

所以我们可以创建一个 Person类来存储这些的共性的内容
在这里插入图片描述
接着我们需要将原来的学生类,老师类,班主任类继承 这个Person类。

继承格式如下:
A extends B.
意思是 A 继承了 B,我们把 A 称作 B 的子类,把 B 称为 A 的 父类。
在这里插入图片描述
我们来看一下extend的意思
在这里插入图片描述
看这个单词的意思,是为了能够更好的理解 继承。

扩展的意思就是在原有 类的内容上加上一些自己的内容。

也解释了为什么刚才我们取的 类名 为Person。

学生、老师、班主任都是 在人这个类中的扩展,都属于人。
在这里插入图片描述

所以我们这时候就可以改一下之前的代码。

在这里插入图片描述
只有这个 学习的方法我们 的 Person类里面没有,所以需要写在子类里,算是学生类特有的方法。

同理 老师和班主任类也是。
在这里插入图片描述
在这里插入图片描述


继承的好处

由此可见继承 会减少代码的 重复性,同时会使 类与类之间产生了关联。


创建子类对象,调用父类的内容

我们来创建一个对象感受一下继承,还是刚才那个例子。

在这里插入图片描述
贴心的idea告诉我们 可以调用哪些内容,既可以调用 父类的成员变量age name和成员方法eat 和 sleep,也可以调用 子类的 study成员方法。

在这里插入图片描述


子类可以继承父类的哪些内容

继承并不是可以继承下子类的所有内容。

对于private的修饰的一切如变量、方法,子类都无法调用。

成员变量

在这里插入图片描述
我们将Person类的 name 属性 的修饰符 改成了 private。
在这里插入图片描述
会发现这里报错了。

所以说明了,子类是无法直接继承 父类的私有化成员变量,但是一般情况下,父类会提供对应的 get 和 set 方法,这些方法一般是public的,子类可以调用。

所以对于 成员变量来说,只要权限够,就可以继承下来。当然虽然 用 private 修饰符不能直接访问,但是往往可以通过 set and get 方法 间接进行访问。

成员方法

对于 成员方法来说,子类是无法继承权限不够的方法。

比如将Person类 的 吃饭 方法改为 private

在这里插入图片描述
在这里插入图片描述

此时如果我们想通过创建一个学生对象 来调用 父类Person类的 eat 方法,会发现idea都 点不出来。
在这里插入图片描述

如果硬要写,贴心的idea也会提醒 这是人家父类自己的私有方法,你没资格调用。

综上所述,其实能不能继承下来,取决于 父类的成员变量和方法是用什么权限修饰符修饰的,如果使用 public 修饰,肯定是能够继承下来的,除了 父类的构造方法,这个继承不了。

构造方法

对于构造方法来说,无论父类的构造方法用什么修饰符来修饰,都不能继承下来,但是权限如果允许的话,是可以调用父类的构造方法的。

我们再来看刚才那个例子。

在之前学习类和对象的时候,我们都知道,如果没有定义任何的构造方法时,编译器会自动补充一个 无参数的构造方法。

比如刚才的Person类,其实它会自动补充成这样。
在这里插入图片描述
对于我们的子类来说,刚才在 Student类中也没有写 构造方法,所以编译器也会自动补上。

其实在我们创建一个子类对象时(比如Student类时),其实也同时会创建一个父类对象(比如此时就是Person类)

这句话就体现在了子类的构造方法上。

在这里插入图片描述
刚才我们没有写子类的构造方法时,其实编译器会自动补充以上代码。

super关键字

这个 super(); 的意思就是调用我们的父类的构造方法,跟 this(); 会调用本类的构造方法一样。

之前我们学习了 this 关键字,它代表的是 调用者的地址值,那么同样,super则代表着调用者 的父类的地址值

在这里插入图片描述
在创建子类对象的时候,会先 new 一个父类的对象,此时子类会有一个 super 关键字来记录 父类 的地址值。

这个super就跟 this 的使用一模一样,接着刚才的例子我们来演示一下。

在这里插入图片描述
我们创建了一个父类,其中包含一个成员变量 num。

在这里插入图片描述
再创建一个子类继承父类。

其中包含一个成员变量 num 和 非静态方法 test 方法,其中方法内也有一个 局部变量 num,并且打印 num 变量。

如果我现在创建一个 Zi 类对象,然后调用Zi 类 的 test方法,那么会打印几呢?

在这里插入图片描述
答案是10.
在这里插入图片描述
这里打印 10 的原因是 test 方法中的 num 为一个局部变量,离打印语句最近,局部优先原则,所以会打印 10。

当然如果想打印 20的num 也是可以的,打印30的num也是可以的。

这个时候就需要用到 this关键字和 super 关键字。
在这里插入图片描述
如果换成this.num,那么就会打印 20的 num。

在这里插入图片描述

在这里插入图片描述
如果换成 super.num ,那么则会打印 30的 num。

在这里插入图片描述
当然这是父类和子类有重名的情况,没重名就更简单了,先在局部找,再在子类找,再在父类找,范围会越来越大。

调用 super 来 初始化父类的成员变量

super 关键字其实有一个很关键的作用,就是初始化父类的成员变量。

我们再次回到最开始的例子。

刚开始为了引入继承 没有写 带有全部参数的构造方法,我们现在来补上。

在这里插入图片描述
写成这样我们是不可以在创建对象的时候初始化的。
在这里插入图片描述
所以也证明了子类无法继承父类的构造方法,那么怎么解决呢,我们来修改一下子类的构造方法。

在这里插入图片描述
子类刚才的代码是这样的,只有一个无参构造,所以传不了参数。

所以得这样写。

在这里插入图片描述
通过父类的构造方法进行对父类的成员变量进行初始化。

说明一下,调用这个super的构造方法时,都必须是 该构造方法的第一行,前面不能写任何的其他语句。

在这里插入图片描述
在这里插入图片描述

方法的重写

方法的重写很简单,我们来看下面例子。
在这里插入图片描述
这里有一个 Animal 类,这里为了方便就不写javabean类了。

其中这个类有一个 eat方法。

在这里插入图片描述
接着我们 创建一个Dog类继承 Animal类。

Animal 中有一个 eat方法。

此时可以对eat方法进行重写。

也就是再写一个eat方法,其中返回值类型、函数名、函数参数都需要一样,此时就会覆盖掉父类的eat方法。
在这里插入图片描述
此时我们如果创建一个Dog对象,再调用 eat方法,调用的就会是子类的eat方法了,而不是父类的eat方法,是吃狗粮而不是吃东西。
在这里插入图片描述
这里会打印 null 的原因是 我们没有对 对象进行初始化,当一个对象的成员变量没有被初始化的时候,如果是引用数据类型,那么默认会存储 null 。

@Override注解

如果我们需要重写父类的方法,那么最好在方法前面加上 @Override,比如下面这样
在这里插入图片描述
这个注解的意思是 告诉编译器 我要重写方法,此时如果你重写eat方法时 与父类的 函数名不同、参数不同或返回类型不同,那么就会直接报错。

比如下面这个例子
在这里插入图片描述
当方法名发生改动时,这里就会直接报错。

但是如果我们没有写这个 注解时,编译器会认为这是 子类的特有方法。

在这里插入图片描述
这与我们的原意不符,所以加上注解可以防止 重写的时候写错。


java继承的特点

在java中,一个类只能继承一个类,不能一个类同时继承多个类,但是可以多层继承,多层继承的意思是 比如 A类 继承 B类,B类再继承与C类。

在java中,如果一个类没有继承别的类,那么会自动继承 Object类。


虚方法表

假设有这么一个继承结构
在这里插入图片描述
B类继承于A类,C类继承于B类,以此类推。

此时假设在A类中定义了一个下面的 方法。
在这里插入图片描述
根据之前的就近原则,在找 num 的时候是一层一层往上找,如果子类没有则在父类当中找,如果还没有,则在父类的父类当中继续找,如果一直找不到,那么就会编译错误,这是对于成员变量来说是这么找的。

那么如果B类、C类…到H类当中的方法很多,那么如果也是一层一层的找就会很费时间,所以便有了虚方法表。

虚方法表是在 加载类的时候就会出现的。
在这里插入图片描述
加载类的时候会先加载 最上头的类,比如这个例子中的A类,此时A类的方法,就会被记录到虚方法表中。(假设虚方法表当中的横线为方法)

当然这些记录的方法是有要求的,需要 非 static、非 private、非 final的。

在这里插入图片描述
同理 B类加载的时候也会 往虚方法表上 记录。

所以方法重写,就会把之前的方法给覆盖掉,虚方法表记录的就会是子类重写的那个方法。

之后如果调用一个方法,那么就会直接在虚方法表中找,从而提高效率


  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值