详解Java之继承与多态

news2024/9/30 10:52:45

目录

继承

派生类和基类各部分执行顺序

protected

访问权限总结

final关键字

组合

多态

向上转型

向下转型

动态绑定

静态绑定

方法重载

方法重写 

super关键字

super和this的对比

在构造方法中调用重写方法


继承

继承是为了解决多个类具有一些相同的属性和方法而造成的代码冗余问题,将这些具有相同属性和方法分离出来设置为一个类,然后让有这些属性和方法的类来继承它。

被继承的类成为父类,基类或超类,而继承的类成为子类或派生类。

语法规则

class 子类 extends 父类 {
}

使用 extends 指定父类.
Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
子类会继承父类的所有 public 的字段和方法.
对于父类的 private 的字段和方法, 子类中是无法访问的.
子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用

super的使用

访问父类的成员属性:super.data

访问父类的成员方法:super.func()

派生类和基类各部分执行顺序

举例

class Animal{
    public String name;

    public Animal(String name) {
        this.name = name;
        System.out.println("Animal的构造方法");
    }

    {
        System.out.println("Animal的实例代码块");
    }

    static{
        System.out.println("Animal的静态代码块");
    }
}

class Dog extends Animal{
    public Dog(String name){
        super(name);
        System.out.println("Dog的构造方法");
    }

    {
        System.out.println("Dog的实例代码块");
    }

    static{
        System.out.println("Dog的静态代码块");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog=new Dog("黑子");
    }
}

输出结果: 

 

protected

对于类的调用者来说, protected 修饰的字段和方法是不能访问的;
对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的。

访问权限总结
Java 中对于字段和方法共有四种访问权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public : 类内部和类的调用者都能访问

final关键字

当final修饰一个变量或者字段的时候,表示不可被修改(常量)。

final关键字也能修饰类,此时表示被修饰的类不能被继承。

我们平时使用的String字符串类,就是用final修饰的,不能被继承。

此时的array变量保存的是地址,指向一段内存,因为array被final修饰,因此不能修改的是array的指向,但是array保存的地址指向的空间的内容可以被修改!!!

组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.
例如表示一个学校:

public class Student { 
 ...
}
public class Teacher { 
 ...
}
public class School {
    public Student[] students;
    public Teacher[] teachers;
}

组合表示has-a语义;

继承表示is-a语义。

多态
向上转型

向上转型发生的时机:

直接赋值;方法传参;方法返回。

向下转型

举例

class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
    public void eat(String food) {
        System.out.println("我是一只小动物");
        System.out.println(this.name + "正在吃" + food);
    }
}
// Bird.java 
class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void eat(String food) {
        System.out.println("我是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
    }

    public void fly() {
        System.out.println(this.name + "正在飞");
    }
}

如果我们将Bird向上转型为Animal,可以调用eat方法,但是不能调用fly方法了,会编译出错

编译过程中, animal 的类型是 Animal, 此时编译器只知道这个类中有一个 eat 方法, 没有 fly 方法.
虽然 animal 实际引用的是一个 Bird 对象, 但是编译器是以 animal 的类型来查看有哪些方法的.
对于 Animal animal = new Bird("小鸟") 这样的代码,编译器检查有哪些方法存在, 看的是 Animal 这个类型执行时究竟执行父类的方法还是子类的方法, 看的是 Bird 这个类型。

解决方法:向下转型

输出结果:

向下转型是不靠谱的,比如

Animal animal = new Cat(" 小猫 ");
Bird bird = (Bird)animal;
bird.fly();

因为Cat类中没有fly方法,因此这样会执行出错,抛异常。 

动态绑定

举例

class Animal{
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat(String food){
        System.out.println("我是动物");
        System.out.println(this.name+"正在吃"+food);
    }
}

class Bird extends Animal{
    public Bird(String name){
        super(name);
    }

    public void eat(String food){
        System.out.println("我是小鸟");
        System.out.println(this.name+"正在吃"+food);
    }
}

public class Test {
    public static void main(String[] args) {
        Animal animal=new Animal("动物");
        animal.eat("小麦");
        Animal animal1=new Bird("小鸟");
        animal1.eat("谷物");
    }
}

