Java的继承到底是怎么回事?看这篇让你明明白白

news2025/1/16 5:17:12

一. 引言

在学习面向对象后,我们就可以使用类来描述对象共有的特征(属性)和行为举止(方法),如果我们用类来描述猫、狗和企鹅,可以进行如下编码:

public class Cat {
    
    private String name;//名字
    
    private int age;//年龄
    
    private String strain; //品种
    //省略getter和setter方法
}

public class Dog {
    
    private String name;//名字
    
    private int age;//年龄
    
    private String strain; //品种
    //省略getter和setter方法
}

public class Penguin{
    
    private String name;//名字
    
    private int age;//年龄
    
    private String sex; //性别
    //省略getter和setter方法
}
复制代码

你会发现,在上面的3个类中存在大量的重复代码,那么该如何优化呢?这里我们可以使用继承来优化

二. 继承

1. 什么是继承

当我们编写的多个类中存在相同的属性或方法时,可以将这些类中相同的属性和方法抽取到一个新的类中,然后再让这些类继承于这个新类,就可以重用新类中的属性和方法,这些类称为子类,这个新类称为父类,这就是Java中的继承。

2. 如何使用继承

我们将上面的案例抽取出一个父类如下:

public class Animal {
    
    String name;//名字
    
    int age;//年龄
}
复制代码

接下来只需要继承于这个父类即可。在Java中,继承使用extends关键字 来表示,上面的三个类修改如下:

public class Cat extends Animal{//猫类继承于动物类
    
    private String strain; //品种
     //省略getter和setter方法
}

public class Dog extends Animal{//狗类继承于动物类
    
    private String strain; //品种
     //省略getter和setter方法
}

public class Penguin extends Animal{//企鹅类继承于动物类
    
    private String sex; //性别
     //省略getter和setter方法
}
复制代码

接下来我们可以编写一个测试案例。

public class AnimalTest {

    public static void main(String[] args) {
        Cat c = new Cat();
        c.setName("苗苗");
        c.setAge(1);
        c.setStrain("咖啡猫");
    }
}
复制代码

我们发现,在 Cat 类中并没有 setNamesetAge 方法,但却可以直接使用这些方法,说明这两个方法都是从父类中继承过来的,其他两个类也一样。

3. 子类能够继承父类的哪些属性和方法

3.1 API文档

在官方文档中有这样的描述:

A subclass inherits all of the public and protected members of its parent, no matter what package the subclass is in. If the subclass is in the same package as its parent, it also inherits the package-private members of the parent.

解释说明:

不论子类与父类是否在同一个包中,父类中使用 public 或者 protected 修饰的属性和方法,都能够被子类继承。如果子类和父类在同一个包中,那么子类还能继承受包保护的属性和方法(受包保护指的是没有使用访问修饰符的属性和方法)。

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

解释说明:

子类不会继承父类中定义的私有成员。但如果父类有提供使用 public 或者 protected 修饰的访问该字段的方法,这些方法也能在子类中被使用。

为了验证这些文档中的说法是否正确,接下来我们通过几个案例来进行验证。

3.2 案例一

public class Animal {
    
    private String name;//修改访问修饰符为private
    
    int age;//年龄
    //省略getter和setter方法
}

public class Cat extends Animal {

    private String strain;

    public String getStrain() {
        return strain;
    }

    public void setStrain(String strain) {
        this.strain = strain;
    }

    public void show(){ //添加一个show方法,打印name和age属性
        System.out.println(name + age);
    }
}
复制代码

此时编译也出错,name 属性不能访问,但 age 属性可以。

该案例说明了父类中私有的属性不能被继承,但受包保护的属性可以被继承

3.3 案例二

package com.qf.oop; //给父类添加包名

public class Animal {
    
    private String name;//修改访问修饰符为private
    
    int age;//年龄
    //省略getter和setter方法
}

package com.qf.oop.sub; //给子类添加包名

import com.qf.oop.Animal;

public class Cat extends Animal {

    private String strain;

    public String getStrain() {
        return strain;
    }

    public void setStrain(String strain) {
        this.strain = strain;
    }

    public void show(){
        System.out.println(name + age);
    }
}
复制代码

此时编译也出错,nameage 属性都不能访问。

该案例说明了在不同的包中,子类不能继承父类中的私有属性和受包保护的属性。

3.4 案例三

package com.qf.oop;

public class Animal {

    public String name; //修改访问修饰符为public

    protected int age; //修改访问修饰符为protected
    
    //省略getter和setter方法
}


package com.qf.oop.sub;

import com.qf.oop.Animal;

public class Cat extends Animal {

    private String strain;

    public String getStrain() {
        return strain;
    }

    public void setStrain(String strain) {
        this.strain = strain;
    }

    public void show(){
        System.out.println(name + age);
    }
}
复制代码

此时编译正常。

该案例说明了在不同的包中,子类可以继承父类中公开的属性和受保护的属性 方法的继承与属性的继承规则一致。

三. 方法重写

1. 什么是方法重写

方法重写指的是在具有继承关系的子类中,如果存在一个成员方法,与父类中的成员方法有相同的签名和返回值类型,那么,这个方法就重写了父类中的成员方法,称为方法重写。

