3.java——继承及拓展(保姆级别教程,万字解析,匠心制作)

三.继承——节省了共有属性和方法的代码:语法 class Student extends Person

1.继承基础

1.继承首先是面向对象中非常强的一种机制,他首先可以复用代码(name ,age),让我们的获得了Person全部功能和属性,只需要为Student编写新增的功能。获得分数等等

  • java使用extends继承
  • 注意点:1.Person被称为基类,超类,父类。Student被称为子类,拓展类
    - 2.继承树
  • 定义Person类时,我们没有加上extends,在java中,没有写extends的类编译器会自动加上extends Object(对象)。所以,任何类,除了Object(对象),都会继承某个类
  • Preson和Student的继承树。
  • student ——> Person——>Object

- 3.java只允许class继承一个类,而C++可以继承很多类

  • java一个类clas只允许有且只有一个父类。只有特殊的Object特殊,它没有父类,他是所有继承的头部。

  • 在这里插入图片描述

  • 4.继承有个特点:java中所有类都是公有继承。拿到全部属性,但子类没有办法访问父类的private字段和方法。

  • 就是Student没有办法访问name和age, Student s1=new Student(); s1.name 报错error,这使得继承的作用大大削弱了
    - 这时我们需要用protect替换private了,这样可以访问了。所以,protect关键字可以把字段和方法全部控制在继承树内部。

class Student extends Person{
    public String hello()
    {
        return "hello, "+super.name;    
    }
}

2.super关键字和this关键字

**

(1)this.属性或方法,别的不多讲,就拿下面的这个吃苹果的经典故事展开。**

this在C++是指针,是类本身属性地址,java中是当前对象,this可以调用方法,属性,指向对象本身。
为什么eatApple()后面还可以接函数。apple可以用 . 操作符访问,因为人家是引用。但是eatApple方法的返回类型是是类名并且返回的是this相当于结果

public class Apple { 
int i = 0; 
Apple eatApple(){ 
i++; 
return this; 
} 
public static void main(String[] args) { 
Apple apple = new Apple(); 
apple.eatApple().eatApple(); 
} 
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)super关键字表示超类(父类)。有父亲构造才有孩子构造。先造出父亲再搞出你

先造出父亲再搞出你
在Java中,任何类的构造方法的第一行语句必须是调用父类的构造方法,是因为Java中的继承关系。当一个类继承自父类时,它会继承父类的属性和方法。在创建子类的对象时,必须先创建父类的对象,并进行初始化。通过调用父类的构造方法来完成父类对象的初始化,然后再对子类对象进行初始化。

子类引用父类字段时,可以用super.fieldName 领域名
实际上super.name, this name, name; 效果都是一样的。编译器会自动定位到父类的name字段
但有些情况必须用super,比如说:

 class Person 
{
 public static void main(String[] args)
 {
     Student s1=new Student("张三",12,67);      
 }   
}

class Person
{
    protected String name;
    protected int age;
    
     Person(String name;int age)
    {
        this.name=name;
        this.age= age;    
    }
}

class Student extends Person{
    protected int score;
    public Student(String name,int age,int score)
    {
        this.score =score;    
    }
} 

这里会报错,大意是在student的构造方法中,无法调用Person的构造方法。
这是因为在java中,任何class的构造方法中,(包括父类自己),第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super(无参);
所以,Student类的构造方法实际上必须在Student(){super() }加上 , super(有参数列表),必须加上参数列表,否则编译失败
‘错误写法没有形式参数’

class Student extends Person{
protected int score;
public Student(String name,int age,int score)
{
super();  //'自动调用父类的构造方法',Person(), 爸爸空手来了
this.socre =score;
}

'正确写法:'
class Student extends Person{
protected int score;
public Student(String name,int age,int score)
{
super(name ,age);//自动调用父类的构造方法Person(Sting,int),爸爸带刀来了
this.socre =score;
}

所以我们得出结论:如果父类没有默认构造方法,子类就必须显示调用super()并给出参数以便以编译器定位到父类的一个合适的构造方法。
这里顺便引出了结论:即子类不会继承父类的任何构造方法。子类默认的构造方法student()是编译器自动生成的,而不是继承的!!!

class Person

{
    private String name;
    private int age;
    