运行结果:

我们惊奇的发现,虽然animal和animal1都是Animal类型的引用,但是animal1的eat方法调用结果与animal的eat方法调用结果不同,即animal指向Animal类型的实例,animal.eat()调用了父类的实例,animal1指向Bird类型的实例,animal1.eat()调用了子类的实例。

因此,在Java中,调用某个类的方法,究竟执行了哪段代码(是父类方法的代码还是子类方法的代码),要看这个引用指向的是父类对象还是子类对象,这个过程是程序运行时决定的(而不是编译期间),因此称之为 动态绑定。

静态绑定

静态绑定发生在编译时期,也就是说,在编译时就已经确定了要调用的方法。这通常适用于那些不需要在运行时根据对象的实际类型来确定方法的情况。静态绑定主要发生在以下几种情况:

private方法:因为private方法是不可见的,所以它们不能被继承,调用它们的引用在编译时就已知,因此是静态绑定的。
final方法:final方法不能被子类覆盖,所以编译器在编译时就可以确定要调用的方法。
static方法:静态方法属于类,不属于任何对象实例,且可以通过类名直接调用。因此,编译器在编译时就能确定调用哪个方法。
构造方法:虽然构造方法看起来像是方法,但实际上它们是在对象创建时调用的特殊方法。因为构造方法不是通过对象实例调用的,所以也是静态绑定的。

方法重载

重载是指在同一个类中,允许多个同名方法同时存在,但要求它们的参数列表不同(参数的个数、类型或顺序至少有一项不同)。重载与方法的返回类型无关,即两个方法可以有相同的名称和不同的返回类型,但如果它们的参数列表相同,则不能构成重载。重载是编译时多态的体现。

举例

class Test {  
    void show(int a) {  
        System.out.println("整数:" + a);  
    }  
  
    void show(String s) {  
        System.out.println("字符串:" + s);  
    }  
  
    // 下面这个方法是合法的重载,因为参数列表不同(参数类型不同)  
    void show(double a) {  
        System.out.println("双精度数:" + a);  
    }  
  
    // 如果下面这个方法被添加到类中,它将导致编译错误,因为与第一个方法参数列表相同  
    // void show(int a) { ... }  
}

方法重写 

针对刚才的 eat 方法来说:
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).


关于重写的注意事项
1. 重写和重载完全不一样,不要混淆.
2. 普通方法可以重写, static 修饰的静态方法不能重写.

3. 重写中子类的方法的访问权限不能低于父类的方法访问权限.
4. 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外).

5.被private修饰的方法不能进行重写。

6.被final修饰的方法不能进行重写,此时这个方法叫做密封方法。

7.访问修饰限定符权限大小:private < 默认权限 < protected < public。

8.方法的返回值可以不同,但是必须是父子关系,或者称为协变。

9.构造方法不能进行重写。

举例

class Animal {  
    void eat() {  
        System.out.println("动物吃东西");  
    }  
}  
  
class Dog extends Animal {  
    // Dog类重写了Animal类的eat方法  
    @Override  
    void eat() {  
        System.out.println("狗吃骨头");  
    }  
}  
  
// 使用  
Animal myDog = new Dog();  
myDog.eat(); // 输出:狗吃骨头(尽管引用类型是Animal,但实际对象类型是Dog,体现了多态性)
super关键字

前面的代码中由于使用了重写机制, 调用到的是子类的方法. 如果需要在子类内部调用父类方法怎么办? 可以使用super 关键字.
super 表示获取到父类实例的引用. 涉及到两种常见用法:

1) 使用了 super 来调用父类的构造器
public Bird(String name) {
    super(name);
}
2) 使用 super 来调用父类的普通方法
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }
    @Override
    public void eat(String food) {
        // 修改代码, 让子调用父类的接口. 
        super.eat(food);
        System.out.println("我是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
    }
}
在这个代码中 , 如果在子类的 eat 方法中直接调用 eat ( 不加 super), 那么此时就认为是调用子类自己的 eat ( 也就是递归了). 而加上 super 关键字 , 才是调用父类的方法.
super和this的对比
在构造方法中调用重写方法
class B {
    public B() {
        // do nothing 
        func();
    }
    public void func() {
        System.out.println("B.func()");
    }
}
class D extends B {
    private int num = 1;
    @Override
    public void func() {
        System.out.println("D.func() " + num);
    }
}
public class Test {
    public static void main(String[] args) {
        D d = new D();
    }
}