方法签名指的是方法名、参数类型和参数个数。

相同的方法签名指的是方法名、参数类型、参数个数和参数出现的位置均相同。

2. 为什么要使用方法重写

我们知道方法表示的是行为举止,子类继承父类,当然也可以继承父类的行为举止。但我们经常会遇到子类和父类做一件事情的方式不一样,也就是说,子类中的方法实现和父类中的方法实现存在差别。例如:动物会吃食物,但不同的动物吃的食物也不一样。 

public class Animal{
    
    public void eat(){
        System.out.println("动物吃食物");
    }
}

public class Cat extends Animal{
   
   public void eat(){
       System.out.println("猫吃鱼");
   }
}
复制代码

子类 Cat 中的 eat 方法与父类 Animal 中的 eat 方法具有相同的签名和返回值类型,这样的方法我们称其为重写了父类中eat 方法。

为了方便查看重写的方法,Java 提供了 @Override 注解来标识。这个注解仅仅就是一个标识,写与不写都不影响。

public class Cat extends Animal{

   @Override //重写的方法的一个标识
   public void eat(){
       System.out.println("猫吃鱼");
   }
}
复制代码

3. 如何使用方法重写

现有这样一个场景:几何图形都有面积和周长,不同的几何图形,面积和周长的算法也不一样。矩形有长和宽,通过长和宽能够计算矩形的面积和周长;圆有半径,通过半径可以计算圆的面积和周长。请使用继承相关的知识完成程序设计。

package com.qf.oop.shape;

/**
 * 几何图形
 */
public class Shape {
    /**
     * 计算周长
     * @return
     */
    public double calculatePerimeter(){
        return 0;
    }

    /**
     * 计算面积
     * @return
     */
    public double calculateArea(){
        return 0;
    }
}

package com.qf.oop.shape;

/**
 * 矩形
 */
public class Rectangle extends Shape {

    private int width;

    private int length;

    public Rectangle(int width, int length) {
        this.width = width;
        this.length = length;
    }

    @Override
    public double calculatePerimeter() {//重写计算周长的方法
        return (width + length) * 2;
    }

    @Override
    public double calculateArea() {//重写计算面积的方法
        return width * length;
    }
}

package com.qf.oop.shape;

/**
 * 圆
 */
public class Circle extends Shape{

    private int radius;

    public Circle(int radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {//重写计算面积的方法
        return Math.PI * radius * radius;
    }

    @Override
    public double calculatePerimeter() {//重写计算周长的方法
        return 2 * Math.PI * radius;
    }
}

package com.qf.oop.shape;

public class ShapeTest {

