面向对象-----继承

news2025/1/17 3:10:57

前面向大家介绍了面向对象中的封装性,今天再来向大家介绍面向对象的继承和多态的两大特性。

1.继承

1.1 为什么需要继承?

在java语言中,我们用类来描述世间万物,虽然万物非常复杂,但总有一些共同点,如果将这些共同点抽取出来,便能更好的提高我们写代码的效率。所以在面向对象的语言中提出了继承的概念,用来抽取事物的共性,实现代码的复用。

1.2 继承的概念

继承机制:在面向对象程序设计中,继承可以让程序员实现代码的复用,也可以让程序员在原有类(父类、基类、超累)的基础上进行属性和供能的扩增,从而产生出新的类,这些新的类被称为派生类,同时也被称为子类。继承实现的主要功能为抽取共性,实现代码的复用。

1.3 继承的语法

在Java中如果要用到继承来表示类之间的继承关系,我们要用到extend关键字。

语法格式:

修饰符 class 子类名 extends 父类名{

}

 接下来我们来举一个例子。

以猫和狗为例

我们知道猫和狗有一些共同点,如名字,年龄,颜色,这些都是动物的共性。我们就可以将这些共同点抽取出来,放在一个类中,这个类就是父类。

接着我们分别将猫和狗分别设置为两个类,分别继承父类。然后分别在猫和狗的类中各自实现自己的功能与属性,如猫要吃猫粮,狗要吃狗粮。

代码实现

父类

public class Animal {
    //共性的抽取
    public String name;
    public int age;
    public String color;
}

狗类

public class Dog extends Animal{
    public void eat(){
        System.out.println(this.name+"在吃狗粮");
    }
}

猫类

public class Cat extends Animal{
    public void eat(){
        System.out.println(this.name+"在吃猫粮");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Dog dog=new Dog();
        System.out.println(dog.name = "旺财");
        System.out.println(dog.age = 6);
        System.out.println(dog.color = "black");
        dog.eat();
        Cat cat=new Cat();
        System.out.println(cat.name = "咪咪");
        System.out.println(cat.age = 7);
        System.out.println(cat.color = "white");
        cat.eat();
    }
}

通过测试类我们发现,即使我们没有在Dog类和Cat类中定义了name、age和color的成员变量,但由于都继承了Animal这个父类,所以我们通过Dog类和Cat类创建的对象也可以使用name、age和color这三个成员变量。

运行代码

4dab512e52dd48eb8c92f8518866813e.png

小总结

父类的成员方法和成员变量会被继承到子类中。

 2. 访问成员变量和成员方法

在继承这个机制中,成员变量和成员的方法遵循就近原则。在子类的方法中或者通过子类的对象去访问成员方法或者成员变量时,优先在子类中寻找使用。如果在子类当中没有找到对应的成员变量或者成员方法,在去父类中寻找使用,如果父类和子类中都没有找到,则编译会报错。

2.1 访问成员变量

父类的成员变量和子类成员变量不同名

优先到子类中找对应的成员变量,如果在子类中没找到,再去父类中找,都没找到,就会报错。

class Base{
    public int a=10;
}
class Derive extends Base{
    public int b=9;
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
        System.out.println(derive.b);
    }
}

83ed31219520476486a7ca0580e27134.png

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

一样遵循就近原则

class Base{
    public int a=10;
}
class Derive extends Base{
    public int a=9;
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
        System.out.println(derive.a);
        System.out.println(derive.a);
    }
}

2737b9573e3147d387f0de4a86590eb3.png

2.2 访问成员方法

父类的成员方法与子类的成员方法不同名字

遵循就近原则

class Base{
    public int a=10;
    public void Base(){
        System.out.println("Base()被调用......");
    }
}
class Derive extends Base{
    public int a=9;
    public void Derive(){
        System.out.println("Derive()被调用。。。。。。");
    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
        derive.Derive();
        derive.Base();
    }
}

1c0a8e522f694391abdad49a8e203791.png

 父类的成员方法与子类的成员方法同名

这里涉及到了方法的重写和动态绑定,后面讲解多态的时候会介绍,这里也先理解为就近原则

class Base{
    public void Test(){
        System.out.println("父类的Test()......被调用");
    }
}
class Derive extends Base{
    public void Test(){
        System.out.println("子类的Test()......被调用");
    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
        derive.Test();
    }
}

5b939fa4a5cd477485f7de54f44a097c.png

注意事项:

