Java时如何实现多态的(重载和重写)_方法重现体现多态-程序员宅基地

回顾一下Java的四大特性抽象,封装,继承,多态
其中封装是依靠访问修饰符(public,default,protected,private)实现的,继承是依靠关键字extends,那么多态又是依靠什么实现的呢?

什么是多态

多态的概念并不难,并且在实际编码中可以说是最最高频使用率。多态就是使得同一个行为具有多个不同表现形式或形态的能力。举个形象点的例子:对于 “打印” 这个行为,使用彩色打印机 “打印” 出来的效果就是彩色的,而使用黑白打印机 “打印” 出来的效果就是黑白的。我们就称 “打印” 这个行为是多态的,彩色打印效果和黑白打印效果就是 “打印” 这个行为的两个不同的表现形式。
在这里插入图片描述

同一个行为在不同的对象上会产生不同的结果。

多态发生的三个必要条件
看下面这段代码,首先,我们有一个基类 Shape,三个子类,并且都重写了基类的 draw 方法:

class Shape {
    
    void draw() {
    }
}
 
class Circle extends Shape {
    
    void draw() {
    
        System.out.println("Circle.draw()");
    }
}
 
class Square extends Shape {
    
    void draw() {
    
        System.out.println("Square.draw()");
    }
}
 
class Triangle extends Shape {
    
    void draw() {
    
        System.out.println("Triangle.draw()");
    }
}

多态的体现就在下面这几行代码里

Shape circle = new Circle();//画一个圆形
Shape square = new Square();//画一个正方形
Shape triangle = new Triangle();//画一个三角形

是否有些眼熟,上面这三行代码不就是向上转型吗!继承中提到的向上转型,它就是多态的体现。同样的一个 draw 方法,在这三个不同的对象上产生了三种不同的行为,多态在此体现的淋漓尽致。
注意点
这里需要注意的是,当使用多态方式调用方法时,编译器会首先检查父类中是否有该方法,如果没有,则编译错误;如果父类中有该方法,并且被子类重写,就会调用子类的这个方法;如果父类的方法没有被子类重写,就会调用父类的方法。

Shape circle = new Circle();
circle.draw(); // 调用的是 Circle 的 draw,不是Shape的,只有当Circle没有重写draw的时候才会调用Shape

简单来说:当父类引用变量指向子类对象后(多态),只能使用父类已声明的方法,但方法如果被重写会执行子类的方法,如果方法未被重写那么将执行父类的方法。

实现多态的三要素(必要条件)
1)继承
2)重写
3)父类引用指向子类对象:Parent p = new Child();
在这里插入图片描述
多态是如何发生的
那么,多态到底是如何发生的?编译器是如何知道父类 Shape 引用指向的是 Circle 而不是 Triangle 或 Square 呢?
若绑定发生在程序运行前,叫做静态绑定,也称前期绑定。你可能从来没有听说这个术语,因为它是面向过程语言不需选择默认的绑定方式,例如在 C 语言中就只有前期绑定这一种方法调用。

Shape circle = new Circle();
Shape square = new Square();
circle.draw(); 

对于上面的代码,Shape 即引用类型在编译期可知,不会被改变,而 Circle 作为实例对象类型在运行期才可知,可能会发生变化。所以如果使用前期绑定,在运行之前,编译器只知道有一个 Shape 引用,它无法得知究竟会调用哪个方法。
解决方法就是动态绑定 Dynamic Binding,在运行时根据对象的类型自动的进行绑定(JVM类加载),所以动态绑定也称运行时绑定。动态绑定是多态的基础。(自动绑定实例化对象对应的类)
注意:Java 中除了 static 和 final方法(private 方法属于 final 方法)之外,其他所有方法都是动态绑定。这意味着通常情况下,我们不需要判断动态绑定是否会发生,它是自动发生的。

final 不允许方法重写,而多态发生的条件之一就是重写,所以 final 方法会在编译期间就进行绑定,即静态绑定
static 方法是类直接拥有的的,与该类的任何一个对象都无关(该类的所有对象共同维护),所以也是静态绑定

重载和重写
方法的重写 Overriding 和重载 Overloading 都是是 Java 多态性的表现。
1.方法的重写是多态的必要条件,也是父类和子类多态性的表现
其中子类方法和父类方法名字相同,参数类型相同,访问权限子类必须大于等于父类,总结来说,子类方法和父类方法除了方法体不一样,访问权限可以有限制的修改之外,其余都是一样的。

class Shape {
    
    public void draw() {
    }
}
 
class Circle extends Shape {
    
    public void draw() {
    
        System.out.println("Circle.draw()");
    }
}

但是重写方法的返回类型一定要和父类方法一模一样吗?
答案其实是否定的,首先,我们需要知道方法的名字参数列表称为方法的签名。例如,draw() 和 draw(String) 是两个具有相同名字, 不同签名的方法。如果在子类中定义了一个与超类签名相同的方法, 那么子类中的这个方法就覆盖/重写了超类中的这个相同签名的方法。
但是返回类型不是签名的一部分, 因此,在覆盖/重写方法时, 一定要保证返回类型的兼容性。 允许子类将覆盖方法的返回类型定义为原返回类型的子类型。
假设shape类为

class Shape {
    
    public Shape draw() {
    
    	......
    }
}

子类重写draw方法

class Circle extends Shape {
    
    public Circle draw() {
    
        ......
    }
}

此时重写的方法返回类型其实和父类方法不同,专业术语来说,这两个 draw 方法具有可协变的返回类型。

2.方法重载并非多态的必要条件,不过可以理解成某个类的多态性的表现
所谓方法重载,就是一个类中定义了多个方法名相同,但是参数的数量或者类型不同。方法的返回类型和访问权限可以任意修改,不以它俩作为方法重载的标志。

class Circle extends Shape {
    
    public void draw() {
    
        System.out.println("Circle.draw()");
    }
    
    public void draw(int i) {
    
        System.out.println("Circle.draw()" + i);
    }
}

在这里插入图片描述
总结一下方法重载和方法重写的区别,其实最简单就是看是否在同一个类

在这里插入图片描述
在这里插入图片描述
既然方法可以重载,那么main方法可以重载吗?
答:只要是方法,都可以重载,但是,如果是作为程序的入口,那么 main 函数只有一种写法,Java 虚拟机在运行的时候只会调用带有参数是 String 数组的那个 main() 方法,而其他重载的写法虚拟机是不认的,只能人为的调用

class Test {
    
	public static void main(String[] args) {
    
		main(1);
	}
	public static void main(int i) {
    
		System.out.println("重载的 main 方法");
	}
}

运行的结果也很简单——“重载的main方法”
可以看出第一个main方法调用了重载后的main方法,打印语句,这也证明了main方法也可以重载,但是程序的入口仍然是String数组的那个main方法
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_45725126/article/details/119043028

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签