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

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签