面向对象-----继承

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

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.mfbz.cn/a/633222.html

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

相关文章

深入Django项目实战与最佳实践

title: 深入Django项目实战与最佳实践 date: 2024/5/19 21:41:38 updated: 2024/5/19 21:41:38 categories: 后端开发 tags: Django 基础项目实战最佳实践数据库配置静态文件部署高级特性 第一章:Django项目架构与设计原则 Django框架概述 Django是一个高级的P…

linux的用户管理

新建用户:1.useradd 2.passwd 完成的操作: (1)/etc/passwd添加一行 (2)/etc/shadow添加一行 (3)/etc/group添加一行 (4)创建用户家目录 (5)创建用户邮件文件 例:创建用户jerry,要求: uid:777&am…

文心一言指令解析

1、介绍 文心一言是一款灵感启发类的产品,它以简洁而深刻的文字表达来激发读者的思考和感悟。该产品通过每天提供一句精选的短语,让用户在繁忙的生活中停下脚步,思考人生和内心的真实需求。 每一句文心一言都经过精心挑选,它们通…

苹果MacOS系统使用微软远程桌面连接Windows电脑桌面详细步骤

文章目录 前言1. 测试本地局域网内远程控制1.1 Windows打开远程桌面1.2 局域网远程控制windows 2. 测试Mac公网远程控制windows2.1 在windows电脑上安装cpolar2.2 Mac公网远程windows 3. 配置公网固定TCP地址 前言 日常工作生活中,有时候会涉及到不同设备不同操作系…

【SpringBoot】整合百度文字识别

流程图 一、前期准备 1.1 打开百度智能云官网找到管理中心创建应用 全选文字识别 1.2 保存好AppId、API Key和Secret Key 1.3 找到通用场景文字识别,立即使用 1.4 根据自己需要,选择要开通的项目 二、代码编写 以通用文字识别(高精度版&am…

2024-5-4-从0到1手写配置中心Config之基于h2的config-server

添加依赖 新建的web工程中添加h2的依赖 添加h2的配置 设置数据源和密码设置初始化sql语句打开h2的控制台 初始化语句创建一个config表,保存服务配置信息。 完成CRUD接口 controller类 mapper接口 测试 在web控制台可以看到sql已经初始化完成,crud接口…

如何*永久*禁用edge打开PDF文件?

要永久禁用Microsoft Edge打开PDF文件,您可以按照以下步骤进行操作: 打开文件资源管理器并找到任意一个PDF文件。 右键单击该文件并选择“属性”。 在“属性”对话框中,单击“更改”按钮旁边的“打开方式”。 在“打开方式”对话框中&…

Leetcode - 398周赛

目录 一,3151. 特殊数组 I 二,3152. 特殊数组 II 三,3153. 所有数对中数位不同之和 四,3154. 到达第 K 级台阶的方案数 一,3151. 特殊数组 I 本题就是判断一个数组是否是奇偶相间的,如果是,…

【Floodfill算法】dfs或者bfs解决floodfill算法

1.图像渲染 图像渲染 dfs解决代码&#xff1a; class Solution { public:int dx[4] {0, 0, -1, 1};int dy[4] {-1, 1, 0, 0};int m, n;int prev;vector<vector<int>> ret;vector<vector<int>> floodFill(vector<vector<int>>& ima…

Java并发: 锁和同步

在Java并发: 面临的挑战那一篇中我们提到锁和同步是实现并发安全(可见性/原子性)的方法之一。这一章我们来讲讲Java中的锁和同步的各种工具&#xff0c;包括: LockSupportAbstractQueuedSynchronizerJava内置的锁实现 1. LockSupport LockSupport是基于Unsafe的park/unpark实…

linux 查看java线程与linux线程关系

linux 查看占用cpu高的 java 线程 linux 排查cpu占用100%故障 ##java程序 import java.util.Scanner; public class JavaThreadIDName {public static void main(String[] args) {Thread t Thread.currentThread();t.setName("laoyoutiao");System.out.println(&…

golang创建式设计模式---工厂模式

创建式设计模式—工厂模式 目录导航 创建式设计模式---工厂模式1)什么是工厂模式2)使用场景3)实现方式4)实践案例5)优缺点分析 1)什么是工厂模式 工厂模式(Factory Method Pattern)是一种设计模式&#xff0c;旨在创建对象时&#xff0c;将对象的创建与使用进行分离。通过定义…

以太坊(2)——共识机制与挖矿算法

共识机制 ETH采用的是基于GHOST协议的共识机制 "GHOST"&#xff08;Greedy Heaviest-Observed Sub-Tree&#xff09;共识机制&#xff0c;它是以太坊使用的一种改进的区块链共识算法。GHOST共识机制旨在提高链的安全性和效率&#xff0c;通过考虑非主链区块的贡献&…

kubectl详解

文章目录 kubectl详解一、陈述式管理1、陈述式资源管理方法2、k8s相关信息查看2.1 查看版本信息2.1.1 查看资源对象简写2.1.2 查看集群信息2.1.3 配置kubectl自动补全2.1.4 查看日志 2.2 基本信息查看2.2.1 查看集群状态2.2.2 查看命名空间 2.3 命名空间操作2.3.1 查看default命…

CDN用户平台安装说明

CDN用户平台安装说明 登录管理员系统 在”系统设置” – “高级设置” – “用户节点”中点击”添加节点” 如果所示&#xff1a; 节点名称 - 可以任意填写 进程监听端口 - 启动用户节点后&#xff0c;进程所监听的端口&#xff0c;通常是HTTP 80或者HTTPS 443&#xff0c;…

html 段落与排版标记 Web前端开发技术、详细文章(例如)

段落与排版标记 网页的外观是否美观&#xff0c;很大程度上取决于其排版。在页面中出现大段的文字&#xff0c;通常采用分段进行规划&#xff0c;对换行也有极其严格的划分。本节从段落的细节设置入手&#xff0c;利用段落与排版标记自如地处理大段的文字。 段落p标记 在HTM…

Spring Cloud Gateway 网关

一. 什么是网关&#xff08;Gateway&#xff09; 网关就是一个网络连接到另一个网络的关口。 在同一个项目或某一层级中&#xff0c;存在相似或重复的东西&#xff0c;我们就可以将这些相似重复的内容统一提取出来&#xff0c;向前或向后抽象成单独的一层。这个抽象的过程就是…

Linux磁盘高级操作

RAID RAID存储系统是一种数据存储虚拟化技术&#xff0c;它将多个物理磁盘驱动器组合成一个或多个逻辑单元&#xff0c;以提供数据冗余和/或提高性能。 1. RAID 0 无奇偶校验与冗余&#xff08;磁盘容错&#xff09;的条带存储&#xff08;带区卷/条带卷&#xff09; 由两块…

Linux-文件或目录权限

在使用 ll 时&#xff0c;可以查看文件夹内容的详细信息&#xff0c;信息的第1位表示类型&#xff0c;具体信息如下&#xff1a; 类型说明-普通文件d文件夹b块设备文件c字符设备文件p管道文件s套接口文件 第2-10位表示权限&#xff0c; 举例&#xff1a;rwxr-xr-x 类型说明r…

简单快捷的图片格式转换工具:认识webp2jpg-online

经常写博客或记笔记的朋友们可能会碰到图床不支持的图片格式或图片太大需要压缩的情况。通常&#xff0c;我们会在浏览器中搜索在线图片格式转换器&#xff0c;但这些转换器往往伴有烦人的广告或要求登录&#xff0c;并且支持的转换格式有限。最近&#xff0c;我在浏览 GitHub …