java 之 继承与多态的详细介绍

在这里插入图片描述

文章目录

  • 类的继承
      • 1. 基本语法
      • 2. 继承的特点
      • 3. 方法的重写(方法的覆盖)
      • super 关键字
      • 1. 调用父类的构造器
      • 2. 访问父类的成员变量
      • 3. 调用父类的方法
      • 4. 在构造器中调用父类方法
      • 封装性以及访问修饰符
      • 抽象方法
      • 1. 声明抽象类
      • 2. 抽象方法
      • 3. 继承抽象类
      • 4. 抽象类的实例化
      • 5. 构造器和抽象类
      • 6. 抽象类 vs 接口
      • 子类对象与父类对象的转换
      • 1. 向上转型(Upcasting)[自动转换]
      • 2. 向下转型(Downcasting)[强制转换]
        • 差异
          • 1. `Animal myAnimal = new Dog();`
          • 2. `Dog myAnimal = new Dog();`
          • 总结
      • instanceof 运算符
      • 语法
      • 示例
      • 应用场景
      • 多态与重载

类的继承

在Java中,类的继承是一种重要的面向对象编程(OOP)概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。这种机制使得代码可以更加灵活、可复用,并支持多层次的类之间的关系。以下是关于Java中类的继承的详细介绍:

1. 基本语法

在Java中,使用关键字 extends 实现类的继承。语法如下:

class Subclass extends Superclass {
    // 子类的成员变量和方法
}

其中,Subclass 是子类,Superclass 是父类。

2. 继承的特点

  • 单一继承: Java不支持多继承,一个子类只能继承一个父类。这是为了避免多继承可能引发的复杂性和歧义。

  • 构造器的继承: 子类会继承父类的构造器,但是子类的构造器不能直接调用父类的构造器。在子类的构造器中,可以使用 super 关键字调用父类的构造器。

  • 访问权限: 子类可以访问父类中的公有(public)和受保护(protected)的成员,但不能访问私有(private)的成员。

3. 方法的重写(方法的覆盖)

子类可以重写(override)父类中的方法,以满足子类的需求。重写的方法必须具有相同的方法签名(方法名字,参数列表、返回类型),而且访问权限不能比父类中的方法更严格。

class Superclass {
    void display() {
        System.out.println("Superclass display");
    }
}

class Subclass extends Superclass {
    @Override
    void display() {
        System.out.println("Subclass display");
    }
}
  • 注意父类中的private 方法不能被被覆盖,父类中的static 方法能被继承,不能被覆盖

super 关键字

在Java中,super 是一个关键字,用于引用父类的成员变量、方法或构造器。它可以用于以下几种情况:

1. 调用父类的构造器

在子类的构造器中,使用 super 调用父类的构造器。这通常用于在子类的构造过程中执行一些父类的初始化操作。

class Superclass {
    Superclass(int x) {
        // 父类构造器
    }
}

class Subclass extends Superclass {
    Subclass(int x, int y) {
        super(x); // 调用父类的构造器
        // 子类构造器
    }
}

2. 访问父类的成员变量

使用 super 关键字可以在子类中访问父类中的成员变量,尤其是当子类和父类有同名的成员变量时。

class Superclass {
    int x = 10;
}

class Subclass extends Superclass {
    void display() {
        System.out.println(super.x); // 访问父类的成员变量
    }
}

3. 调用父类的方法

在子类中,可以使用 super 关键字调用父类的方法。这在子类重写父类方法的时候很有用,可以在子类方法中调用父类版本的方法。

class Superclass {
    void display() {
        System.out.println("Superclass display");
    }
}

class Subclass extends Superclass {
    @Override
    void display() {
        super.display(); // 调用父类的display方法
        System.out.println("Subclass display");
    }
}

4. 在构造器中调用父类方法

在子类的构造器中,可以使用 super 调用父类的方法,确保在子类对象初始化时执行必要的父类操作。

class Superclass {
    void init() {
        // 父类初始化操作
    }
}

class Subclass extends Superclass {
    Subclass() {
        super(); // 调用父类的构造器
        super.init(); // 调用父类的方法
        // 子类构造器
    }
}

总的来说,super 关键字提供了一种访问父类成员的途径,可以在子类中调用父类的构造器、成员变量和方法,从而实现更灵活的代码编写。

封装性以及访问修饰符

