Java——继承的初步认识

news2025/1/12 23:06:10

目录

一.为什么需要继承

二.继承概念

三.继承的语法

四.父类成员访问 

1.子类中访问父类的成员变量

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

1.2子类和父类成员变量同名

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

2.1成员方法名字不同

2.2成员方法名字相同

五.super关键字

六.子类构造方法


一.为什么需要继承

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 + "喵喵喵~~~");
 }
}
通过观察上述代码会发现,猫和狗的类中存在大量重复,如下所示:

那能否将这些共性抽取呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用 

二.继承概念

继承 (inheritance) 机制 :是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能 ,这样产生新的类,称 派生类 。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用
例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。

 

 

上述图示中, Dog Cat 都继承了 Animal 类,其中: Animal 类称为父类 / 基类或超类, Dog Cat 可以称为 Animal 的子类/ 派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。
从继承概念中可以看出继承最大的作用就是:实现代码复用,还有就是来实现多态 ( 后序讲 )

三.继承的语法

在Java中如果要表示类之间的继承关系,需要借助 extends 关键字,具体如下:
修饰符 class 子类 extends 父类 {
// ... 
}

 对1.2中场景使用继承方式重新设计:

// Animal.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{
  void bark(){
    System.out.println(name + "汪汪汪~~~");
  }
}

// Cat.Java
public class Cat extends Animal{
 void mew(){
  System.out.println(name + "喵喵喵~~~");
 }
}

// TestExtend.java
public class TestExtend {
 public static void main(String[] args) {
  Dog dog = new Dog();
  // dog类中并没有定义任何成员变量,name和age属性肯定是从父类Animal中继承下来的
  System.out.println(dog.name);
  System.out.println(dog.age);
  // dog访问的eat()和sleep()方法也是从Animal中继承下来的
  dog.eat();
  dog.sleep();
  dog.bark();
 }
}
注意:
  • 子类会将父类中的成员变量或者成员方法继承到子类中了
  • 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了

四.父类成员访问 

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

1.子类中访问父类的成员变量

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

1.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; // 编译失败,因为父类和子类都没有定义成员变量d
  }
}
在子类方法中 或者 通过子类对象访问成员时
  • 如果访问的成员变量子类中有,优先访问自己的成员变量
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找

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

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()
  }
}
总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则 优先访问自己的 自己没有时再到父类中找,如果父类中也没有则报错

2.2成员方法名字相同

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(),基类的无法访问到
  }
}
【说明】
  • 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错
  • 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错
问题:如果子类中存在与父类中相同的成员时,那如何在子类中访问父类相同名称的成员呢?

 

五.super关键字

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

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

  【注意事项】  
  • 只能在非静态方法中使用
  • 在子类方法中,访问父类的成员变量和方法 
super 的其他用法在后文中介绍。

六.子类构造方法

父子父子,先有父再有子,即:子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。
public class Base {
  public Base(){
    System.out.println("Base()");
}
}
public class Derived extends Base{
  public Derived(){
  // super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
  // 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
  // 并且只能出现一次
  System.out.println("Derived()");
 }
}
public class Test {
  public static void main(String[] args) {
   Derived d = new Derived();
  }
}

结果打印:
Base()
Derived()
注意:
  • 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
  • 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败
  • 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句
  • super(...)只能在子类构造方法中出现一次,并且不能和this同时出现

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【QT进阶】Qt Web混合编程之VS2019 CEF的编译与使用(图文并茂超详细介绍)

往期回顾 【QT入门】Qt自定义控件与样式设计之自定义QLineEdit实现搜索编辑框-CSDN博客 【QT入门】Qt自定义控件与样式设计之自定义QTabWidget实现tab在左,文本水平的效果-CSDN博客【QT进阶】Qt Web混合编程之CEF、QCefView简单介绍-CSDN博客 【QT进阶】Qt Web混合编…

敬请关注 | 第五届隆道数智大会——2024数字化采购与供应链发展论坛即将开幕

数智赋能 创新驱动 第五届隆道数智大会 ——2024数字化采购与供应链发展论坛 即将开幕! 近200位采购与供应链、数字技术领域 专家、学者及行业领军企业的实践者 将齐聚本届盛会 解读产业政策落地 聚焦采购与供应链数字化创新发展态势 探讨AI、大数据在企业…

聚观早报 | 小度推出DuerOS X;问界新M5开启预定

聚观早报每日整理最值得关注的行业重点事件,帮助大家及时了解最新行业动态,每日读报,就读聚观365资讯简报。 整理丨Cutie 4月18日消息 小度推出DuerOS X 问界新M5开启预定 库克访问印尼 方程豹产品矩阵正式发布 苹果折叠屏iPhone新专利…

实验室信息系统源码 saas模式java+.Net Core版开发的云LIS系统全套源码可二次开发有演示

实验室信息系统源码 saas模式java.Net Core版开发的云LIS系统全套源码可二次开发有演示 一、技术框架 技术架构:Asp.NET CORE 3.1 MVC SQLserver Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架&am…

Python 全栈 Web 应用模板:成熟架构,急速开发 | 开源日报 No.223

tiangolo/full-stack-fastapi-template Stars: 15.6k License: MIT full-stack-fastapi-template 是一个现代化的全栈 Web 应用模板。 使用 FastAPI 构建 Python 后端 API。使用 SQLModel 进行 Python SQL 数据库交互(ORM)。Pydantic 用于数据验证和设…

JavaSE——常用API进阶二(5/8)-JDK 8新增的时间API,LocalDate、LocalTime、LocalDateTime