输出结果:

解释:

构造 D 对象的同时, 会调用 B 的构造方法.
B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func。
此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0。

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

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

相关文章

DotNetty ChannelRead接收数据为null

问题&#xff1a;C#使用Dotnetty和Java netty服务器通讯&#xff0c;结果能正确发送数据到服务器&#xff0c;却始终接收不到服务器返回的数据。 解决&#xff1a;一定一定要注意服务器和客户端使用的编码一定要完全一样才行 我先前在客户端添加了StringDecoder,服务器却没有…

AI如此迅猛,你还能跟上吗?快来试试这个对口型新神器!

国庆即将到来&#xff0c;宇航祝大家国庆节快乐&#xff01;最近感觉有些寒意了&#xff0c;气温忽高忽低的&#xff0c;大家一定要注意&#xff0c;别感冒了。 今天给大家分享一个即梦的新功能 : 对口型&#xff0c;也是最近即梦不声不响新上线的功能。 一、 功能介绍 即梦的…

【C++】多态(上)

个人主页~ 多态 一、多态的概念二、多态的定义以及实现1、多态的构成条件2、虚函数3、虚函数的重写虚函数重写的两个特殊情况①协变② 析构函数的重写 4、C11的override和final&#xff08;1&#xff09;final&#xff08;2&#xff09;override 5、重载、重写、隐藏的对比 三、…

普中51单片机

参考&#xff1a;51单片机快速入门教程2022&#xff08;普中51开发板A2新版&#xff09;--绍兴文理学院元培学院《单片机原理与应用》课程建设_哔哩哔哩_bilibili 1.以管理员启动&#xff0c;破解

【开源免费】基于SpringBoot+Vue.JS校园资料分享平台(JAVA毕业设计)

本文项目编号 T 059 &#xff0c;文末自助获取源码 \color{red}{T059&#xff0c;文末自助获取源码} T059&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

【抖音矩阵源码开发:短视频矩阵SEO技术深度解析与实践指南】

开发部署短视频矩阵源码的主要步骤如下&#xff1a; 开发和部署短视频矩阵平台涉及一系列精细化的技术步骤&#xff0c;旨在确保系统的高效构建与稳定运行。该流程起始于开发环境的精心部署&#xff0c;涵盖PHP环境的搭建、集成开发环境&#xff08;IDE&#xff09;的配置以及…

STM32编码器接口笔记

1. 引言 在现代控制系统中&#xff0c;编码器扮演着非常重要的角色。它就像一个精密的测量工具&#xff0c;可以告诉我们机械部件的位置和运动状态。在STM32微控制器中&#xff0c;编码器接口可以轻松地与各种编码器连接&#xff0c;实现精确的控制。我将在这里探讨STM32编码器…

string类的使用(上)

目录 1.string类的概念 2.string的构造函数&#xff08;实现初始化&#xff09; 3.对string类容量获取和操作 4.string类对象的访问和遍历 4.1operator[] 4.2begin和end 4.3 rbegin 和 rend 4.4迭代器分类 4.5范围for&#xff08;自动实现遍历&#xff09; 5.string类…

打造高效舒适的气膜网球馆—轻空间

气膜网球馆&#xff0c;作为现代运动设施的创新选择&#xff0c;其成本构成涵盖多个重要方面&#xff0c;确保为运动者提供最佳体验。 一、膜材选择 膜材是气膜网球馆的核心&#xff0c;品质不同直接影响成本。高品质膜材不仅增强了耐用性&#xff0c;也能有效阻挡外界气候影响…

【展会回顾】阿尔泰科技2024上海工博会精彩瞬间,圆满收官 ,感恩遇见 ,共赴新程!

9月24日&#xff0c;以“工业聚能 新质领航”为主题的第二十四届中国国际工业博览会&#xff08;以下称“工博会”&#xff09;在国家会展中心&#xff08;上海&#xff09;举办&#xff0c;展示了一批代表中国工业领域的最新技术与前沿成果。 本届工博会的主题“工业聚能&…