如果我们通过子类创建的对象去访问父类和子类同名的成员方法时,但是由于父类和子类同名的成员方法的参数列表不同(重载),会根据调用方法时的参数去子类和父类中去寻找合适的成员方法。

class Base{
    public void Test2(int a){
        System.out.println("父类Test2(int a)被调用......");
    }
    public void Test1(){
        System.out.println("父类的Test1()被调用......");
    }
}
class Derive extends Base{
    public void Test2(){
        System.out.println("子类的Test2()被调用......");
    }
    public void Test1(int a){
        System.out.println("子类的Test1(int a)被调用......");
    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
        int a=10;
        derive.Test1(a);  //调用子类的Test1(int a);
        derive.Test1();   //调用父类的Test1();
        derive.Test2(a);  //调用父类的Test2(int a);
        derive.Test2();   //调用子类的Test2();
    }
}

运行代码

220fdc06a2d243819d0733807a7cf771.png

3.super关键字

如果我们要想在子类中直接去访问父类的去访问符类的成员变量和成员方法,要如何操作呢?

答案就是super关键字。通过super关键字我们就能直接在子类中去访问父类的成员变量和成员方法。

class Base{
    int a=10;
    public void Test2(int a){
        System.out.println("父类Test2(int a)被调用......");
    }
    public void Test1(){
        System.out.println("父类的Test1()被调用......");
    }
}
class Derive extends Base{
    int a=9;
    public void Test2(){
        System.out.println("子类的Test2()被调用......");
    }
    public void Test1(int a){
        System.out.println("子类的Test1(int a)被调用......");
    }
    public void Test(){
        System.out.println(super.a);//调用父类的a
        super.Test2(a);//调用父类的Test2(int a)
        super.Test1();//调用父类的Test1()

    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
       derive.Test();
    }
}

 

cca6a8b7aa174b738e5391e9dd238e06.png

注意事项:

super关键字只能在非静态的函数(不被static修饰的函数)中使用。

 4.子类构造方法

常言道,先有爸爸再有儿子,所以在调用子类的构造方法时,我们要在子类的构造方法中用super关键字去调用父类的构造方法,否则编译器会报错

class Base{
    public Base(){
        System.out.println("调用了父类的构造方法");
    }
}
class Derive extends Base{
    public Derive(){
        super();
        System.out.println("子类的构造方法");
    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive();
    }
}

 

b563b39f124546719b9f77dd88214bae.png

如果父类和子类的构造方法都构成重载,我们会跟据创建对象时传的参数列表,进入子类中对应的构造函数,然后根据子类的构造函数中的super(......) 括号里的参数列表去调用父类中合适的构造方法。

class Base{
    public int a;
    public int b;
    public Base(){
        System.out.println("调用了父类的构造方法");
    }
    public Base(int a,int b){
        this.a=a;
        this.b=b;
        System.out.println("调用了父类中的有参构造方法");
    }
}
class Derive extends Base{
    public Derive(){
        super();
        System.out.println("调用了子类的构造方法");
    }
    public Derive(int a,int b){
        super(a,b);
        System.out.println("调用了子类的有参构造方法");
    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive=new Derive(10,20);
        System.out.println("==================");
        Derive derive1=new Derive();
    }
}

5deaf4e6fbe34a8aa417946f2823dbaa.png

 

运行代码

 

9872a3eff9ee4a57ad8bfd8e2e6d61c9.png

注意事项:

1.如果我们没有在子类的构造方法中去调用父类的构造函数,编译器会自动默认子类的构造方法中调用了super()。

class Base{
    public int a;
    public int b;
    public Base(){
        System.out.println("调用了父类的构造方法");
    }
}
class Derive extends Base{
    public Derive(){
        //super();  没有写,但会默认有
        System.out.println("调用了子类的构造方法");
    }
}
public class Test {
    public static void main(String[] args) {
        Derive derive1=new Derive();
    }
}

d297ffb55c134e73869ca1316ec991a4.png

2.super(......)关键字必须位于子类的构造函数的第一行。

3.super(......)只能在子类的构造函数中出现一次,并且不能和this(......)同时出现。 

小总结----super与this的异同点

相同点:

1.super和this都是Java中的关键字。

2.都只能再非静态方法中使用,只能用来访问非静态成员变量和成员方法。

3.在构造方法中使用this和super关键字调用构造方法时,只能位于第一行,并且this(...)和super(...)不能同时存在

不同点:

1.this关键字当前对象的引用,当前对象即本类实例化的对象,super关键字是子类从父类继承的属性和方法的引用。