目录 JDK 8新增的时间API LocalDate、LocalTime、LocalDateTime 获取对象的方案 案例演示 ​编辑 LocalDateTime的不同 常用API总结 为什么要学JDK 8 新增的时间? JDK 8之前传统的时间API 设计不合理,使用不方便,很多都被淘汰了。都…

Android 12 如何加载 native 原生库

在 Android 7.0 及更高版本中,系统库与应用库是分开的。 图1. 原生库的命名空间 原生库的命名空间可防止应用使用私有平台的原生 API(例如使用 OpenSSL)。该命名空间还可以避免应用意外使用平台库(而非它们自己的库)的…

openlayers 入门教程(七):Interactions 篇

目录 ​一、交互功能 二、defaults默认设置 三、使用交互功能 四、简单示例展示 1、draw 示例 2、 modify 示例 3、 select 示例 4、 Drag-and-Drop 示例 5、 DragPan示例 6、 DragZoom 示例 五、Openlayers 入门教程 -系列文章列表 Interaction是用来控制地图的&am…

STM32H7定时器TIM1-TIM17中断、PWM实现

STM32H7定时器TIM1-TIM17中断、PWM实现 高级定时器硬件框图定时器模式时基输出PWM定时器输入捕获 TIM1-TIM17的中断配置TIM1-TIM17的PWM输出 STM32H7 支持的定时器有点多,要简单的区分下。STM32H7 支持 TIM1-TIM8,TIM12-TIM17 共14 个定时器,…

Java | Leetcode Java题解之第36题有效的数独

题目&#xff1a; 题解&#xff1a; class Solution {public boolean isValidSudoku(char[][] board) {int[][] rows new int[9][9];int[][] columns new int[9][9];int[][][] subboxes new int[3][3][9];for (int i 0; i < 9; i) {for (int j 0; j < 9; j) {char …

ThreadLocal 原理及源码详解

什么是ThreadLocal&#xff1f; ThreadLocal 是一种提供线程本地变量&#xff08;也称为线程局部变量&#xff09;的类&#xff0c;这种变量确保了在不同的线程中访问同一个 ThreadLocal 变量时&#xff0c;每个线程会有一个该变量的私有副本&#xff0c;即使多个线程修改了相…

MATLAB环境下基于同步压缩变换重分配算子的瞬时频率估计

瞬时频率是表征非平稳信号特征的重要物理量&#xff0c;已经被广泛应用于桥梁振动检测、地震勘测、机械、电力系统、雷达、通信、医学等各个方面。瞬时频率的概念最早由Carson提出&#xff0c;后来&#xff0c;Gabor提出解析信号的定义&#xff0c;为瞬时频率的研究提供了新的方…

「不羁联盟/XDefiant」4月20号开启服务器测试,游戏预下载安装教程

XDefiant》开启Alpha测试&#xff0c;这是一款免费游玩的快节奏 FPS 竞技游戏&#xff0c;可选择特色阵营&#xff0c;搭配个性化的装备&#xff0c;体验 6v6 对抗或是线性游戏模式。高品质射击竞技端游XDefiant以6v6双边对抗为核心&#xff0c;对局模式分为区域与线性两大类&a…

【Spring】-编程式事务和声明式事务

spring中控制事务的方式有两种&#xff1a;编程式事务和声明式事务&#xff0c;今天我以两种事务出发&#xff0c;对spring中实现事务的EnableTransactionManagement和Transaction两个注解的底层原理进行讨论。 一、编程式事务 什么是编程式事务&#xff1f; 硬编码的方式实现…

数据结构-栈和队列刷题集(长期更新)

文章目录 万能计算器的实现以及源码分析1. leetcode 150 逆波兰表达式求值 万能计算器的实现以及源码分析 /*** 我们尝试写一个完整版的计算器,由于计算机不能很好的识别括号,所以一般要转换为逆波兰表达式求解* 思路解析 :* 1. 输入一个 中缀表达式* 2. 中缀表达式转化为list…

鸡汤笔记-致自己

《你只是看起来很努力》李尚龙 我们看起来每天熬夜&#xff0c;却只是拿着手机点了无数个赞&#xff1b;看起来在图书馆坐了一天&#xff0c;却真的只是坐了一天&#xff1b;看起来买了很多书&#xff0c;只不过晒了个朋友圈&#xff1b;看起来每天很晚地离开办公室&am…

聊聊go语言中的内存填充

写在文章开头 我们都知道数据加载到CPU缓存中可以提升执行性能&#xff0c;所以为了保证每一个结构体中的成员能够完整的被单个CPU核心加载以避免缓存一致性问题而提出内存对齐&#xff0c;这篇文章笔者会从go语言的角度来讨论这个优化机制。 Hi&#xff0c;我是 sharkChili &…

基于Springboot+Vue的Java项目-网上点餐系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

杀鸡焉用牛刀,用unity3D开发数字孪生是大材小用吗?

"杀鸡焉用牛刀"这句话的意思是指使用过于强大或不适合的工具来完成一个简单的任务。而用Unity3D开发数字孪生并不一定是大材小用。 Unity3D是一款功能强大的游戏开发引擎&#xff0c;它可以用于开发各种类型的游戏和交互应用程序。数字孪生是一种基于现实世界对象的虚…

网络靶场实战-PE 自注入

默认的 Windows API 函数&#xff08;LoadLibrary、LoadLibraryEx&#xff09;只能加载文件系统中的外部库&#xff0c;无法直接从内存中加载 DLL&#xff0c;并且无法正确地加载 EXE。有时候&#xff0c;确实需要这种功能&#xff08;例如&#xff0c;不想分发大量文件或者想增…