当前位置: 首页 > news >正文

让我们进入面向对象的世界(三)

文章目录

  • 前言
  • 一.了解什么是继承
  • 二.我们针对继承来设计一个动物继承树
  • 前言
    • 2.1 第一步 找出共同属性和行为的对象
    • 2.2 设计代表共同状态行为的类
    • 2.3 决定子类是否让某项行为有不同的运作方式。
    • 2.4我们仔细去观察一下子类的特征,争取更多的抽象化的机会。
  • 三.继承的相关语法
    • 3.1 父类的成员的访问
    • 3.2 子类访问父类的成员方法
    • 3.3 super关键字
  • 四.怎么去检验继承关系
  • 五.总结


前言

自从上节课我们开始进入面向对象的封装已经有一些日子了,接下来我们会进入对象村非常有意思的环节,就是继承与多态。为什么我们要去学习这些特性呢?因为这是面向对象非常的重要,还记得我们在第一次进入面向对象村举的第一个例子吗?你的老板要你和你的朋友几个不同的形状,来满足需求,这个时候我们就可以给你的朋友解释一下什么是继承了。


一.了解什么是继承

在设计类的时候,你会把共同的带啊放在某个类中,然后告诉其他的类说此类是它们的父类。当某一个类继承另一个类的时候,也就是子类继承父类的时候。
以java的方式来说,这是“子类继承父类“。继承关系意味着子类继承了父类的方法,当我们提及“类的成员”时,成员的意思就是实例变量和方法。


说了这么多,我举一个简单的例子,让你们大致的了解一下,我上面说的一堆话,到底是什么。
这是一个简单的继承的一个范例:

public class Doctor {
    boolean worksAtHopsptial;
    void treatPatient(){
        //执行检查
    }
}
public class FamilyDoctor extends Doctor{
    boolean makesHouseCalls;
    void giveAdvice(){
        //提出诊断
    }
}
public class Surgeon extends Doctor{
    void treatPatient(){
        //执行检查
    }
    void makeIncision(){
        //截肢
    }
}


在这里插入图片描述
这里面具体的例子就是,我们子类在继承父类的时候可以覆盖父类的方法,也可以增加子类自己独有的实例变量和方法,这这是一个简单例子,让大家继承的了解更清楚一些。


二.我们针对继承来设计一个动物继承树

在开始设计动物继承树之前,我们先来了解一下java继承的语法,在Java中如果要表示类之间的继承关系,需要extends关键字去来实现继承关系。具体怎么操作,跟着我去完成照这个动物继承树的例子之后,你就明白了。


前言

1.假设你要设计一个仿真系统程序,可以让用户设定将一群动物丢到某种环境中以观察会发生什么事情。现在不需要写出程序,我们只在乎设计。
2.我们已经被告知一部分会用到的动物,但是并不知道还有多少种动物会加进来。每个动物都会用一个对象来表示,且动物会在环境中活动,执行任何被设计出的行为。
3.这个程序必须能够在任何时间加入新类型的动物

2.1 第一步 找出共同属性和行为的对象

我这里列举六个动物
在这里插入图片描述大家想一想着六种动物有什么共同点在里面?
当然我已经给大家列出来了。我的答案并不是标准的。
我么可以设五个实例变量
picture:动物图像的名称
food:动物所吃得食物。现在持有meat和grass俩种值
hunger:代表饥饿程度的值,根据动物吃了多少而改变。
boundaries:动物活动的区域的长宽
location:动物活动区域的X与Y坐标。
还有四个方法:
makeNoise():动物发出的声音
eat():动物吃的行为
sleep():不同的动物的睡觉行为
roam():其他行为


2.2 设计代表共同状态行为的类

因为对象都是动物的原因,我们可以用Animal作为共同父类的名称。
并且构造图如下。
在这里插入图片描述


2.3 决定子类是否让某项行为有不同的运作方式。

这里就非常有趣了。我们想一想我们应该让子类覆盖哪些方法呢?其实按照常识来说,狮子的叫声绝对不会跟河马的叫声一样,如果你说一样,那我也没办法了,所以我们要根据不同的类型去设计不同的行为程序。
观察animal的这个类以后,我们认为eat()与makeNosie()应该由各个子类自行覆盖。