Java中封装性的实现主要靠包的实现以及类以及类的成员的访问修饰符来实现
在这里插入图片描述

封装的目的是将对象的状态(成员变量)和行为(方法)封装在一起,提供一种受控的访问机制,防止外部直接访问对象的内部细节。在Java中,封装通过以下方式实现:

  1. 成员变量私有化(Private Fields): 将类的成员变量声明为私有,只能在类的内部访问。

    public class MyClass {
        private int myField;
    
        public int getMyField() {
            return myField;
        }
    
        public void setMyField(int value) {
            // 可以在setter方法中添加一些逻辑,例如范围检查
            if (value >= 0) {
                myField = value;
            }
        }
    }
    
  2. 提供公共方法(Public Methods): 通过公共方法来访问和修改私有成员变量,以实现对成员变量的控制和封装。

    MyClass obj = new MyClass();
    obj.setMyField(42);
    int value = obj.getMyField();
    

通过这种方式,封装隐藏了对象的内部细节,使得对象更加安全、可维护,同时提供了一种更灵活的方式来管理对象的状态。

Java提供了几种访问修饰符,用于控制类、变量、方法等成员的访问权限。

  1. public(公共): 修饰的成员对所有类可见,无访问限制。

  2. private(私有): 修饰的成员只能在当前类中访问,其他类无法直接访问。

  3. protected(受保护): 修饰的成员对同一包内的类和所有子类可见,但对其他包中的类不可见。

  4. default(默认,无修饰符): 修饰的成员对同一包内的类可见,但对其他包中的类不可见。在没有显式声明修饰符的情况下,默认为包内可见。

  5. final(最终): 用于修饰类、方法、变量。修饰类时,表示该类不能被继承;修饰方法时,表示方法不能被重写;修饰变量时,表示变量为常量,不可被修改。

使用访问修饰符和封装的概念,可以控制对象的访问权限,提高代码的安全性和可维护性。

抽象方法

在Java中,抽象类是一种不能被实例化的类,用于定义一些抽象的方法,这些方法在具体的子类中被实现。抽象类通过关键字 abstract 来声明。以下是关于Java抽象类的一些重要概念和规则:

1. 声明抽象类

使用 abstract 关键字来声明抽象类。抽象类可以包含抽象方法和非抽象方法。

abstract class Shape {
    // 抽象方法
    abstract void draw();

    // 非抽象方法
    void display() {
        System.out.println("Displaying shape");
    }
}

2. 抽象方法

抽象方法是没有具体实现的方法,它只有方法签名而没有方法体。任何包含抽象方法的类必须被声明为抽象类。

abstract class Animal {
    abstract void makeSound();
}

3. 继承抽象类

如果一个类继承了一个抽象类,它必须实现父类中所有的抽象方法,否则这个类也必须声明为抽象类。

class Circle extends Shape {
    // 实现抽象方法
    void draw() {
        System.out.println("Drawing circle");
    }
}

4. 抽象类的实例化

抽象类不能被实例化,但可以通过创建其非抽象子类的实例来使用抽象类。例如:

Shape shape = new Circle();
shape.draw();     // 调用子类实现的抽象方法
shape.display();  // 调用抽象类中的非抽象方法

5. 构造器和抽象类

抽象类可以有构造器,但它不能被直接实例化。构造器通常被子类调用,以初始化抽象类中的成员变量。

abstract class AbstractClass {
    AbstractClass() {
        // 构造器
    }
}

6. 抽象类 vs 接口

抽象类和接口都是实现代码重用和多态性的机制,但它们有一些区别。主要的区别在于:

  • 抽象类可以包含非抽象方法,而接口中的方法都是抽象的。
  • 类只能继承一个抽象类,但可以实现多个接口。
abstract class AbstractClass {
    abstract void method1();
    void method2() {
        // 非抽象方法
    }
}

interface MyInterface {
    void method1();
    void method3();
}

抽象类在设计一些具有共同特征的类时非常有用,而接口更适用于定义一些类似于协议的东西,可以被多个类实现。选择抽象类还是接口取决于具体的设计需求。

子类对象与父类对象的转换

在Java中,子类对象与父类对象之间的转换通常涉及向上转型和向下转型,这是基于类的继承关系的一种操作。

1. 向上转型(Upcasting)[自动转换]