    public void setName(String name){}
    public String getName(){}
}

class Student extends Person{
    private int score;
    //Student获得了Person全部属性
    public void setScore(){}
    public void getScore(){}    
}

3.方法重写

方法的重写与重载虽然名字很类似,但是确是完全不一样的东西,重写描述是子类和父类的东西。重载必须在同一个类中。
不同点:重写必须全部方法签名和方法返回值类型一模一样。
@Override注解可写可不写!!!
在这里插入图片描述

4.阻止继承(难点):

关键字:final, sealed,static

final——最后的,固定的,不可以改变的,java中被誉为最终变量,最终方法,最终类——起到限制作用,俗称:铁公鸡——一毛不拔!!!一点也不给机会

最终变量(Final Variables): 在Java和C#中,使用"final"关键字声明的变量被称为最终变量或常量。
最终变量只能被赋值一次,一旦赋值后就不能再改变其值。
最终方法(Methods): 使用"final"关键字声明的方法不能被子类重写(override)。
这意味着如果你在一个父类中声明了一个方法为"final",那么在任何继承这个父类的子类中都不能有与之同名且参数列表相同的方法。
最终类(Final Classes): 当一个类被声明为"final"时,它不能被其他类继承。
这种限制可以用来保护类的设计和实现细节,防止被不适当或意外的修改。
总的来说,"final"关键字主要用于限制变量的可变性、方法的可重写性和类的可继承性,以增强代码的稳定性和可预测性。

sealed——有封条的,密封的,permits(允许)他们两一般同时用 ——封条其实可以被公家撕下来,也可以被无赖撕下来,permits就是屁股后面跟着的就是“特殊人群”。特殊人群特殊对待!!!

"sealed"关键字主要用于限制类或接口的继承性,以增强代码的控制力和可预测性。在某些情况下,它可以提高编译时的安全性和性能优化。
sealed class Shape permits Rect,Circle.。。。只允许跟着屁股后面的东西继承**
正常情况下,只要某个class没有final修饰符,那么任何类都可以从该class继承。!!
从Java 15开始,允许使用sealed修饰class,并通过permits明确写出能够从该class继承的子类名称。
例如,定义一个Shape类:

public sealed class Shape permits Rect, Circle, Triangle {
    '你的形状只允许能由于矩形圆形或者三角形继承'
}

上述Shape类就是一个sealed类,它只允许指定的3个类继承它。如果写:

public final class Rect extends Shape {...}

是没问题的,因为Rect出现在Shape的permits列表中。但是,如果定义一个Ellipse(椭圆)就会报错:

public final class Ellipse extends Shape {...}

// Compile error: class is not allowed to extend sealed class: Shape

原因是Ellipse并未出现在Shape的permits列表中。这种sealed类主要用于一些框架,防止继承被滥用。
sealed类在Java 15中目前是预览状态,要启用它,必须使用参数–enable-preview和–source 15。

1.sealed 密封的,不能被继承和重写
2.final 最后的,相当于C++中const不可以改 属性不可以改

static ——静态的,停止的 ,共享,在堆区开辟,static面前众生平等,堆区,这片区域很安静,来来往往方法和属性都必须带有static的标签老老实实。俗称:校长

静态成员变量(Static Member Variables): 静态变量是属于类的,而不是属于类的实例。
当类被加载时,静态变量就会被创建并分配内存。 所有类的实例共享同一个静态变量的值,也就是说,无论创建多少个对象,静态变量只有一份拷贝。
静态变量可以通过类名直接访问,不需要创建类的实例。

静态方法(Static Methods): 静态方法也是属于类的,而不是属于类的实例。
静态方法可以在没有类的实例的情况下被调用,同样通过类名直接访问。
静态方法不能访问非静态成员变量或非静态方法,因为它们在没有对象实例的情况下无法确定。

静态块(Static Blocks): 静态块是在类加载时执行的一段代码,通常用于初始化静态变量或者执行一些必要的设置操作。

静态内部类(Static Nested Classes): 静态内部类与非静态内部类的主要区别在于,它不需要对外部类的实例进行引用。
静态内部类可以直接通过外部类名加"."来访问。

静态导包(Static Import): 在Java中,静态导入允许程序员在不使用类名的情况下直接访问静态成员(如静态变量和静态方法)。
这可以减少代码中的冗余,并提高可读性。

总的来说,"static"关键字主要用于表示那些与类的实例无关,而是与类本身相关的属性和行为。这些静态元素在类的生命周期中有着特殊的地位和作用。

1.静态方法只能访问静态方法和属性。
2. 静态方法和静态成员变量可以直接有类名.静态方法(静态变量)的方式调用。并且还会引入方法重写 的概念!!!
3.静态方法可以被子类继承或重载,但是不可以被子类重写
4.如果子类中的静态方法和父类的静态方法名,参数,返回值类型都一样,这是被允许的,属于再次声明。

public class Test{
    public static int func(int num)
    {
        return num;    
    }
}

public test extends Test
{
    public int func(int num)
    {
        return num+2;    
    }
    //报错了func也必须是 static
}

static 除了修饰属性和方法外,还有的功能:
静态代码块
在这里插入图片描述

可用于类的初始化操作。进而提升程序的性能
由于静态代码块随着类的加载而执行,因此,很多时候会将只需要进行一次的初始化操作放在 static 代 码块中进行。**

5.向上转型,向下转型——人往高处走,水往低处流。

个人总结:类可以看成一种复杂的数据类型对象看成普通的引用变量,向上转型成功的原因更可能是因为对象拥有两种数据类型,
对象拥有两种数据类型他可以随心所欲了。因为数据类型决定了你可以拥有多大的活动(内存)空间,和你每走一步能走多远(运算,数据操作)

向上转型——铁定成功!!!

如果一个引用变量的类型是Student,那么它可以指向一个Student类型的实例:

Student s = new Student();

如果一个引用类型的变量是Person,那么它可以指向一个Person类型的实例:

Person p = new Person();

现在问题来了:如果Student是从Person继承下来的,那么,一个引用类型为Person的变量,能否指向Student类型的实例?

Person p = new Student(); // ???
多态性(如果加上方法重写就是有多态性,p有了两重身份,他本身数据类型就是Person 但是指向类型确是Student

测试一下就可以发现,这种指向是允许的!
这是因为Student继承自Person,因此,它拥有Person的全部功能。Person类型的变量,如果指向Student类型的实例,对它进行操作,是没有问题的!
这种把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)。
向上转型实际上是把一个子类型安全地变为更加抽象的父类型:

Student s = new Student();
Person p = s; // upcasting, ok
Object o1 = p; // upcasting, ok
Object o2 = s; // upcasting, ok

注意到继承树是Student > Person > Object,所以,可以把Student类型转型为Person,或者更高层次的Object。

向下转型——几乎失败!!!

和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。例如:

Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok
Student s2 = (Student) p2; // runtime error! ClassCastException!

如果测试上面的代码,可以发现:
Person类型p1实际指向Student实例,Person类型变量p2实际指向Person实例。在向下转型的时候,把p1转型为Student会成功,因为p1确实指向Student实例(P1有双重身份),把p2转型为Student会失败,因为p2的实际类型是Person,不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。(子类条件更为苛刻)
因此,向下转型很可能会失败。失败的时候,Java虚拟机会报ClassCastException。
为了避免向下转型出错,Java提供了instanceof操作符,可以先判断一个实例究竟是不是某种类型:

Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false

Student s = new Student();
System.out.println(s instanceof Person); // true
System.out.println(s instanceof Student); // true

Student n = null;
System.out.println(n instanceof Student); // false

instanceof实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为null,那么对任何instanceof的判断都为false。
利用instanceof,在向下转型前可以先判断:

Person p = new Student();
if (p instanceof Student) {
    // 只有判断成功才会向下转型:
    Student s = (Student) p; // 一定会成功
}

从Java 14开始,判断instanceof后,可以直接转型为指定变量,避免再次强制转型。例如,对于以下代码:

Object obj = "hello";
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.toUpperCase());
}

