Java继承:抽取相同共性,实现代码复用

在这里插入图片描述

  • 👑专栏内容:Java
  • ⛪个人主页:子夜的星的主页
  • 💕座右铭:前路未远,步履不停

目录

  • 一、继承的概念
  • 二、继承的语法
  • 三、父类成员访问
    • 1、子类中访问父类成员变量
      • Ⅰ、子类和父类不存在同名成员变量
      • Ⅱ、子类和父类成员变量同名
    • 2、子类中访问父类的成员方法
      • Ⅰ、成员方法名字不同
      • Ⅱ、成员方法名字相同
    • 3、`super`关键字
    • 4、子类构造方法
    • 5、`super`和`this`的区别
  • 四、继承方式
    • 1、 `final`关键字
    • 2、继承与组合


(。・∀・)ノ゙嗨,今天让我们来一起学习一下Java的继承吧。

Java中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,可能两个对象之间会存在某种关系。继承在编程中也是类似的概念,其中一个类可以继承另一个类的属性和方法,并且可以在此基础上添加或修改。这样可以使代码更加模块化、可维护,同时提高代码的复用性。
在这里插入图片描述

一、继承的概念

假设我们现在有两个类,一个是猫类,另外一个是狗类。

// Dog.java
public class Dog{string name;int age;float weight;public void eat(){System.out.println(name + "正在吃饭");}public void sleep(){System.out.println(name + "正在睡觉");}void Bark(){System.out.println(name + "汪汪汪~~~");}
}
// Cat.java
public class Cat{string name;int age;float weight;public void eat(){System.out.println(name + "正在吃饭");}public void sleep(){System.out.println(name + "正在睡觉");}void mew(){System.out.println(name + "喵喵喵~~~");}
}

通过观察上述代码会发现,猫和狗的类中存在大量重复,如下所示:

image-20230510003440174
那能否将这些共性抽取呢?既然狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。
image-20230510004236552
上述图示中,DogCat都继承了Animal类,其中:Animal类称为父类/基类或超类,DogCat可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。
在这里插入图片描述
从上面可以看出,继承概念中可以看出继承最大的作用就是:共性的抽取,实现代码复用

二、继承的语法

在Java中如果要表示类之间的继承关系,需要借助extends关键字,具体如下:

修饰符 class 子类 extends 父类 {
// ... 
}

图片描述

让我们对上面的常见用继承重新设计一下吧。
首先,我们可以创建一个父类叫做动物类。

// nimal.java
public class Animal {String name; // 动物的名字int age; // 动物的年龄// 动物吃饭的方法public void eat() {System.out.println(name + "正在吃饭");}// 动物睡觉的方法public void sleep() {System.out.println(name + "正在睡觉");}
}

然后,让猫类和狗类分别继承动物类。

// Dog.java
public class Dog extends Animal { // Dog类继承自Animal类// 狗叫的方法void bark() {System.out.println(name + "汪汪汪~~~");}
}

// Cat.Java
public class Cat extends Animal { // Cat类继承自Animal类// 猫叫的方法void mew() {System.out.println(name + "喵喵喵~~~");}
}

在这里插入图片描述
这里,dog类和Cat类中并没有定义任何成员变量,nameage属性肯定是从父类Animal中继承下来的,其使用的eat()sleep()方法也是从Animal中继承下来的。

注意:

  • 子类会将父类中的成员变量或者成员方法继承到子类中了

  • 子类继承父类之后,必须要新添加自己特有的成员,否则就没有必要继承了

三、父类成员访问

在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?

1、子类中访问父类成员变量

Ⅰ、子类和父类不存在同名成员变量

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

Ⅱ、子类和父类成员变量同名

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}
}

在子类方法中 或者 通过子类对象访问成员时

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。

  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。

  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。

成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找

2、子类中访问父类的成员方法

Ⅰ、成员方法名字不同

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()}
}

总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。

Ⅱ、成员方法名字相同

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(),基类的无法访问到}
}

【说明】

  • 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。

  • 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错。

问题:如果子类中存在与父类中相同的成员时,那如何在子类中访问父类相同名称的成员呢?