2.4我们仔细去观察一下子类的特征,争取更多的抽象化的机会。

类的继承结构已经大致成型。我们让每个子类都去覆盖掉makeNoise()与eat()这两个方法,因此狗不会瞄瞄叫、河马也不会抢狮子的食物。
但或许我们还能做更多的设计。我们必须观察Animal的子类找寻是否有可以组织归纳使用共同程序代码的部分。看起来小红帽的好朋友大野狼跟狗有共同的部分。猫、狮子与老虎也有共同的部分。
1.我们观察到Wolf与Dog可能有某些共同的行为,在Lion、Tiger、Cat之间也是。
2.相信你应该知道我们说的是什么,因为动物本来就有组织化的层次(界、门、纲、目、科、属、种),我们可以用这些层次来制作有意义的类设计。我们使用犬科和猫科动物的分类来作出Feline与Caninc这两个类。
3.我们决定Canine使用共同的roam()方法,因为它们都以相同的方式移动。Feline之间也是差不多。而Hippo则持续使用继承下来的roam()方法。

于是我们得出了下面的继承图
在这里插入图片描述

上述我们对动物继承类的构造已经完成了。大家应该明白的差不多了吧。


三.继承的相关语法

前言

3.1 父类的成员的访问

1.子类和父类不存在相同的成员变量

public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10; // 访问从父类中继承下来的a
b = 20; // 访问从父类中继承下来的b
c = 30; // 访问子类自己的c
}
}

2.子类和父类的成员变量相同

public class Base {
int a;
int b;
int c;
}
/
public class Derived extends Base{
int a; // 与父类中成员a同名,且类型相同
char b; // 与父类中成员b同名,但类型不同
public void method(){
a = 100; // 访问父类继承的a,还是子类自己新增的a?
b = 101; // 访问父类继承的b,还是子类自己新增的b?
c = 102; // 子类没有c,访问的肯定是从父类继承下来的c
// d = 103; // 编译失败,因为父类和子类都没有定义成员变量b
}
}

总结:
如果访问的成员变量子类中有,优先访问自己的成员变量。
如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
如果访问的成员变量与父类中成员变量同名,则优先访问自己的。


3.2 子类访问父类的成员方法

1.成员方法名字不同

public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
}
public class Derived extends Base{
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodB(); // 访问子类自己的methodB()
methodA(); // 访问父类继承的methodA()
// methodD(); // 编译失败,在整个继承体系中没有发现方法methodD()
}
}
  1. 成员方法名字相同
public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
public void methodA(int a) {
System.out.println("Derived中的method(int)方法");
}
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
methodB(); // 直接访问,则永远访问到的都是子类中的methodB(),基类的无法访问到
}
}

总结:
通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到
则访问,否则编译报错。
通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用
方法适传递的参数选择合适的方法访问,如果没有则报错;


3.3 super关键字

由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成
员时,该如何操作?直接访问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父
类的成员。

public class Base {
    int a;
    int b;
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
    public void methodB(){
        System.out.println("Base中的methodB()");
    }
}

public class Derived extends Base{
    int a; // 与父类中成员变量同名且类型相同
    char b; // 与父类中成员变量同名但类型不同
    // 与父类中methodA()构成重载
    public void methodA(int a) {
        System.out.println("Derived中的method()方法");
    }
    // 与基类中methodB()构成重写(即原型一致,重写后序详细介绍)
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
    }
    public void methodC(){
// 对于同名的成员变量,直接访问时,访问的都是子类的
        a = 100; // 等价于: this.a = 100;
        b = 101; // 等价于: this.b = 101;
// 注意:this是当前对象的引用
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从基类继承下来的部分
        super.a = 200;
        super.b = 201;
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
        methodA(); // 没有传参,访问父类中的methodA()
        methodA(20); // 传递int参数,访问子类中的methodA(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
        methodB(); // 直接访问,则永远访问到的都是子类中的methodA(),基类的无法访问到
        super.methodB(); // 访问基类的methodB()
    }
}


四.怎么去检验继承关系

