Java的多态如何实现的?
xsobi 2025-01-03 19:37 1 浏览
面向对象编程语言三大特征:继承、封装、多态。虽说是三大特征,但其实从多态的角度看,继承和封装都是为了实现多态而准备的,尤其是在一些大型优秀的框架上,多态的使用随处可见,所以说多态是一个十分重要的知识点。
什么是多态?
多态的定义:指允许不同类的对象对同一消息做出响应。即方法传入同一参数可以根据对象的不同而采用多种不同的处理方式。
多态的实现:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法,而在java中,多态是具体表现为继承(extends)或实现(implements)。
多态的作用:可以极大消除类型之间的耦合关系,多用于架构及复用的设计中。
无论是继承还是实现,多态的核心原理都是声明的总是父类类型或接口类型,创建的是实际类型。
假如有一种场景,人开汽车,但是汽车有很多品牌有很多种类很多参数配置,这个时候该如何设计代码实现满足此种场景的要求呢?来看一下使用多态是如何完美解决的;
首先,我们考虑人开车,但不知道具体是什么车,所以我们可以将车的一些基本特征抽象成一个接口。
再定义人类,里面有开车的方法run,需要特别注意的是,这里的形参使用的是顶级接口Car,而不是具体的子类。
考虑到车还有很多品牌,每个品牌的定位及配置等都不同,这里可以再基于汽车品牌抽象出品牌车的抽象类,如国产汽车BYD是品牌,其DM系列的汉EV是具体的车型号,也就是具体的子类。
假设比亚迪DM汉EV具体的实现如下,汉是BYD品牌,所以需要继承自BYD品牌的车类。
同样的我们再写一个奔驰的品牌车类及对应的车型奔驰GLC:
奔驰GLC是具体的车型号,所以是具体的实现类
我们简单创建两个人来开车试试看,其中创建两个人分别是小明和小红,分别创建了两个车bydEV和glc,两个子类对象都指向Car顶级接口,然后运行这段代码:
最后得到的运行结果是:小明开的车上BYD汉EV,小红开的车是奔驰GLC。
在代码中明明都指向共同的一个父类接口Car,为何在运行时就不同了呢?其实这就是多态,这个底层运行实现在前文中已提到,那就是动态绑定。
动态绑定和静态绑定
JVM在执行方法时,通常调用的指令有五个,分别是:
invokestatic:调用静态方法;
invokespecial:调用实例构造器<init>方法、私有方法和父类方法;
invokevirtual:调用虚方法;
invokeinterface:调用接口方法,运行时确定具体实现;
invokedynamic:运行时动态解析所引用的方法,然后再执行,用于支持动态类型语言。
其中Invokestatic和invokespecial指令是用于静态绑定,invokevirtual 和 invokeinterface 用于动态绑定。
静态绑定指的是在编译期就能确定的,比如静态方法、构造器、私有方法和父类方法这4种方法在编译期就能解析引用确定的称为非虚方法,与之相对的就是虚方法,对象方法基本都为虚方法,例如上方例子中人类的drive(Car car),汽车子类实现类中的run()方法等。
有个特例的是被final修饰的方法,由于不能被继承重写,所以是可以唯一确定的,是属于非虚方法,但却是使用invokevirtual指令调用的。
JVM底层多态实现过程
多态的实现过程,本质就是方法调用动态绑定的过程,通过栈帧的信息去找到被调用方法的具体实现,然后使用这个具体实现的直接引用完成方法调用。
根据《Java虚拟机规范》,invokevirtual指令在运行时解析大致分为以下几个步骤:
- 先从操作栈中找到对象的实际类型 C;
- 找到 C中与被调用方法签名相同的方法,如果有访问权限就返回这个方法的直接引用,如果没有访问权限就报错 java.lang.IllegalAccessError ;
- 如果第 2 步找不到相符的方法,就去搜索 C的父类,按照继承关系自下而上依次执行第 2 步的操作;
- 如果第 3 步找不到相符的方法,就报错 java.lang.AbstractMethodError ;
可以看到,如果子类覆盖了父类的方法,则在多态调用中,动态绑定过程会首先确定实际类型是子类,从而先搜索到子类中的方法。
我们都知道在程序运行时,动态绑定是一个非常高频的行为,JVM为了提高性能,避免反复搜索对应类型的绑定数据,会建立一个对应的虚方法表和接口方法表,使用对应的表索引来提高查询的性能。
以虚方法表为例,如果某个父类的方法在子类中没有被进行重写,那么此时子类和父类的虚方法表指向的地址是一致的,只有当出现子类重写了父类的方法时,才会出现子类的虚方法表与父类的虚方法表指向的地址不一样。因此,如果子类没有重写父类的方法时,会随着父类的方法解析一同解析。
总结
多态是面向对象编程语言的重要特征,也是架构及复用设计的基础!例如文章开头的场景中,人开车,因为车有很多品牌及很多类型,车的品牌类型也无时无刻在变更,有可能明天多一个品牌,我们只需求去实现Car接口就可以轻松添加一个新的品牌,而且不用去改动原本的代码实现,所以在人类的drive不能够用具体的类型作为形参,需要使用Car顶级抽象的接口,使用多态的特性去动态绑定各种车的品牌实现。
- 上一篇:C++中的多态性
- 下一篇:继承和多态概念及语法
相关推荐
- Asp.Net快速开发平台(敏捷开发框架)
-
前言:敏捷开发框架的名称由来呢?我希望开发项目可以结构化的,轻量级的,就像敏捷开发团队一样的高效快速,通过它可以快速开发一个项目。1:什么是敏捷开发框架?答:敏捷开发框架是一款Asp.Net轻量级智能...
- 干货来了!推荐10个用于C#.NET开发的基本调试工具
-
今天给各位网友分享10个用于C#.NET开发的基本调试工具,掌握了这10个工具,大家就可以轻松玩转C#.NET开发与调试。话不多说,直接上干活!!1、VisualStudio...
- 「Net Core开发」webapi 开发
-
之前的文章:【NetCore开发】C#开发跨平台程序...
- .NET5.0和Quartz.NET开发的极简任务调度平台
-
任务调度是让系统自动化完成特定的任务,在预约的时间点执行任务的过程。任务调度在不同业务需求情况也不一样,有些可能是有着上千上万个任务,需要统一管理;有些可能是为了方便异常进行提醒、监控。项目简介...
- 3个基于.Net开发的、开源远程管理工具
-
我是编程乐趣,一个10年.Net开发经验老程序员,点击右上方“关注”,每天为你分享开源项目和编程知识。盘点3个基于.Net开发的、开源Windows远程管理工具。...
- 跨平台开发的未来:如何在 .NET 6 上构建高效的跨平台应用
-
跨平台开发是当今软件开发领域的一大热点。开发者一直在寻找能够让他们编写一次代码并部署到多个操作系统(如Windows、Linux和macOS)上的工具和框架。传统的开发方式需要针对每个操作系统编...
- .Net开发框架最终版将与Win10同步问世
-
对许多用户而言,7月29日最受关注的事件是Windows10的发布。但事实上,除了Windows10外这一日微软还会带来更多的亮点。届时微软还将发布针对Windows通用应用程序平台的(UWP)....
- 微软推出 .NET Aspire云端框架:可改进分布式应用开发流程
-
IT之家5月24日消息,据微软官方新闻稿,微软近日推出一款能够简化.NET云端开发的.NETAspire开发框架,该框架主要包含工具、模板和NuGet包,允许用户“更容易地”创建分布...
- VOL.NET6开发MES系统第二篇——基础数据
-
大家好,我是李工。系统框架我们已经运行起来了,今天我们正式开始搭建MES系统。MES系统主要实现四大模块:基础数据、生产管理、生产数据、操作记录;今天我们主要演示一个单表的增删改查以及权限控制,我们不...
- .NET混合开发解决方案1 WebView2简介
-
在我的博客《...
- VOL.NET6开发MES系统第一篇——搭建程序
-
大家好,我是李工,接下来我将用VOL.NET6搭建一套MES系统;有兴趣的小伙伴们可以一起学习。一、下载源码VOL...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- patch补丁 (31)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- firebug 使用 (31)
- characterencodingfilter (33)
- getmonth (34)
- hibernate教程 (31)
- label换行 (33)
- curlpost (31)
- android studio 3 0 (34)
- android应用开发 (31)
- html转js (35)
- 索引的作用 (33)
- css3 0 (31)
- checkedlistbox (34)
- localhost 8080 (32)
- 多态 (32)
- net开发 (31)