面向对象修炼手册(二)(消息与继承)(Java宝典)

🌈 个人主页:十二月的猫-CSDN博客
🔥 系列专栏: 🏀面向对象修炼手册

💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 

目录

前言

消息传递

1 基本概念

1.1 概念

 2 消息表达式

3 消息机制特性

4 java中的消息传递

动/静态类型语言

1 动态类型语言

2 静态类型语言

3 区别与联系

伪变量 

继承

1 子类与父类

1.1 子类与父类的关系限制

1.2 子类与父类的替换原则

1.3 改写(重写)(覆盖)

1.4 继承形式

1.4.1 特化继承

1.4.2 规范继承

1.4.3 构造继承

1.4.4  泛化继承

1.4.5  扩展继承

1.4.6  限制继承

1.4.7  变体继承

1.4.8  合并继承

1.5 构造函数在继承中

1.5.1 构造函数的调用

1.5.2 构造函数的继承

1.5.3 子类与父类的构造函数

1.5.4 子类、父类构造例题:

总结


前言

上文介绍了类和对象的基础概念,然后深入研究了面向对象编程这个词语的深层含义。

简单复习一下:

面向对象方法的本质:

  • 找代理
  • 消息传递给代理
  • 代理解决问题
  • 我的问题就解决了

面向对象:只关注对象,不关注过程;对象包括:对象和实例对象

对于C语言这种面向过程的语言,在编程中,程序员关注的重点是过程、是解决问题的方法、是一个个函数

面向对象语言,在编程中,程序员关注的重点转变为对象

面向对象编程:通过对象间的消息传递解决任务,完成编程

编程的目的是解决问题;

面向过程的语言直接关注解决问题的方法解决问题

面向对象的语言关注解决问题的对象,通过消息传递解决问题

本篇重点来讲消息机制继承

消息机制:细心的小伙伴应该已经发现:消息机制上节课就已经提到过了!没错,消息机制就是面向对象编程中实现相应功能的方法(面向对象编程完成功能都靠对象,而对象完成功能需要消息的传递)。没有消息传递,再有手段的对象也无法完成功能(因为它压根不知道要完成什么功能、有什么要求)

继承:继承自然也是非常重要的。面向对象编程有许多的优点,其中最重要的一点就是代码复用,能够重复使用一段完成特定功能的代码。进一步思考:为什么代理人解决就比全部自己解决更容易?深层次的原因在于:使用代理人解决问题,代表这一类的问题都可以用代理人来解决,不需要每次换算法都要从头实现每一个方法(代码复用性很好)。