Pycharm 本地搭建 stable-diffusion-webui

一、下载工程源码 Github官方连接 https://github.com/AUTOMATIC1111/stable-diffusion-webui 二、Pycharm打开工程 1、设置环境 文件-设置-项目-Python解析器-添加解释器-添加本地解释器 Conda环境-创造新环境-Python版本3.10 注意一定要选择Python3.10版本&#xff0c;否…

uni-app canvas文本自动换行

封装 支持单行文本超出换行。多行文本顺位排版 // 填充自动换行的文本function fillFeedText({ctx, text, x, y, maxWidth, lineHeight, color, size}) {// 文本配置ctx.setFontSize(size);ctx.setFillStyle(color);// 计算文本换行宽高&#xff0c;换行逻辑const words text…

JavaScript中的函数定义

第8章 函数 在JS中函数即对象&#xff0c;程序可以随意操控他们。可以把函数赋值给变量&#xff0c;或者作为参数传递给其他函数。因为函数就是对象&#xff0c;所以可以给他们设置属性&#xff0c;甚至调用他们的方法。 JavaScript的函数可以嵌套在其他函数中定义&#xff0…

初识C语言(四)

目录 前言 十一、常见关键字&#xff08;补充&#xff09; &#xff08;1&#xff09;register —寄存器 &#xff08;2&#xff09;typedef类型重命名 &#xff08;3&#xff09;static静态的 1、修饰局部变量 2、修饰全局变量 3、修饰函数 十二、#define定义常量和宏…

5250 Fantasy RPG Icons Pack 幻想RPG游戏图标合集

这里是集合 - 幻想RPG图标 它包括50个主题图标。文件:PNG。 在档案中,带有背景的图标(512512)和没有背景的单个对象(大小取决于主题)。仅具有背景技能的技能。 2024年2月更新(+500个图标): RPG蔬菜图标; RPG游戏中的蜘蛛战利品图标; RPG海战战利品图标; RPG怪物战利…

匿名管道 Linux

管道 首先自己要用用户层缓冲区&#xff0c;还得把用户层缓冲区拷贝到管道里&#xff0c;&#xff08;从键盘里输入数据到用户层缓冲区里面&#xff09;&#xff0c;然后用户层缓冲区通过系统调用&#xff08;write&#xff09;写到管道里&#xff0c;然后再通过read系统调用&…

新手上路:Anaconda虚拟环境创建和配置以使用PyTorch和DGL

文章目录 前言步骤 1: 安装 Anaconda步骤 2: 创建新的 Anaconda 环境步骤 3: 安装最新版本的 PyTorch步骤 4: 安装特定版本的 PyTorch步骤 5: 安装最新版本的 DGL步骤 6: 安装特定版本的 DGL步骤 7: Pycharm中使用虚拟环境解释器第一种情况&#xff1a;创建新项目第二种情况&am…

Linux Shell编程最重要的十个核心概念

对于每个Linux学习者而言&#xff0c;Shell编程的重要性不言而喻。它是连接用户与系统操作的桥梁&#xff0c;能够培养命令行的熟练度和解决问题的能力。通过Shell编程&#xff0c;学习者可以深入理解系统管理和日常任务自动化的精髓&#xff0c;提高工作效率。此外&#xff0c…

应急响应(1)-同事电脑

一、现象 重要时间节点&#xff0c;同事反馈桌面有鼠标移动、随机断网&#xff1b;发现登录账户多了一个&#xff0c;由于电脑长时间没有更改过密码&#xff0c;导致忘记密码无法登录。随机联系进行应急处理。 二、排查 2.1、密码重置/删除 由于同事忘记密码导致无法进行登录…

Linux文件系统入门详解-总结大章

我们先看一张图&#xff1a; 这张图大体上描述了 Linux 系统上&#xff0c;应用程序对磁盘上的文件进行读写时&#xff0c;从上到下经历了哪些事情。 这篇文章就以这张图为基础&#xff0c;介绍 Linux 在 I/O 上做了哪些事情。 文件系统 什么是文件系统 文件系统&#xff0…