    public static void main(String[] args) {
        Shape s1 = new Rectangle(10, 9);
        System.out.println(s1.calculatePerimeter());
        System.out.println(s1.calculateArea());


        Shape s2 = new Circle(5);
        System.out.println(s2.calculatePerimeter());
        System.out.println(s2.calculateArea());
    }
}
复制代码

重写方法时访问修饰符的级别不能降低。

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

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

相关文章

操作系统,计算机网络,数据库刷题笔记11

操作系统,计算机网络,数据库刷题笔记11 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开的话,你就得学数据库,sql&#xf…

kubelet源码分析 syncLoopIteration(一) configCh

kubelet源码分析 syncLoopIteration syncLoopIteration里有四个chan管道。分别是configCh、plegCh、syncCh、housekeepingCh。这篇主要聊一下这四个管道的由来。 一、configCh configCh是通过list&watch的API SERVER获得的数据。然后在本地进行比对,推送到c…

Qt-Web混合开发-QtWebChannel实现Qt与Web通信交互-进阶功能(6)

Qt-Web混合开发-QtWebChannel实现Qt与Web通信交互-进阶功能🥬 文章目录Qt-Web混合开发-QtWebChannel实现Qt与Web通信交互-进阶功能🥬1、概述🌽2、实现效果🍆3、实现功能🍒4、关键代码🥝5、源代码&#x1f9…

Android基础学习(二十二)—— View的事件分发(1)

一、View的层级关系 二、View的事件分发机制 1、MotionEvent ——点击事件 点击事件用MotionEvent来表示 ACTION_DOWN:手指刚接触屏幕 ACTION_MOVE:手指在屏幕上移动 ACTION_UP:手指从屏幕上松开的一瞬间 点击事件的事件分发&#xff0…

OM6621系列国产M4F内核低功耗BLE5.1大内存SoC蓝牙芯片

目录OM6621系列简介OM6621P系列芯片特性应用领域OM6621系列简介 随着5G与物联网时代的到来,智慧城市、电动出行、智能家居、可穿戴设备等应用高速发展,低功耗蓝牙技术在近几年智能化浪潮中的地位也尤为重要。OM6621系列的开发即是为解决国内低功耗蓝牙应…

Linux安装docker 保姆级教程

一、docker介绍 Docker 是 2014 年最为火爆的技术之一,几乎所有的程序员都听说过它。Docker 是一种“轻量级”容器技术,它几乎动摇了传统虚拟化技术的地位,现在国内外已经有越来越多的公司开始逐步使用 Docker 来替换现有的虚拟化平台了。 二…

图为科技深圳人工智能产业协会重磅推出边缘计算机全新概念

人工智能作为提升区域竞争力的重要战略,全国各地都在推动发展,人工智能是未来科技创新发展的风向标,也是产业变革升级的关键驱动力,我国在《“十四五”数字经济发展规划》及《工业互联网创新发展行动计划(2021-2023年)》中&#x…

Linux基础(4)-进程管理

该文章主要为完成实训任务,详细实现过程及结果见【参考文章】 参考文章:https://howard2005.blog.csdn.net/article/details/127066383?spm1001.2014.3001.5502 文章目录一、查看进程1. 进程查看命令 - ps2. Liunx进程状态3. 观察进程变化命令 - top4. …

b站黑马的Vue快速入门案例代码——【axios+Vue】天知道(天气信息查询功能)

目录 目标效果: 更换的新接口接口文档: 天知道新的Get请求接口:http://ajax-api.itheima.net/api/weather html文件中注意因为接口更换,要修改原代码为如下红字部分: 重点原理: (1)v-on可以…

环形链表问题

文章目录环形链表问题1.环形链表题干思路延申问题总结2. 环形链表 II题干思路环形链表问题 环形链表就是一个链表没有结束的位置,链表的最后一个节点它会指向链表中的某一个节点形成一个环。 拿力扣的两到题目来看 1.环形链表 题干 给你一个链表的头节点 head …

JavaScript JSON解析

最近在uniapp中遇到了一个bug,排查后是json解析的问题。对uniapp开发比较熟悉的,应该会知道uni.navigateTo 这个API方法。这是官方提供用于跳转页面的方法。 有时候我们在跳转页面时会想传递一些参数,通常采用这样的方式 navigateTo(url, r…

oauth2.0--基础--6.1--SSO的实现原理

oauth2.0–基础–6.1–SSO的实现原理 1、什么是SSO 1.1、概念 在一个 多系统共存 的环境下,用户在一处登录后,就不用在其他系统中登录,就可以访问其他系统的资源。用户环境 浏览器:只能同一个浏览器,不会出现A浏览器…

zabbix部署【各模块超详细】

目录 安装zabbix 部署zabbix 配置zabbix 1. 修改语言 2. 监控linux端 3. 修改中文乱码 报警功能 报警音报警 邮件报警 脚本报警 邮件通知内容 图形模块 创建图形 创建聚合图形 percona mysql模板 nginx模板 克隆主机 网络发现 自动注册 主被动模式 🍁如果对你有帮助…

Handsontable复制列标题内容的功能

Handsontable复制列标题内容的功能 添加了通过使用3个新的上下文菜单选项复制列标题内容的功能:“使用标题复制”、“使用组标题复制”和“仅复制标题”。 添加了4个用于以编程方式复制列标题的新API方法:“copyCellsOnly()”、“copyWithColumnHeaders(…

vscode jupyter配置远程服务器开发

背景说明:本地vscode中使用jupyter编写本地python代码很方便,各种快捷键用的飞起。但是要做线上大数据分析时。在集群环境中搭建一个jupyter。使用网页端编写程序非常不习惯,所以想到能不能将线上的jupyter接口开出来,使用vscode远…

js-有关时间

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date 有关Date 返回格式 Sun Oct 10 2021 00:00:00 GMT0800 (中国标准时间) new Date() 无参数 获取当前时间new Date(value) 传入时间戳 传入一个时间戳 一个 Unix 时间戳(U…

JVM运行流程/运行时数据区

JVM运行流程 程序在执行之前先要把 java代码 转换成 字节码文件 (.class文件), JVM 首先需要把字节码通过一定的方式 类加载器 (ClassLoader) 把文件加载到内存中 运行时数据区 (Runtime Data Area) , 而字节码文件是 JVM 的一套指令集规范, 并不能直接交给底层操作系统去执行…

【大数据技术Hadoop+Spark】Hive数据仓库架构、优缺点、数据模型介绍(图文解释 超详细)

一、Hive简介 Hive起源于Facebook,Facebook公司有着大量的日志数据,而Hadoop是实现了MapReduce模式开源的分布式并行计算的框架,可轻松处理大规模数据。然而MapReduce程序对熟悉Java语言的工程师来说容易开发,但对于其他语言使用…

Anaconda为虚拟环境安装第三方库与Spyder等软件的方法

本文介绍在Anaconda中,为Python的虚拟环境安装第三方库与Spyder等配套软件的方法。 在文章Anaconda中Python虚拟环境的创建、使用与删除(https://blog.csdn.net/zhebushibiaoshifu/article/details/128334614)中,我们介绍了在Anac…

提前做好网络安全分析,运维真轻松(二)

背景 某汽车总部已部署NetInside流量分析系统,使用流量分析系统提供实时和历史原始流量。汽车配件电子图册系统是某汽车集团的重要业务系统。本次分析重点针对汽车配件电子图册系统进行预见性分析,以供安全取证、性能分析、网络质量监测以及深层网络分析…