向上转型是将子类对象引用赋给父类对象引用的过程,这是一种隐式的转换,不需要显式的类型转换。向上转型是安全的,因为子类对象可以被视为父类对象。

class Animal {
    // ...
}

class Dog extends Animal {
    // ...
}

Dog myDog = new Dog();
Animal animal = myDog; // 向上转型

在这个例子中,myDogDog 类的对象,通过向上转型,可以将它赋给 Animal 类型的引用变量 animal

2. 向下转型(Downcasting)[强制转换]

向下转型是将父类对象引用转换为子类对象引用的过程,这需要使用显式的类型转换,并且在进行转换之前需要确保原始对象是目标子类的实例。

Animal animal = new Dog();
Dog myDog = (Dog) animal; // 向下转型

在这个例子中,animalAnimal 类的对象,通过向下转型,将其转换为 Dog 类型的引用变量 myDog。需要注意,如果在运行时 animal 不是 Dog 类型的对象,将会抛出 ClassCastException 异常。因此,在进行向下转型之前,通常应当使用 instanceof 运算符来检查对象的类型。

if (animal instanceof Dog) {
    Dog myDog = (Dog) animal; // 向下转型
}

向上转型和向下转型的操作在处理多态性和继承关系时是常见的,但需要谨慎使用,以确保类型转换的安全性。

差异

这两行代码涉及到Java中的多态性和引用类型的概念。让我们逐一解释这两行代码的区别:

1. Animal myAnimal = new Dog();

这是一个典型的向上转型(Upcasting)的例子。在这里,创建了一个 Dog 类的对象,并将其赋给了一个 Animal 类型的引用变量 myAnimal

这种向上转型的效果是,尽管 myAnimal 的静态类型(声明类型)是 Animal,但在运行时,它引用的是一个 Dog 对象。这使得你可以通过 myAnimal 调用 Animal 类中定义的方法,但不能调用 Dog 类中独有的方法,除非进行强制类型转换。

Animal myAnimal = new Dog();
myAnimal.someMethod();  // 可以调用 Animal 类的方法
// myAnimal.bark();  // 不能调用 Dog 类的方法,因为其静态类型是 Animal
2. Dog myAnimal = new Dog();

这是一个直接创建 Dog 类的对象,并将其赋给了一个 Dog 类型的引用变量 myAnimal。这是一个常规的对象创建和引用赋值的操作。

在这种情况下,myAnimal 的静态类型和运行时类型都是 Dog。因此,你可以直接调用 Dog 类中定义的方法。

Dog myAnimal = new Dog();
myAnimal.someMethod();  // 可以调用 Animal 类的方法
myAnimal.bark();       // 可以调用 Dog 类的方法
总结
  1. Animal myAnimal = new Dog(); 表示使用 Animal 类型的引用指向 Dog 类型的对象,发生了向上转型。
  2. Dog myAnimal = new Dog(); 表示使用 Dog 类型的引用指向 Dog 类型的对象。

在实际应用中,选择使用哪种方式主要取决于代码的设计需求。向上转型通常用于提高代码的灵活性,而直接使用具体类型的引用则可能更加直观和明确。

instanceof 运算符

instanceof 是Java中的一个二元运算符,用于在运行时检查对象是否是特定类的实例,或者是否实现了特定的接口。它返回一个布尔值,表示对象是否是指定类型的实例。

语法

object instanceof type

其中,object 是要检查的对象,type 是要检查的类或接口的类型。

示例

class Animal {
    // ...
}

class Dog extends Animal {
    // ...
}

class Cat extends Animal {
    // ...
}

Animal myAnimal = new Dog();

if (myAnimal instanceof Dog) {
    System.out.println("myAnimal is an instance of Dog");
} else if (myAnimal instanceof Cat) {
    System.out.println("myAnimal is an instance of Cat");
} else {
    System.out.println("myAnimal is not an instance of Dog or Cat");
}

在这个例子中,myAnimalAnimal 类型的引用,但它指向的是 Dog 类的实例。通过使用 instanceof 运算符,我们可以在运行时检查 myAnimal 是否是 Dog 类或 Cat 类的实例。