在Java中,如果子类中存在与父类中相同名称的成员,那么在子类中默认访问的是子类自己的成员。要在子类中访问父类的同名成员,可以使用super关键字。super关键字用于引用当前子类实例的直接父类。

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; // 使用相同的名称和类型遮蔽了基类中的成员变量'a'char b; // 使用相同的名称但不同类型遮蔽了基类中的成员变量'b'// 重载了基类中的methodA()public void methodA(int a) {System.out.println("Derived中的method()方法"); // 打印表明在派生类中的语句}// 重写了基类中的methodB()public void methodB(){System.out.println("Derived中的methodB()方法"); // 打印表明在派生类中的语句}public void methodC(){// 对于同名的成员变量,直接访问时,访问的是派生类中的变量this.a = 100; // 等价于:this.a = 100;this.b = 101; // 等价于:this.b = 101;// 注意:'this' 是当前对象的引用// 要访问基类中的成员变量,需要使用'super'关键字super.a = 200;super.b = 201;// 在基类和派生类中都存在重载的方法,可以通过参数列表区分访问基类还是派生类的方法methodA(); // 没有传参,访问基类中的methodA()methodA(20); // 传递int参数,访问派生类中的methodA(int)// 要访问重写的基类方法,需要使用'super'关键字methodB(); // 直接访问,则永远访问派生类中的methodB(),无法访问基类的super.methodB(); // 访问基类的methodB()}
}

在子类方法中,如果想要明确访问父类中成员时,借助super关键字即可。

注意事项

  • 只能在非静态方法中使用。

  • 在子类方法中,访问父类的成员变量和方法。

4、子类构造方法

在这里插入图片描述
子类对象构造时,需要先调用基类(父类)构造方法,然后执行子类的构造方法。