继承作为C++三大特性之一,其就体现了代码复用的思想(例如:男人、女人都继承自人类,那么男女人都有作为人的特征。因此男女人编程时可以直接使用人中的特性和方法,不需要改动原本的代码细节(仅仅加入人这一类的各个方法接口即可)

消息传递

消息传递:一个对象通知另一个已经完成声明的对象需要进行的特定行为的机制

本质:调用一个类的方法,在方法中给需要传递的形参

1 基本概念

1.1 概念

对象间相互请求相互协作完成某一任务的途径

  • 对象接收多个消息,响应不同
  • 同一消息给多个对象,响应不同

 2 消息表达式

  1. 消息接受者:消息传递的目的函数,消息的接受对象
  2. 消息选择器:消息传递系统中的过滤器,用于让消息接收者接受并处理特定性的消息
  3. 参数(消息内容) :实际传递给接收者的信息(需要经过选择器的过滤和限定)

3 消息机制特性

封装:

封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法。保护类受到不必要的修改

解耦合:

解除了消息发送者对任务完成过程的耦合,消息发送者不需要具体知道任务是如何完成的。仅仅需要负责发送消息并等待消息接收者的响应即可

消息传递中的重点概念辨析:

1、消息发送的对象是:消息接收器

2、消息接受器过滤后送给消息接收者

3、过程调用是非面向对象编程中的复用方法,其没有接收器

4、 响应消息所执行的行为并不是一成不变的,他们根据接收器类的不同而不同。(响应行为随接收器不同而不同) 

4 java中的消息传递

aCard.flip ();
aCard.setFaceUp(true);
aGame.displayCard(aCard, 45, 56);

/静态类型语言

动/静态类型语言的区别就在对于:变量类型是动态的还是静态的

动态:在运行时绑定

静态:在编译时绑定 

1 动态类型语言

定义:数据类型是动态的(动态绑定、运行时绑定、自动匹配)

  • 类型的检查是在运行时做的;
  • 变量不需要声明类型,程序在运行时自动确定
  • 优点是方便阅读
  • 缺点是不利于调试

2 静态类型语言

定义:数据类型是静态的(静态绑定、编译时绑定、人工分配)

  • 类型检查是编译时确定
  • 变量需要明确类型
  • 优点是结构规范,利于调试
  • 缺点是代码不够简洁

3 区别与联系

  • 动态类型语言与静态类型语言之间的差异在于变量或数值是否具备类型这种特性。
  • 静态类型语言在编译时做出内存分配,动态类型语言在运行时才分配内存

伪变量 

大多数面向对象语言中,接收器并不出现在方法的参数列表中,而是隐藏于方法的定义之中。只有当必须从方法体内部去存取接收器的数值时,才会使用伪变量(pseudo-variable)

Java,C++:this

伪变量在使用时就好像作为类的一个实例

在理解上应该认为this是:接收器留给所有选择器的接口

Java:构造函数中,使用this区分参数和数据成员

public class ThisTest {
    private int i=0;
    //第一个构造器:有一个int型形参
    ThisTest(int i){
       this.i=i+1;//此时this表示引用成员变量i,而非函数参数i
       System.out.println("Int constructor i——this.i:  "+i+"——"+this.i);
       System.out.println("i-1:"+(i-1)+"this.i+1:"+(this.i+1));
       //从两个输出结果充分证明了i和this.i是不一样的!
    }
}

继承

1 子类与父类

1.1 子类与父类的关系限制

  • 子类实例拥有父类的所有数据成员。(私有成员变量也会拥有,但是无法访问)
  • 子类的实例必须至少通过继承实现父类所定义的所有功能

1.2 子类与父类的替换原则

指如果类B是类A的子类,那么在任何情况下都可以用类B来替换类A,而外界毫无察觉(这里强调的是语法上可行,和里氏替换原则有一定的重合)

这里的子类是指符合替换原则的子类关系(形式上继承,行为上也继承

1.3 改写(重写)(覆盖)

子类有时为了避免继承父类的行为,需要对其进行改写

语法上:子类定义一个与父类有着相同名称且类型签名相同的方法

运行时:变量声明为一个类,它所包含的值来自于子类,与给定消息相对应的方法同时出现于父类和子类

改写发生下的实际调用: 

改写发生在:

1、父子类之间

2、同姓名、同标签方法上

1.4 继承形式

继承的目的就是复用代码,但是继承的形式存在区别,存在:1、特殊化;2、规范化;3、构造化;4、泛化两种类型

1.4.1 特化继承

很多情况下,都是为了特殊化才使用继承。在这种形式下,新类是基类的一种特定类型,它能满足基类的所有规范。 用这种方式创建的总是子类型,并明显符合可替换性原则。与规范化继承一起,这两种方式构成了继承最理想的方式,也是一个好的设计所应追求的目标。
例如:
从马派生出白马:从抽象的马,到具有具体颜色(白色)的马,增加了颜色这个属性。
从人派生出男人:从抽象的人,到具有具体性别(男性)的人,增加了性别这个属性。

1.4.2 规范继承

规范化继承用于保证派生类和基类具有某个共同的接口,即所有的派生类实现了具有相同方法界面的方法。基类中既有已实现的方法,也有只定义了方法接口、留待派生类去实现的方法。派生类只是实现了那些定义在基类却又没有实现的方法

在Java中,关键字abstract确保了必须要构建派生类。声明为abstract的类必须被派生类化,不可能用new运算符创建这种类的实例。除此之外,方法也能被声明为abstract,同样在创建实例之前,必须覆盖类中所有的抽象方法。规范化继承可以通过以下方式辨认:基类中只是提供了方法界面,并没有实现具体的行为,具体的行为必须在派生类中实现。GraphicalObject没有实现关于描绘对象的方法,因此它是一个抽象类。其子类Ball,Wall和Hole通过规范子类化实现这些方法

最理想的继承:特殊化继承、规范化继承

1.4.3 构造继承

一个类可以从其基类中继承几乎所有需要的功能,只是改变一些用作类接口的方法名,或是修改方法中的参数列表

即使新类和基类之间并不存在抽象概念上的相关性,这种实现也是可行的

例如:

树-独木舟 保留了材质等属性,修改了形状的属性

堆栈-队列 修改了pop() push()等方法,栈顶和栈底变成了队首和队尾

写二进制文件-写学生信息文件

当继承的目的只是用于代码复用时,新创建的子类通常都不是子类型(违反里氏替换原则)。这称为构造子类化。一般为了继承而继承,如利用一些工具类已有的方法

1.4.4  泛化继承

派生类扩展基类的行为,形成一种更泛化的抽象。不完全等同于特殊化继承的反面。是从基类扩展一部分行为,形成更加泛化的抽象。在程序中表现为对原来存在的功能进行修改或者扩展

子类对基类功能进行修改、拓展。其功能的范围比基类更大,并不一定包含。因此不符合可替换原则

可替换原则: 

  1. 子类可以实现父类的抽象方法,但不能覆盖(改写)父类的非抽象方法。
  2. 子类中可以增加自己特有的方法。
  3. 当子类的方法重写父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  4. 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

前两者保证逻辑上可替换,后两者保证语法上可替换

从Window派生出了Colored_Window。
public Class Window{
...
    double size;
    setSize(){...}
    getSize(){...}
}
public Class Colored_Window extends Window{
...
    String color;
    setColor(String str){...};
    getColor(String str){...};
//扩展了查看颜色和设置颜色两个行为
}

1.4.5  扩展继承

如果派生类只是往基类中添加新行为,并不修改从基类继承来的任何属性,即是扩展继承。(泛化子类化对基类已存在的功能进行修改或扩展,扩展子类化则是增加新功能

由于基类的功能仍然可以使用,而且并没有被修改,因此扩展继承并不违反可替换性原则,用这种方式构建的派生类还是派生类型 

举例:学生(父类)、会弹琴的学生(子类)

1.4.6  限制继承

如果派生类的行为比基类的少或是更严格时(违反里氏替换原则),就是限制继承。

常常出现于基类不应该、也不能被修改时。

限制继承可描述成这么一种技术:它先接收那些继承来的方法,然后使它们无效

举例:双向队列-〉堆栈

1.4.7  变体继承

子类和父类之间都是对方的变体,可以任意选择两个之间的父子关系

举例:用为控制鼠标的代码与用来控制图形输入板的代码几乎完全相同。在概念上没有理由让一个类作为另外一个类的父类,因此可以选择任何一个类作为另外一个类的父类

1.4.8  合并继承

可以通过合并两个或者更多的抽象特性来形成新的抽象。

一个类可以继承自多个基类的能力被称为多重继承 

多重继承在java中是不允许的,因为一旦父类中有同名同签名方法则子类不知道该调用哪个方法

举例:助教

1.5 构造函数在继承中

1.5.1 构造函数的调用
  • 在构造实例对象时,由程序自动调用(隐式调用)
  • 由程序员主动调用:在子类构造方法中调用父类的方法
1.5.2 构造函数的继承
  • 构造函数不能被继承(子类和父类有自己的构造函数)
  • 构造函数只能通过两种方法获得:1、自己编写;2、系统默认生成
1.5.3 子类与父类的构造函数
  • 子类构造函数可以用super()主动调用父类的构造函数(调用必须在第一行完成)
  • 子类构造函数如果没有主动调用父类构造函数,则系统会主动调用父类构造函数
  • 如果系统调用super(),而父类中的super()并不存在,则报错
1.5.4 子类、父类构造例题:

题目一:

运行下面程序:

class SuperClass{
    private int n;
    SuperClass(){
        System.out.println("SuperClass()");
    }
    SuperClass(int n){
        System.out.println("SuperClass(int n)");
        this.n = n;
    }
}
class SubClass extends SuperClass{
    private int n;
    
    SubClass(){
        super(300);
        System.out.println("SuperClass");
        
    }    
    SubClass(int n){
        System.out.println("SubClass(int n):"+n);
        this.n = n;
    }
}
public class TestSuperSub{
    public static void main (String args[]){
        SubClass sc = new SubClass();
        SubClass sc2 = new SubClass(200); 
    }
}

结果如下:

SuperClass(int n)
SuperClass
SuperClass()
SubClass(int n):200

题目二:

class A { 
	A() { 
System.out.println("A"); 
}
 } 
class B extends A {
	 B() {
       System.out.println("B"); 
   } 
}
 class C extends B { 
	C() { 
      System.out.println("C");
    }
 } 
public class hrt { 
	public static void main(String args[]) {
	 new C();
   } 
}

运行结果:

输出
A
B
C

基类构造器总是在导出类的构造过程中被调用,而且按照继承层级逐渐向上链接(调用顺序则是从基类开始向下)。可以理解为,这么做的逻辑关系是在一个类构建时可能会用到其父类的成员、方法。在清理时顺序相反。

总结

本系列内容均来自:山东大学-潘丽老师-面向对象开发技术-课程ppt、《设计模式》、《大话设计模式》

如果觉得写的还不错,可以点个赞收藏一下呀~~

祝大家学业、事业、爱情顺利!

天天开心,没有Bug每一天

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/738857.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python19 lambda表达式

在 Python 中,lambda 表达式是一个小型匿名函数,通常用于实现简单、单行的函数。lambda 函数可以接受任意数量的参数,但只能有一个表达式。 基本语法: lambda arguments: expression这里,arguments 是传递给 lambda …

LeetCode —— 只出现一次的数字

只出现一次的数字 I 本题依靠异或运算符的特性&#xff0c;两个相同数据异或等于0&#xff0c;数字与0异或为本身即可解答。代码如下: class Solution { public:int singleNumber(vector<int>& nums) {int ret 0;for (auto e : nums){ret ^ e;}return ret;} };只出…

Kubernetes排错(十)-处理容器数据磁盘被写满

容器数据磁盘被写满造成的危害: 不能创建 Pod (一直 ContainerCreating)不能删除 Pod (一直 Terminating)无法 exec 到容器 如何判断是否被写满&#xff1f; 容器数据目录大多会单独挂数据盘&#xff0c;路径一般是 /var/lib/docker&#xff0c;也可能是 /data/docker 或 /o…

基于CDMA的多用户水下无线光通信(3)——解相关多用户检测

继续上一篇博文&#xff0c;本文将介绍基于解相关的多用户检测算法。解相关检测器的优点是因不需要估计各个用户的接收信号幅值而具有抗远近效应的能力。常规的解相关检测器有运算量大和实时性差的缺点&#xff0c;本文针对异步CDMA的MAI主要来自干扰用户的相邻三个比特周期的特…

wordpress教程自动采集并发布工具

随着互联网的快速发展&#xff0c;越来越多的人开始关注网络赚钱。而对于许多人来说&#xff0c;拥有一个自己的个人网站是一个不错的选择。然而&#xff0c;要让自己的个人网站内容丰富多样&#xff0c;就需要不断地进行更新。那么&#xff0c;有没有一种方法可以让我们轻松地…

服务器数据恢复—raid5热备盘同步失败导致阵列崩溃如何恢复数据?

服务器存储数据恢复环境&故障&#xff1a; 某品牌DS5300存储&#xff0c;包含一个存储机头和多个磁盘柜&#xff0c;组建了多组RAID5磁盘阵列。 某个磁盘柜中的一组RAID5阵列由15块数据盘和1块热备硬盘组建。该磁盘柜中的某块硬盘离线&#xff0c;热备盘自动替换并开始同步…

C语言入门系列:从内存原理看函数的值传递和引用传递

文章目录 一&#xff0c;值传递二&#xff0c;引用传递三&#xff0c;从内存原理看值传递和引用传递的区别1 值传递内存示意图2 引用传递内存示意图 参考文献 函数参数用于向函数传递数据&#xff0c;C语言支持两种传递方式&#xff1a;值传递和引用传递。 一&#xff0c;值传递…

校史馆虚拟翻书设计有哪些技术上的亮点?

近年来&#xff0c;互动多媒体已成为展览展示行业中备受瞩目的焦点&#xff0c;尤其是那些凭借尖端的投影与感应技术打造的互动装置&#xff0c;它们在各个主题展厅中独领风骚&#xff0c;其独特魅力不言而喻。而当我们深入思考其在校史馆设计中的应用时&#xff0c;不难预见&a…

【每日一题】503. 下一个更大元素 II

思路&#xff08;c&#xff09; 使用单调栈的解法&#xff0c;单调栈里面存的是大于当前元素的index&#xff0c;不是直接存值。但是这个题目是一个循环数组&#xff0c;可以在后面补一段前面的内容&#xff0c;这样就可以正常遍历。将每个位置对应的结果存在map中 后面循环…

BUUCTF [CISCN2019 华北赛区 Day2 Web1] Hack World

1、通过题目&#xff0c;可以知道该题目为SQL注入类型&#xff1a; 2、判断注入类型为数字注入&#xff1a; 3、通过BP抓包&#xff0c;来判断注入点。 字典爆破发现常规的注入方式都被过滤。 4、因此可以尝试通过布尔盲注的方式来得到flag。编写脚本得到flag import requests…

华为仓颉语言:编程语言的新篇章

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Vue.js 自定义组件的三种用法

1.创建项目 创建项目,你可以参考我以前的博文,这里省略了 项目的目录结构如下: 接着,我们在 src/components 目录下创建一个自定义的组件 SplashHello.vue,示例代码如下所示: <template><div><p>{{ title }}</p><p>{{ message }}</p&…

MTK7628+MT7612 加PA定频数据

1、硬件型号TR726A5G121-DPA PC9.02.0017。如下所示&#xff1a; 2、WIFI5.8 AC模式 42&#xff08;5120MHz&#xff09;信道&#xff0c;80带宽 3、WIFI5.8 AC模式 38&#xff08;5190MHz&#xff09;信道&#xff0c;40带宽 4、WIFI5.8 AC模式 36&#xff08;5180 MHz&…

【机器学习】自然语言处理的新前沿:GPT-4与Beyond

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 &#x1f525;引言 背景介绍 文章目的 一、GPT-4简介 GPT-4概述 主要特性 局限性和挑战 二、自监督学习的新进展 自监督学习的原理 代表性模型和技术 三、少样本学习和零样本学习 少样本学习的挑战 先…

AIGC+艺术=教育变革?

在数字化时代的浪潮中&#xff0c;技术的每一次跃进都深刻影响着社会的各个领域&#xff0c;教育亦不例外。近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术的兴起&#xff0c;为艺术教育领域带来了前所未有的变革机遇。当AIGC与艺术相结合&#xff0c;我…

人工智能-鲁棒性(通俗易懂)

1.什么是鲁棒性 在机器学习中&#xff0c;鲁棒性&#xff08;Robustness&#xff09;是指模型对于异常数据或噪声的抗干扰能力。一个鲁棒性较强的模型能够在面对未知的数据或者数据中存在噪声或异常值时&#xff0c;仍能保持较好的性能和泛化能力。鲁棒性是一个重要的性能指标…

JavaSE (Java基础):Scanner类介绍

4 Scanner最最最基础的使用 Scanner是Java中十分常用到的类&#xff0c;对于这个类的用法我认为并不难&#xff0c;想用直接调用就行&#xff0c;在IDE中输入&#xff1a;new Scanner&#xff08;System.in&#xff09;;后按住altenter键后会直接给这个被赋给类的元素&…

如何用家政服务小程序源码系统 快速搭建家政自己接单的软件?

随着移动互联网的快速发展&#xff0c;线上预约服务已成为家政行业的新趋势。然而&#xff0c;许多家政企业面临着信息不透明、服务质量参差不齐、管理效率低下等问题。家政服务小程序系统&#xff0c;可以帮助商家快速搭建自己的接单软件&#xff0c;提升服务效率&#xff0c;…

二叉树第一期:树与二叉树的概念

一、树 1.树的定义 与线性表不同&#xff0c;树是一种非线性的数据结构&#xff0c;由N(N>0)个结点组成的具有层次关系的集合&#xff1b;因其形状类似生活中一颗倒挂着的树&#xff0c;故将其数据结构称为树。 2.树的相关概念 根结点 没有前驱的结点&#xff0c;称为根…

【数据结构】时间复杂度

目录 一、算法的复杂度 二、时间复杂度 2.1 时间复杂度的概念 2.2 大O渐进表示法 2.3 计算时间复杂度步骤 三、常见时间复杂度举例 3.1 ❥ 常数阶 3.2 ❥ 线性阶 3.3 ❥ 平方阶 3.4 ❥ 对数阶 3.5 ❥ 指数阶 3.6 ❥ 多个未知数的复杂度 四、最好&#xff0c;最坏&am…