应用场景

  1. 类型检查: 用于检查对象是否属于特定的类或接口。

    if (myObject instanceof MyClass) {
        // 执行特定的逻辑
    }
    
  2. 避免 ClassCastException: 在进行向下转型时,先使用 instanceof 进行类型检查,以确保对象是目标类型的实例,避免抛出 ClassCastException 异常。

    if (myObject instanceof Dog) {
        Dog myDog = (Dog) myObject; // 向下转型
        // 执行特定的逻辑
    }
    

instanceof 在面向对象的程序设计中是一个非常有用的工具,能够增加程序的灵活性和鲁棒性,避免在运行时发生类型不匹配的错误。

多态与重载

多态和重载是两个不同的概念。

  1. 多态性(Polymorphism): 多态是指同一个方法调用可以根据对象的不同类型而具有不同的行为。它主要通过方法的’重写(override)‘实现以及方法重载,使得子类能够提供对方法的自定义实现。多态性通过继承和接口的方式来体现,能够提高代码的灵活性和可扩展性。

    class Animal {
        void makeSound() {
            System.out.println("Some generic sound");
        }
    }
    
    class Dog extends Animal {
        @Override
        void makeSound() {
            System.out.println("Bark");
        }
    }
    
    class Cat extends Animal {
        @Override
        void makeSound() {
            System.out.println("Meow");
        }
    }
    
    Animal myDog = new Dog();
    Animal myCat = new Cat();
    
    myDog.makeSound();  // 调用 Dog 类的 makeSound 方法
    myCat.makeSound();  // 调用 Cat 类的 makeSound 方法
    
  2. 重载(Overloading): 重载是指在同一个类中,可以定义多个方法,它们具有相同的名称但是参数列表不同。重载通过方法的参数类型、参数个数或者参数顺序的不同来区分不同的方法。

    class Calculator {
        int add(int a, int b) {
            return a + b;
        }
    
        double add(double a, double b) {
            return a + b;
        }
    }
    
    Calculator myCalculator = new Calculator();
    int resultInt = myCalculator.add(3, 5);        // 调用 int add(int a, int b)
    double resultDouble = myCalculator.add(3.0, 5.0);  // 调用 double add(double a, double b)
    

总结:

  • 多态性是面向对象编程中的一个概念,与继承和接口有关,通过方法的重写与重载实现。
  • 重载是指在同一个类中定义多个方法,它们有相同的名称但参数列表不同,通过参数的类型、个数或者顺序的不同来区分。

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

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

相关文章

Zabbix自定义监控内容

自定义监控客户端服务器登录的人数 需求:限制登录人数不超过 3 个,超过 3 个就发出报警信息 1.在客户端创建自定义key //明确需要执行的 linux 命令 who | wc -l//创建 zabbix 的监控项配置文件,用于自定义 key vim /etc/zabbix/zabbix_ag…

com.mongodb.MongoSocketOpenException: Exception opening socket