这里其实我们当用一个类去继承另外一个类的时候,我们会去说这是子类应该去继承父类,若你想知道某物是否会去继承父类的时候,则可以用IS-A去验证。
三角形是一个多边形?
外科医生是一个医生?
狮子是一种动物?
这些都是继承关系。
要确认你的设计是否正确,使用这样的测验来加以检验。如果不合理,则表示你的设计有问题。
就比如我们洗澡的时候,浴室和澡盆有关联吧,确实是有关联,但不是继承上的关系。澡盆和浴室发生的是HAS-A的关系,如果表示浴室有澡盆的话,只能说明澡盆是浴室的实例变量,浴室里面会有一个澡盆的引用,但他们其实没有继承关系。

这一个环节到这里就结束了,哈哈,朋友,简单的对我们的继承做个总结吧。


五.总结

我们通过一个问题来总结,我们对继承的意义,这里你先别说,听我列举,然后你再去思考

1.避免了重复的代码
在单一的位置定义共同程序代码,然后让子类继承父类的程序代码。当你想要改变这个行为程序时,只需修改这个地方,而子类就会发生同样的改变。
2.定出了共同的协议
当你在父类中定义方法时,它们会被子类继承,这样你就是在对其他程序代码声明:“我所有的子类(例如说subclass)都能用这些方法来执行这几项工作……”。也就是说你拟出了一份“合约”。
我们提出动物继承关系的Animal这个类拟出所有动物子型的共同协议。

朋友们,今天到这里就结束了,我们还没有讨论最精彩的部分,就是多态,这里留到下一部分,我们再讨论。

相关文章:

  • 动态域名解析
  • 《工程伦理》1-13章汇总
  • Jackson @JsonProperty重复字段处理
  • 元组啊,不就是不可变的列表吗?
  • Java练习题
  • 蓝桥杯跑步锻炼.c语言
  • java计算机毕业设计妇女健康保健系统源码+mysql数据库+系统+lw文档+部署
  • 第十四届蓝桥杯(web应用开发) 模拟赛2期 -大学组
  • 用Python代码画世界杯吉祥物拉伊卜(附代码)
  • 大规模异构图召回在美团到店推荐广告的应用
  • 在大厂工作是这样的
  • [附源码]SSM计算机毕业设计民宿客栈管理系统JAVA
  • FPGA片内RAM读写测试实验+逻辑分析仪ila
  • 【数据结构】七种排序方法,一篇文章掌握
  • 【web前端开发】HTML知识点超详细总结
  • 自己简单写的 事件订阅机制
  • 2017 前端面试准备 - 收藏集 - 掘金
  • Effective Java 笔记(一)
  • EventListener原理
  • Linux各目录及每个目录的详细介绍
  • miaov-React 最佳入门
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • React-flux杂记
  • Redux 中间件分析
  • 复习Javascript专题(四):js中的深浅拷贝
  • - 概述 - 《设计模式(极简c++版)》
  • 关于List、List?、ListObject的区别
  • 汉诺塔算法
  • 前端临床手札——文件上传
  • 小程序 setData 学问多
  • 学习Vue.js的五个小例子
  • 云大使推广中的常见热门问题
  • 智能合约开发环境搭建及Hello World合约
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #NOIP 2014# day.1 T2 联合权值
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (二)hibernate配置管理
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (区间dp) (经典例题) 石子合并
  • (一)u-boot-nand.bin的下载
  • .gitattributes 文件
  • .Net CF下精确的计时器
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET 解决重复提交问题
  • .net生成的类,跨工程调用显示注释
  • [1204 寻找子串位置] 解题报告
  • [Android] Android ActivityManager
  • [BUUCTF NewStarCTF 2023 公开赛道] week4 crypto/pwn
  • [BZOJ1060][ZJOI2007]时态同步 树形dp
  • [c]统计数字
  • [EWS]查找 文件夹
  • [Firefly-Linux] RK3568修改控制台DEBUG为普通串口UART
  • [Kubernetes]4. 借助腾讯云TKE快速创建Pod、Deployment、Service部署k8s项目
  • [mit6.s081] 笔记 Lab2:system calls