区分继承和组合——is和has逻辑性

在使用继承时,我们要注意逻辑一致性。
考察下面的Book类:

class Book {
    protected String name;
    public String getName() {...}
    public void setName(String name) {...}
}

这个Book类也有name字段,那么,我们能不能让Student继承自Book呢?

**class Student extends Book {
    protected int score;
}**

显然,语法上是合理的,但从逻辑上讲,这是不合理的,,Student不应该从Book继承,而应该从Person继承。
究其原因,是因为Student是Person的一种,它们是is关系,而Student并不是Book。实际上Student和Book的关系是has关系。
具有has关系不应该使用继承,而是使用组合,即Student可以持有一个Book实例:人是书的持有者,书只是学生类中的一个属性
**

class Student extends Person {
    protected Book book;
    protected int score;
}

**

因此,继承是is关系,组合是has关系。

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

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

相关文章

使用keytool查看Android APK签名

文章目录 一、找到JDK位置二、使用方法2.1 打开windows命令行工具2.2 查看签名 三、如何给APK做系统签名呢? 一、找到JDK位置 安卓AS之后,可选择继续安装JDK,如本文使用amazon版本默认位置:C:\Users\66176.jdks\corretto-1.8.0_342可通过自…

智能优化算法应用:基于北方苍鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于北方苍鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于北方苍鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.北方苍鹰算法4.实验参数设定5.算法结果6.…