估计mongodb数据库没开启,或者链接错误了,谁又改了,唉 2023-11-29 16:19:45.818 INFO 39552 --- [127.0.0.1:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server 127.0.0.1:27017…

浅析Hotspot的经典7种垃圾收集器原理特点与组合搭配

# 浅析Hotspot的经典7种垃圾收集器原理特点与组合搭配 HotSpot共有7种垃圾收集器,3个新生代垃圾收集器,3个老年代垃圾收集器,以及G1,一共构成7种可供选择的垃圾收集器组合。 新生代与老年代垃圾收集器之间形成6种组合&#xff0c…

Unity 代码控制Color无变化

Unity中,我们给Color的赋值比较常用的方法是: 1、使用预定义颜色常量: Color color Color.white; //白色 Color color Color.black; //黑色 Color color Color.red; //红色 Color color Color.green; //绿色 Color color Color.blue; …

【Java】类和对象之超级详细的总结!!!

文章目录 前言1. 什么是面向对象?1.2面向过程和面向对象 2.类的定义和使用2.1什么是类?2.2类的定义格式2.3类的实例化2.3.1什么是实例化2.3.2类和对象的说明 3.this引用3.1为什么会有this3.2this的含义与性质3.3this的特性 4.构造方法4.1构造方法的概念4…

回溯和分支算法

状态空间图 “图”——状态空间图 例子:农夫过河问题——“图”状态操作例子:n后问题、0-1背包问题、货郎问题(TSP) 用向量表示解,“图”由解向量扩张得到的解空间树。 ——三种图:n叉树、子集树、排序树 ​ 剪枝 不满住条件的…

单细胞测序并不一定需要harmony去除批次效应

大家好,今天我们分享的是单细胞的学习教程https://www.singlecellworkshop.com/analysis-tutorial.html 教程的作者使用了四个样本,但是没有使用harmony或者其他方法去整合 去除批次效应。 主要内容: SCTransform流程代码及结果 harmony流程…

python pyaudio 录取语音数据

python pyaudio 录取语音数据 pyaudio安装方法: pip install pyaudio如果这个不行,可以尝试: pip install pipwin pipwin install pyaudio代码如下: import pyaudio import waveRESPEAKER_RATE 44100 # 采样率,每…

界面组件DevExpress Reporting v23.1新版亮点 - UX功能增强

DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已于前段时间…

无头浏览器与Selenium:探索无界爬虫的奇妙世界

selenium设置无头浏览器 背景 ​ 我们之前的selenium都是浏览器驱动自动打开一个网页,执行相关操作,其实也可以让其后台显示,不用在前台显示。 ​ 要设置无头浏览器,可以使用Selenium的Headless模式。在Headless模式下&#xf…

从零开始实现神经网络(二)_CNN卷积神经网络

参考文章: 介绍卷积神经网络1 介绍卷积神经网络2 在过去的几年里,关于卷积神经网络(CNN)的讨论很多,特别是因为它们彻底改变了计算机视觉领域。在这篇文章中,我们将建立在神经网络的基本背景知识的基础上,探…

GCN,GraphSAGE 到底在训练什么呢?

根据DGL 来做的,按照DGL 实现来讲述 1. GCN Cora 训练代码: import osos.environ["DGLBACKEND"] "pytorch" import dgl import dgl.data import torch import torch.nn as nn import torch.nn.functional as F from dgl.nn.pytorc…

质量小议35 -- SQL注入

已经记不得上次用到SQL注入是什么时候了,一些概念和操作已经模糊。 最近与人聊起SQL注入,重新翻阅,暂记于此。 重点:敏感信息、权限过大、未脱敏的输入/输出、协议、框架、数据包、明文、安全意识 SQL - Structured Query La…

时间序列预测实战(二十三)进阶版LSTM多元和单元预测(课程设计毕业设计首选)

一、本文介绍 本篇文章给大家带来的是利用我个人编写的架构进行LSTM模型进行时间序列建模(专门为了时间序列领域新人编写的架构,简单且不同于市面上大家用GPT写的代码),包括结果可视化、支持单元预测、多元预测、模型拟合效果检测…

(C++)盛水最多的容器--双指针法

个人主页:Lei宝啊 愿所有美好如期而遇 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://le…

软著项目推荐 深度学习图像风格迁移

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习图像风格迁移 - opencv python 该项目较为新颖,适合作为竞赛课题…

【ArcGIS Pro微课1000例】0048:深度学习--人群计数

文章目录 一、小学回忆录二、深度学习计算人头数三、案例实现一、小学回忆录 加载配套实验数据包中的图片及训练模型。你还记得当年的小学毕业班有多少同学吗?今天我们就用ArcGIS提供的人工智能工具,重温一下童年记忆。 二、深度学习计算人头数 本案例使用到的是深度学习中…

[树莓派3B+][内核版本6.1]的linux内核编译+替换 (超详细)

学习Linux的内核编译,我使用的是x86 64位的18.04的ubuntu-linux虚拟机: 目录 树莓派的Linux内核源码安装 操作系统的启动过程 & Bootloader 单片机裸机:C51,STM32 X86,Intel:windows 嵌入式产品:…

CUDA简介——同步

1. 引言 前序博客: CUDA简介——基本概念CUDA简介——编程模式CUDA简介——For循环并行化CUDA简介——Grid和Block内Thread索引CUDA简介——CUDA内存模式 本文重点关注Thread同步和Barriers。 Threads并行执行,可能存在如下问题: 1&#…

芯擎科技与芯华章深度合作,软硬件协同开发加速车规级芯片创新

12月4日,系统级验证EDA解决方案提供商芯华章,与国产高端车规芯片设计公司芯擎科技正式建立战略合作。双方强强联手,芯擎科技导入芯华章相关EDA验证工具,赋能车规级芯片和应用软件的协同开发,助力大规模缩短产品上市周期…
最新文章