如下图:

11cfdef2f2c546abb6e382b0ec9ea959.jpeg

2.this关键字使用来调用本类的成员方法和成员变量,super关键字是用来调用父类的成员变量和成员方法。

3.在继承机制的构造方法中,一定存在super调用的构造方法,如果没写,编译器也会默认有。但是如果this(...)没写,那就没有。

5.再谈初始化

在Java中,代码块运行的顺序为静态代码块到实例化代码块再到构造代码块。

那父类和子类这3种代码块的运行先后是怎么样的呢?

我们直接来看代码

class Father{
    public int age;
    public Father(){
        System.out.println("父类的构造代码块");
    }
    {
        System.out.println("父类实例化代码块");
    }
    static {
        System.out.println("父类的静态代码块");
    }
}
class Son extends Father{
    public Son(){
        super();
        System.out.println("子类的构造代码块");
    }
    {
        System.out.println("子类的实例化代码块");
    }
    static {
        System.out.println("子类的静态代码块");
    }
}
public class Test {
    public static void main(String[] args) {
        Son son1=new Son();
        System.out.println("=======");
        Son Son2=new Son();
    }
}

运行代码

b053bcedb7c34b3fb5fb0ba4de683f73.png

得出结论:

1.先执行父类的静态代码块,再执行子类的静态代码块,并且只执行一次,因为静态代码块是再类的加载成功时运行的,而类的加载只进行一次。

2.执行完静态代码块,再先后执行父类的实例化代码块,父类的构造代码块,最后再分别先后执行子类的实例化代码块和构造代码块。

6.继承方式

再Java中,我们支持单继承,多层继承和不同的多个类继同时承一个类。但是不能一个类同时继承多个类。

如图

45941c1441fc4d8ab16a377b7ce8bf55.jpeg

7.final关键字

1.final修饰的成员变量无法被修改

2.final修饰的类无法被继承

3.final修饰的方法无法被重写 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

Java NIO 基础

Java NIO 基础 1. NIO 介绍2. NIO 三大组件2.1 Channel2.1.1 常见的 Channel2.1.2 常用方法 2.2 Buffer2.2.1 常见的 Buffer2.2.2 重要属性2.2.3 常用方法 2.3 Selector2.3.1 四种事件类型 1. NIO 介绍 NIO(non-blocking io):非阻塞IO&#…

2024.5.20 学习记录

1、react 原理(jsx的本质、事件机制原理、setState和batch Update、组件渲染更新和diff算法、fiber) 2、代码随想录贪心刷题

【C++初阶】--- C++入门(上)

目录 一、C的背景及简要介绍1.1 什么是C1.2 C发展史1.3 C的重要性 二、C关键字三、命名空间2.1 命名空间定义2.2 命名空间使用 四、C输入 & 输出 一、C的背景及简要介绍 1.1 什么是C C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题&…

GPT-4o 引领人机交互新风向的向量数据库Milvus Cloud 成本

成本 AIGC 时代对于冷热储存的呼唤 成本一直是向量数据库获得更广泛使用的最大阻碍之一,这个成本来自两点: 储存,绝大多数向量数据库为了保证低延迟,需要把数据全量缓存到内存或者本地磁盘。在这个动辄百亿量级的AI 时代,意味着几十上百 TB 的资源消耗。 计算,数据需…

OCR版面分析-- PaddleOCR(python 文档解析提取)

1. 创建新的conda环境 # 在命令行输入以下命令,创建名为paddle_env的环境 # 此处为加速下载,使用清华源 conda create --name paddle_env python3.8 --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ # 这是一行命令2. 激活刚创建…

全球视频会议软件巨头Zoom,率先引入后量子端到端加密

5月21日,Zoom Video Communications公司宣布,后量子端到端加密(E2EE)现已面向全球推出,适用于Zoom Workplace。目前,Zoom已将该功能加入Zoom Meetings,稍后将扩展至Zoom Phone和Zoom Rooms。 图…

数据中心大型AI模型网络需求

数据中心大型AI模型网络需求 随着Transformer的崛起和2023年ChatGPT的大规模应用,业界逐渐形成共识:遵循一定的规模效应原则,增加模型参数量能够显著提升模型性能。特别是在参数数量级跃升至数百亿乃至更高时,大型AI模型在语言理…

20232803 2023-2024-2 《网络攻防实践》实践十报告