数据库之MySQL的介绍

操作系统: windows:win10、win11、win7、windows Server2016 Linux/Unix :红帽(RedHat)、Bebian、SUSE MacOS Linux系统:CantOS(yum、dnf)、Ubuntu(apt、apt—get&am…

2024 年 22 款顶级免费数据恢复软件比较 [Windows 和 Mac]

适用于 Windows 和 Mac 用户的最佳数据恢复软件下载列表和比较,可快速恢复丢失的数据、已删除的文件、照片或格式化的分区数据: 数据恢复软件是一种从任何存储介质恢复丢失文件的应用程序。它可以恢复由于病毒攻击、硬盘故障或任何其他原因而意外删除或…

机器人创新实验室任务三参考文档

一、JAVA环境配置 需要在Linux里面下载并且安装java。 sudo apt-get install openjdk-17-jre-headless 打开终端并且运行指令,用apt下载安装java。官方用的好像是java11,我安装的是java17。 如果无法定位软件安装包,可以试试更新一下 sudo …

极智一周 | MoE、FlashAttention、PTQ、MI300禁令、H100利润空间、戴口罩检测 And so on

欢迎关注我的公众号 [极智视界],获取我的更多技术分享 大家好,我是极智视界,带来本周的 [极智一周],关键词:MoE、FlashAttention、PTQ、MI300禁令、H100利润空间、戴口罩检测 And so on。 邀您加入我的知识星球「极智…

1856_emacs_calc使用介绍与故事

Grey 全部学习内容汇总: GitHub - GreyZhang/g_org: my learning trip for org-mode 1856_emacs_calc使用介绍与故事 calc是emacs内置的一个计算器,可以提供多种计算表达方式并且可以支持org-mode中的表格功能。 主题由来介绍 我是因为想要了解org-…

c语言的练习---BCD解密

#继续源于c语言翁恺先生 一.分析 初看这道题的时候,可能很多人就想选择放弃,但这道题实在不是考察我们对于编码的能力;而是我们的数学能力。 就拿它的输入样例---18,来举例。 我们来看---在十进制中,是18D&#xf…

网络协议-BIO实战和NIO编程

网络通信编程基本常识 原生JDK网络编程-BIO 原生JDK网络编程-NIO Buffer 的读写 向 Buffer 中写数据 写数据到 Buffer有两种方式: 1. 读取 Channel写到 Buffer。 2.通过 Buffer 的 put0方法写到 Buffer 里。 从 Channel 写到 Buffer …

分布式锁常见问题及其解决方案

一、为什么要使用分布式锁? 因为在集群下,相当于多个JVM,就相当于多个锁,集群之间锁是没有关联的,会照成锁失效从而导致线程安全问题 分布式锁可以分别通过MySQL、Redis、Zookeeper来进行实现 二、redis分布式锁的实…

SpringBoot 3 集成Hive 3

前提条件: 运行环境&#xff1a;Hadoop 3.* Hive 3.* MySQL 8 &#xff0c;如果还未安装相关环境&#xff0c;请参考&#xff1a;Hive 一文读懂 Centos7 安装Hadoop3 单机版本&#xff08;伪分布式版本&#xff09; SpringBoot 2 集成Hive 3 pom.xml <?xml ver…

力扣经典面试题——搜索二维矩阵(两次二分搜索)

https://leetcode.cn/problems/search-a-2d-matrix/description/?envTypestudy-plan-v2&envIdtop-100-liked 思路&#xff1a;先按行二分&#xff0c;再按列进行二分。即先找到对应的行&#xff0c;再找对应的列。 对于这种判断是否存在某个数&#xff0c;记得while(left…

PHP案例代码:PHP如何提供下载功能?

对Web开发人员来说,“下载”功能是一个非常常见的需求。在网站中提供文件下载,通常用于提供用户手册、软件升级、音乐、视频等各种资源文件。本教程将向您介绍如何实现一个PHP下载功能,同时告诉浏览器文件名称、文件大小、文件类型,并统计下载次数。 首先,我们需要了解一些…

Verilog RAM/ROM的数据初始化

文章目录 一、初始化方式二、测试 FPGA设计中RAM和ROM作为存储器用来存储可变或不可变类型的数据。 ROM初始化一般是加载固定数据&#xff0c;RAM声明时默认为不定态数据&#xff0c;初始化时可以让数据为全1或者全0。 一、初始化方式 复位时按地址写入初值always (posedge cl…

nodejs+vue+ElementUi房屋房产销售预约看房系统bqv00

完成房产销售系统&#xff0c;对房源的信息、用户信息及各种资料进行收集和科学的管理&#xff0c;该系统的功能基本可以满足当前市面上的小型房产企业对于房产销售的基本要求&#xff0c;收集各个地区的房源信息并进行分类管理&#xff0c;用户通过注册账号登录网站查询房源信…

MySQL内外连接

目录 内连接外连接左外连接右外连接 内连接 给出一张员工表和一张部门表&#xff0c;员工表数据如下&#xff1a; 部门表信息如下&#xff1a; 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选&#xff0c;我们前面学习的查询都是内连接&#xff0c;也是在开发过…

小程序面试题 | 11.精选小程序面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

推荐算法架构7:特征工程(吊打面试官,史上最全!)

系列文章&#xff0c;请多关注 推荐算法架构1&#xff1a;召回 推荐算法架构2&#xff1a;粗排 推荐算法架构3&#xff1a;精排 推荐算法架构4&#xff1a;重排 推荐算法架构5&#xff1a;全链路专项优化 推荐算法架构6&#xff1a;数据样本 推荐算法架构7&#xff1a;特…

算法:BFS宽度优先遍历

文章目录 BFS与Queue相结合N叉树的层序遍历二叉树的锯齿形层序遍历二叉树的最大宽度 BFS和FLoodFill相结合图像渲染岛屿数量岛屿的最大面积 BFS解决最短路问题最小基因变化单词接龙为高尔夫比赛砍树 本篇总结的是BFS算法&#xff0c;BFS算法相比起DFS算法来说还是比较简单的 B…

基于 Sentry 的前端监控系统搭建(Linux)

一、前言 随着技术这几年的发展与沉淀&#xff0c;线上数据指标监控也变得尤为重要&#xff0c;研发人员和运营人员需要对线上的产品指标有所感知&#xff0c;同时风险也需要及时暴露&#xff0c;很多公司开始自建监控系统&#xff0c;但对于一些定制化要求不是特别高的团队&a…
最新文章