public class Base {public Base(){System.out.println("Base()"); // 打印在基类构造方法中的语句}
}public class Derived extends Base{public Derived(){// super(); 注意:子类构造方法中默认会调用基类的无参构造方法:super()// 当用户没有显式写出时,编译器会自动添加super(),并且super()必须是子类构造方法中的第一条语句,// 并且只能出现一次System.out.println("Derived()"); // 打印在派生类构造方法中的语句}
}public class Test {public static void main(String[] args) {Derived d = new Derived(); // 创建派生类的实例}
}
结果打印:Base()Derived()

在子类的构造方法中,如果没有显式地写出关于基类构造的代码,那么在构造子类对象时会先执行基类的构造方法,然后再执行子类的构造方法。

这是因为子类对象的成员由两部分组成:继承自基类的部分和子类新增加的部分。

因此,在构造子类对象时,需要先调用基类的构造方法来构造继承下来的成员,然后再调用子类自己的构造方法来初始化子类新增加的成员。

需要注意以下几点:

  1. 如果父类显式地定义了无参或默认的构造方法,那么在子类的构造方法中,默认会隐含地调用super(),即调用基类的构造方法。
  2. 如果父类的构造方法带有参数,那么在子类中就需要显式地定义构造方法,并在子类的构造方法中选择适合的父类构造方法进行调用,否则会导致编译错误。
  3. 在子类的构造方法中,通过super(...)调用父类构造方法时,必须作为子类构造函数中的第一条语句。
  4. super(...)只能在子类的构造方法中出现一次,并且不能与this同时出现。

5、superthis的区别

superthis都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那他们之间有什么区别呢?

相同点

  • 都是Java中的关键字

  • 只能在类的非静态方法中使用,用来访问非静态成员方法和字段

  • 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

不同点

  • this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用

image-20230511174010010

  • 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性

  • 在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造方法中出现

  • 构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有

四、继承方式

在Java中只支持以下几种继承方式:

image-20230512151133518
注意:Java中不支持多继承。

时刻牢记, 我们写的类是现实事物的抽象. 而我们真正在公司中所遇到的项目往往业务比较复杂, 可能会涉及到一系列复杂的概念, 都需要我们使用代码来表示, 所以我们真实项目中所写的类也会有很多,类之间的关系也会更加复杂。

但是即使如此, 我们并不希望类之间的继承层次太复杂。 一般我们不希望出现超过三层的继承关系. 如果继承层次太多, 就需要考虑对代码进行重构了。如果想从语法上进行限制继承, 就可以使用final 关键字。

在这里插入图片描述

1、 final关键字

final关键可以用来修饰变量、成员方法以及类。

final修饰符大多数应用于基本类型域,或不可变类的域。

将方法或者类的声明为final的主要目的是:确保它们不会在子类中改变语义。

  • 修饰变量或字段,表示常量(即不能修改)
final int a = 10;
a = 20; // 编译出错
  • 修饰类:表示此类不能被继承
final public class Animal {...
}
public class Bird extends Animal {...
}
// 编译出错
Error:(3, 27) java: 无法从最终com.bit.Animal进行继

image-20230512151520650

我们平时是用的String 字符串类, 就是用 final修饰的, 不能被继承

  • 修饰方法:表示该方法不能被重写

2、继承与组合

和继承类似,组合也是一种表达类之间关系的方式,也是能够达到代码重用的效果。组合并没有涉及到特殊的语法(诸如 extends 这样的关键字),仅仅是将一个类的实例作为另外一个类的字段。

组合(或聚合)是另一种关系,表示一个类是由其他类的对象组成的。换句话说,一个类的对象包含了其他类的对象。这种关系通常被描述为“有-a"关系。例如,一辆汽车有一个引擎和四个轮子,因此汽车类可以包含一个引擎对象和四个轮子对象。
image-20230512151945967
组合的主要优点是它提供了更好的封装,更强的代码灵活性,更易于修改和维护。由于类之间的关系不再像继承那样紧密,所以修改一个类的实现不太可能影响到使用该类的其他类。此外,组合也使得代码更加模块化,每个类都专注于一个单一的职责。

然而,组合也有一些缺点。它可能导致更复杂的代码,因为你需要管理和协调多个对象之间的交互。选择使用继承还是组合通常取决于具体的需求和上下文。

一般来说,如果两个类之间存在"is-a"(是一个)的关系,比如“苹果是一种水果”,那么继承可能是最好的选择;如果两个类之间存在"has-a"(有一个)的关系,比如“汽车有一个引擎”,那么组合可能是更好的选择。

更详细的可以看这个大佬的文章:深入理解Java中的组合和继承


继承就先说到这里了,我们下次再见!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql:B+树/事务

B树 : 为了数据库量身定做的数据结构 我们当前这里的讨论都是围绕 mysql 的 innodb 这个存储引擎来讨论的 其他存储引擎可能会用到hash 作为索引,此时就只能应对这种精准匹配的情况了 要了解 B树 我们先了解 B树, B树 是 B树 的改进 B树 有时候会写作 B-树 (这里的" -…

Rust编程基础核心之所有权(上)

1.什么是所有权? Rust 的核心功能(之一)是 所有权(ownership)。虽然该功能很容易解释,但它对语言的其他部分有着深刻的影响。 所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制&#x…

pytorch+LSTM实现使用单参数预测,以及多参数预测(代码注释版)

开发前准备: 环境管理:Anaconda python: 3.8 显卡:NVIDIA3060 pytorch: 到官网选择conda版本,使用的是CUDA11.8 编译器: PyCharm 简述: 本次使用seaborn库中的flights数据集来做试验,我们通过…

ConnectionError: HTTPSConnectionPool

ConnectionError: HTTPSConnectionPool(host‘zbbfxstatic.figtingdream.com’, port443): Max retries exceeded with url: /api/cache (Caused by NewConnectionError(‘<urllib3.connection.HTTPSConnection object at 0x00000249795AD9A0>: Failed to establish a ne…

游戏开发中的“御用中介“

点击上方亿元程序员关注和★星标 引言 大家好&#xff0c;我是亿元程序员&#xff0c;一位有着8年游戏行业经验的主程。 本系列是《和8年游戏主程一起学习设计模式》&#xff0c;让糟糕的代码在潜移默化中升华&#xff0c;欢迎大家关注分享收藏订阅。 游戏开发中的"御用…

【Redis】String字符串类型-常用命令

文章目录 String字符串类型常用命令setgetMGETMSET 计数命令INCRINCRBYDECRDECRBYINCRBYFLOAT 其它命令APPENDGETRANGESETRANGESTRLEN 命令总结 String字符串类型 1&#xff09;⾸先Redis中所有的键的类型都是字符串类型 2&#xff09;字符串类型的值&#xff08;value&#…

2.2整式的加减(第1课时)——合并同类项教学及作业设计

【学习目标】 1&#xff0e;理解同类项的概念&#xff0c;并能正确辨别同类项&#xff0e; 2&#xff0e;理解合并同类项的依据是乘法分配律&#xff0c;掌握合并同类项的方法&#xff0e; 知识点归纳&#xff1a; ★合并同类项后&#xff0c;所得的项的系数是___________…

Linux学习第28天:Platform设备驱动开发(二): 专注与分散

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 三、硬件原理图分析 四、驱动开发 1、platform设备与驱动程序开发 53 /* 54 * 设备资源信息&#xff0c;也就是 LED0 所使用的所有寄存器 55 */ 56 static str…

堆叠注入 [GYCTF2020]Blacklist1

打开题目 判断注入点 输入1&#xff0c;页面回显 输入1 页面报错 输入 1 # 页面正常&#xff0c;说明是单引号的字符型注入 我们输入1; show databases; # 说明有6个数据库 1; show tables; # 说明有三个表 我们直接查看FlagHere的表结构 1;desc FlagHere&#xff1b;# 发…

【Hadoop】Apache Hadoop YARN

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; 感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01; 目录 一、YARN概述 二、YARN基础架构 2.1 ResourceManager&#x…

[100天算法】-有序矩阵中第K小的元素(day 58)

题目描述 给定一个 n x n 矩阵&#xff0c;其中每行和每列元素均按升序排序&#xff0c;找到矩阵中第 k 小的元素。 请注意&#xff0c;它是排序后的第 k 小元素&#xff0c;而不是第 k 个不同的元素。示例&#xff1a;matrix [[ 1, 5, 9],[10, 11, 13],[12, 13, 15] ], k …

基础知识:位运算

基础知识&#xff1a;位运算 1. 两类表达式 1. 两类表达式

展开一个结构加法等式

4a6 4a8 - - - - - 1 - 1 - - - 1 - 1 - - 1 - - 1 - - 1 - - 1 - - - - 在5-1的方向上具体展开4a64a8 25 19 19 19 19 19 19 19 25 19 19 19 19 19 19 19 1 10 10 10 10 10 10 10 1 10 10 10 10 10 10 10 …

全网最详细的【shell脚本的入门】

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Linux》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这…

蓝桥杯每日一题2023.11.5

题目描述 方格分割 - 蓝桥云课 (lanqiao.cn) 题目分析 对于每个图我们可以从中间开始搜索&#xff0c;如果到达边界点就说明找到了一种对称的方法&#xff0c;我们可以直接对此进行答案记录每次进行回溯就会找到不同的图像&#xff0c;如果是一样的图像则算一种情况&#xff…

初识Vue 输出Hello World 及注意事项

在我们还没接触Vue之前&#xff0c;我同学常说我可以直接在元素里输出JS的表达式吗&#xff1f;肯定是不太行。当我们接触vue.js后&#xff0c;这个想法成了现实。 每当我们学习一门新的语言或者框架时&#xff0c;我们都习惯打印一个“hello world”&#xff0c;在我们vue当中…

Docker 安装ELK7.7.1

(注&#xff1a;在安装之前&#xff0c;本方法必须安装jdk1.8以上版本) (注&#xff1a;如果在虚拟机下用可以直接按方法走即可&#xff0c;如果是想进行备份后在别的机器上进行相关操作&#xff0c;必须把所有带有172.17.0.6、192.168.8.166:9200和端口号都改成你自己的方可使…

使用 curator 连接 zookeeper 集群 Invalid config event received

dubbo整合zookeeper 如图&#xff0c;错误日志 2023-11-04 21:16:18.699 ERROR 7459 [main-EventThread] org.apache.curator.framework.imps.EnsembleTracker Caller0 at org.apache.curator.framework.imps.EnsembleTracker.processConfigData(EnsembleTracker.java…

MTK联发科、高通、紫光展锐手机SOC平台型号汇总(含详细参数)

MediaTek联发科手机平台汇总&#xff1a; Qualcomm高通SOC平台汇总&#xff1a; 紫光展锐SOC平台汇总&#xff1a; 新移科技已成功研发手机SOC平台&#xff1a; 联发科平台&#xff1a; MTK6739、MTK6761、MTK6762、MTK6765、MTK8788、MTK6853、MTK6873、MTK6833、MTK6877、…

试试流量回放,不用人工写自动化测试case了

大家好&#xff0c;我是洋子&#xff0c;接触过接口自动化测试的同学都知道&#xff0c;我们一般要基于某种自动化测试框架&#xff0c;编写自动化case&#xff0c;编写自动化case的依据来源于接口文档&#xff0c;对照接口文档里面的请求参数进行人工添加接口自动化case 其实…