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

news2025/1/15 16:27:51

三.继承——节省了共有属性和方法的代码:语法 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.coloradmin.cn/o/1331834.html

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

相关文章

基于Kubernetes的jenkins上线

1、基于helm 部署jenkins 要求:当前集群配置了storageClass,并已指定默认的storageClass,一般情况下,创建的storageClass即为默认类 指定默认storageClass的方式 # 如果是新创建默认类: apiVersion: storage.k8s.io/v1…

C# WPF上位机开发(从demo编写到项目开发)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 C# WPF编程,特别是控件部分,其实学起来特别快。只是后面多了多线程、锁、数据库、网络这部分稍微复杂一点,不过…

如何在linux安装软件

一.安装种类 1.编译安装:灵活性高,难度较大, 可以安装新版本 2.rpm安装:查软件信息,是否安装,文件列表 3.yum:是rpm的升级版本,解决rpm的弊端 rpm安装: 安装软件的时…

OpenCV利用HSV颜色区间分离不同物体

需求 当前有个需求是从一个场景中将三个不同的颜色的二维码分离出来,如下图所示。 这里有两个思路可以使用 思路一是通过深度学习的方式,训练一个能够识别旋转边界框的模型,但是需要大量的数据进行模型训练,此处缺少训练数据&a…

Quartz.NET 事件监听器

1、调度器监听器 调度器本身收到的一些事件通知,接口ISchedulerListener,如作业的添加、删除、停止、挂起等事件通知,调度器的启动、关闭、出错等事件通知,触发器的暂停、挂起等事件通知,接口部分定义如下&#xff1a…

springMVC-与spring整合

一、基本介绍 在项目开发中,spring管理的 Service和 Respository,SrpingMVC管理 Controller和ControllerAdvice,分工明确 当我们同时配置application.xml, springDispatcherServlet-servlet.xml , 那么注解的对象会被创建两次, 故…

ZooKeeper 使用介绍和原理详解

目录 1. 介绍 重要性 应用场景 2. ZooKeeper 架构 服务角色 数据模型 工作原理 3. 安装和配置 下载 ZooKeeper 安装和配置 启动 ZooKeeper 验证和管理 停止和关闭 4. ZooKeeper 数据模型 数据结构和层次命名空间: 节点类型和 Watcher 机制&#xff…

8002D 3W单声道带关断模式音频功率放大器 适用于游戏机、无源扬声器

8002D 是一款 AB 类&#xff0c;单声道带关断模式&#xff0c;桥式音频功率放大器。在输入 1KHZ,5V 工作电压时&#xff0c;最大驱动功率为: 3W.(422 负载&#xff0c;THD<10%)&#xff0c;2W,(4Q负载&#xff0c;THD<1%):音频范围内总谐波失真噪音小于 1%(20Hz20KHz ); …

基于YOLOv8深度学习的200种鸟类智能检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

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

智能优化算法应用&#xff1a;基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于跳蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.跳蛛算法4.实验参数设定5.算法结果6.参考文献7.MA…

如何使用树莓派Bookworm系统中配置网络的新方法NetworkManager

树莓派在 10 月新出的 Bookworm 版本系统中&#xff0c;将使用多年的 dhcpcd 换成了 NetworkManager&#xff08;以前是在rasp-config中可选&#xff09;&#xff0c;这是因为 Raspberry Pi OS 使用的是 Debian 内核&#xff08;和 Ubuntu 一样&#xff09;&#xff0c;所以树莓…

持续集成交付CICD:Linux 部署 Jira 9.12.1

目录 一、实验 1.环境 2.K8S master节点部署Jira 3.Jira 初始化设置 4.Jira 使用 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注master1K8S master节点1.20.6192.168.204.180 jenkins slave &#xff08;从节点&#xff09; jira9.12.1…

Java经典框架之Spring

Java经典框架之Spring Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring简介 2.…

kubernetes集群 应用实践 kafka部署

kubernetes集群 应用实践 kafka部署 零.1、环境说明 零.2、kafka架构说明 zookeeper在kafka集群中的作用 一、Broker注册 二、Topic注册 三、Topic Partition选主 四、生产者负载均衡 五、消费者负载均衡 一、持久化存储资源准备 1.1 创建共享目录 [rootnfsserver ~]# mkdir -…

springcloud-gateway-2-鉴权

目录 一、跨域安全设置 二、GlobalFilter实现全局的过滤与拦截。 三、GatewayFilter单个服务过滤器 1、原理-官方内置过滤器 2、自定义过滤器-TokenAuthGatewayFilterFactory 3、完善TokenAuthGatewayFilterFactory的功能 4、每一个服务编写一个或多个过滤器&#xff0c…

Centos安装vsftpd:centos配置vsftpd,ftp报200和227错误

一、centos下载安装vsftpd&#xff08;root权限&#xff09; 1、下载安装 yum -y install vsftpd 2、vsftpd的配置文件 /etc/vsftpd.conf 3、备份原来的配置文件 sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.backup 4、修改配置文件如下&#xff1a;vi /etc/vsftpd.conf …

在Jetpack Compose中使用ExoPlayer实现直播流和音频均衡器

在Jetpack Compose中使用ExoPlayer实现直播流和音频均衡器 背景 ExoPlayer与Media3的能力结合&#xff0c;为Android应用程序播放多媒体内容提供了强大的解决方案。在本教程中&#xff0c;我们将介绍如何设置带有Media3的ExoPlayer来支持使用M3U8 URL进行直播流。此外&#x…

【数据结构一】初始Java集合框架(前置知识)

Java中的数据结构 Java语言在设计之初有一个非常重要的理念便是&#xff1a;write once&#xff0c;run anywhere&#xff01;所以Java中的数据结构是已经被设计者封装好的了&#xff0c;我们只需要实例化出想使用的对象&#xff0c;便可以操作相应的数据结构了&#xff0c;本篇…

锯齿云服务器租赁使用教程

首先登陆锯齿云账号 网盘上传数据集与代码 随后我们需要做的是将所需要的数据集与代码上传到网盘&#xff08;也可以直接在租用服务器后将数据集与代码传到服务器的硬盘上&#xff0c;但这样做会消耗大量时间&#xff0c;造成资源浪费&#xff09; 点击工作空间&#xff1a;…

【Python】基于flaskMVT架构与session实现博客前台登录登出功能

目录 一、MVT说明 1.Model层 2.View层 3.Template层 二、功能说明 三、代码框架展示 四、具体代码实现 models.py 登录界面前端代码 博客界面前端代码&#xff08;profile.html&#xff09; main.py 一、MVT说明 MVT架构是Model-View-Template的缩写&#xff0c;是…