目录 1. 实践内容1.1 SEED SQL注入攻击与防御实验1.2 SEED XSS跨站脚本攻击实验(Elgg) 2. 实践过程2.1 SEED SQL注入攻击与防御实验2.1.1 熟悉SQL语句2.1.2 对SELECT语句的SQL注入攻击2.1.3 对UPDATE语句的SQL注入攻击2.1.4 SQL对抗 2.2 SEED XSS跨站脚本攻击实验(Elgg)2.2.1 发…

超前预热|博睿数据将应邀出席双态IT用户大会,分享《构建云原生时代的一体化智能可观测性》

5月31日,第十二届双态IT用户大会将于成都盛大开幕,此次大会由DCMG和双态IT论坛联合主办,聚焦“信创时代的组织级云原生能力建设”和“组织级云原生运维能力建设”两大会议主题,旨在推动双态IT落地与创新,为企业数字化转…

Android AV World 序

序 做Android系统开发很久了,基于高通和MTK硬件平台,使用Android10量产了一些车载项目。由于功能模块属于系统底层支撑,类似于docker,涉及到音视频的处理,及Display Graphics的一些处理,需要调试解决显示花…

【map、set】C++用红黑树来封装map、set容器

🎉博主首页: 有趣的中国人 🎉专栏首页: C进阶 🎉其它专栏: C初阶 | Linux | 初阶数据结构 小伙伴们大家好,本片文章将会讲解map和set之用红黑树来封装map、set容器的相关内容。 如果看到最后您…

Star CCM+中边界模式交界面与接触模式交界面的生成差异

前言 前文已经介绍过将零部件分配至区域的方法与步骤,根据接触创建边界模式交界面与根据接触创建接触模式交界面两种交界面模式对初始化时间的影响。两者除了对初始化时间的影响差异外,其生成的边界面也是存在差异的。本文将对两者的生成的交界面的差异…

【BUG】Edge|联想电脑 Bing 搜索报错“Ref A: 乱码、 Ref B:乱码、Ref C: 日期” 的解决办法

文章目录 省流版前言解决办法 详细解释版前言问题描述与排查过程解决办法与总结 省流版 前言 我也不清楚咋滴了,Bing 搜索突然偶尔报错: 换了代理关了插件都报错。 参考: 我在用bing搜索时出现了如下代码,导致bing无法使用&am…

只需5步帮你有效监控员工上网记录

监控员工上网记录是企业实施网络管理、确保工作效率、保护信息安全和遵循合规要求的一种常见做法。这一过程通常涉及使用专业的上网行为管理软件,如安企神、域智盾等,这些软件具备多样化的功能来帮助企业管理者有效地监控和控制员工的上网行为。以下是监…

【Java基础】IO流(4) —— 转换流、打印流

【Java基础】IO流(1) —— 简介 【Java基础】IO流(2) —— 字符流 【Java基础】IO流(3) —— 字节流 【Java基础】IO流(4) —— 转换流、打印流 【Java基础】IO流(5) —— 序列流、内存流 【Java基础】IO流(6) —— 随机访问文件流、数据流 转换流 InputStreamReader 是字节输…

DataGrip测试连接时出现报错解决方案

(一)报错情况描述: DBMS: MySQL (无版本) 区分大小写: 普通形式mixed,分隔形式exact Connection refused: connect. (二)解决方案: 1、 首先打开命令指示符,选择以管理员身份运行。…

在排序数组中查找元素的第一个位置和最后一个位置 ---- 二分查找

题目链接 题目: 分析: 如果我们查找元素的第一个位置, 随便假设一个位置为x, 如果这个数>target, 说明 [left,x-1] 是我们要找的位置, [x,right] 可以舍去, 让right mid-1,如果这个数target, 说明[left,x] 是我们要找的位置, [x1,right] 可以舍去, 让right mid,(因为当…

做抖音小店不想赔钱,这几个功能必须关掉!

大家好,我是电商糖果 有很多新手刚开始运营店铺,对店铺的有些设置并不了解。 前期将所有的设置都打开了,等到店铺出单之后,才发现麻烦一大堆。 这里糖果就跟自己开店的经验,劝告各位新手朋友,这几个功能…

数据仓库实验四:聚类分析实验

目录 一、实验目的二、实验内容和要求三、实验步骤1、建立数据表2、建立数据源视图3、建立挖掘结构Student.dmm4、部署项目并浏览结果5、挖掘模型预测 四、实验结果分析五、实验总结体会 一、实验目的 通过本实验,进一步理解基于划分的、基于层次的、基于密度的聚类…