java 抽象类语法_JAVA基础语法8--多态/抽象类/抽象方法

多态

继承、封装、多态、抽象是面向对象编程的四大基本特征。封装隐藏了类的内部实现机制,从而可以在不影响使用者的前提条件下,改变类的内部结构,同时保护了数据。继承是为了重用父类代码,同时为多态做准备。那么,什么是多态呢?

所谓多态,英文单词为polymorphism,这个英文单词是由单词poly(意思是很多或多个)和morph(意思是形状或形式)组成的复合词。多态一词最早出现在生物学,是指生物学的一个基本原则:一个生物或物种可以有多种不同的形式或阶段。面向对象编程吸收了这一原则,在OOP中,多态是指一个对象有多种形式的能力。一个类的子类可以定义它们唯一的行为,同时共享父类的某些相同特征。

多态可以说是面向对象编程的精髓所在。因此,理解多态的含义,对理解面向对象编程有特别重要的意义。

Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同。C++允许多继承,这确实给它带来了非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦。为了规避风险,Java只允许单继承,子类与父类间有IS-A的关系。这样做虽然保证了继承关系的简单明了,但是势必在功能上有很大的限制。所以,Java引入了多态性的概念,以弥补这点的不足。此外,我们在本节后面要学到的抽象类和接口也是解决单继承规定限制的重要手段。

在Java中,多态有两种理解方式:第一种是对象的不同的方法可以用相同的一个方法名,也就是重载的概念。 另一种是同一对象根据不同的消息执行相应的行为,也可以这样认为发送消息给某一个对象,让对象自行选择哪种相应的行为。根据这种两种方式,所以多态可以分为静态多态和动态多态。

静态多态指的是程序在编译时,系统就能决定调用哪个方法,所以也称为编译时多态。在Java中,静态多态实现的方式就是方法重载,其调用规则是依据对象在定义时的类型相应地调用对应类中的重载方法。

动态多态指在运行中系统才能动态确定方法所指的对象,所以也称为运行时多态。动态多态的实现方式是重写父类中的同名成员方法,其调用规则是依据对象在实例化时而非定义时的类型,相应地调用对应类中的同名成员方法。也就是说,动态多态主要通过动态绑定和重写的机制来实现。

多态技术基础

在Java中,使用动态绑定和重写机制来实现多态,我们首先需要掌握如下三个基础技术概念:

向上转型技术:一个父类的引用变量可以指向不同的子类对象,或者说一个子对象可以被当作一个父类类型。

instanceof关键字:instanceof关键字用于判断运行时对象的真正类型。

可以规避掉“强制向下转型过程中”可能会出现的转型风险。

动态绑定技术:运行时根据父类引用变量所指对象的实际类型执行相应的子类方法,从而实现多态性。

1)向上转型和向下转型

在基础数据类型中,我们已经看到了表达式中数值数据类型byte、short、int、long、float和double的相互转换规则,即:当从低精度数据类型向高精度数据类型转换时实行自动转换,这种类型转换技术称为向上转型;当从高精度数据类型向低精度数据类型转换时,需要使用强制类型转换符,这种类型转换技术称为向下转型。

对于引用数据类型,这种转换技术依然适用。在父类和子类的继承层次关系中,沿着子类向父类向上转型是自动转换,而从父类向子类必须使用强制类型转换才能实现向下转型。

例如:Employee e = new Salary("王二", "胜利大道24号", 47, 250000.00);

这里Salary是Employee的子类

那么,我们为什么要用一个父类类型的引用去指向一个子类的对象呢?为什么不直接用一个子类类型的引用呢?这样做到底有什么意义呢?

这是因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特。定义一个父类类型的引用指向一个子类的对象,既可以使用子类强大的功能,又可以抽取父类的共性,从而可以使代码更容易编写,更容易维护。

既然父类类型的引用没有改变什么,那么为什么不总是用它呢?如果我们使用Employee类型的引用来指向一个Salary对象,对象不会丢失数据,但是用父类类型的引用则不能直接访问Salary类的成员变量和方法的。

如果要用父类类型的引用访问子类的成员变量和方法,我们就必须将Employee类型的引用强制转换为Salary类型的引用。

如:Salary salary =(Salary)e;

注:引用数据类型向下强制转换是有风险的,不一定能够转型成功,如果要转型成功,必须同时满足以下两个要求:

必须是父类引用指向一个子类的实现

强制转换类型必须跟这个子类实现具体的类型一致,不能是父类其他子类的类型

使用instanceof关键字判断对象的真正类型

Java语言的多态机制导致了引用变量的声明类型和实际引用对象的类型可能不一致。为更准确鉴别一个对象的真正类型,Java语言引入了instanceof运算符。

使用instanceof的语句如下:

引用 instanceof 类名

如果引用是指定的类类型,那么instanceof运算符返回true,否则返回false。

动态绑定技术

我们首先要理解Java中的动态绑定机制。

在面向对象程序开发中,我们将一个方法调用与该方法所在的类关联起来,称为"绑定"。绑定分静态绑定和动态绑定,或者称为前期绑定和后期绑定。

所谓静态绑定,是指在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现。针对Java简单的可以理解为程序编译期的绑定;这里特别说明一点,Java中的方法只有final、static、private和构造器是前期绑定。

所谓动态绑定,是指在运行时根据具体对象的类型进行绑定。Java中所有的普通方法,都采用动态绑定技术。通过动态绑定,JVM必须沿着继承层次树向下找,判断一个方法是否被重写。如果方法被重写了,在运行时就执行子类中的方法,而不是编译时调用的父类方法。

多态的主要应用

1)多态参数

所谓多态参数,就是当方法的某个形式参数是一个引用的时候,与该引用兼容的任何对象都可以传递给方法,从而允许方法接受不同数据类型的形式参数。

例如,如下的方法有一个Employee类型的形式参数:

public void payEmployee(Employee e)

如果要调用payEmployee()方法,我们需要用一个Employee对象作为实际参数。如果Salary和Hourly继承自Employee类,那么Salary或Hourly对象也可以作为实际参数传给payEmployee()方法。因为通过多态,Salary或Hourly对象也是一个Employee对象。

现在,通过将Employee类型的引用作为形式参数,使payEmployee()成为了一个更通用的方法。现在,它可以接受Employee、Hourly、Salary对象作为实际参数。如果出现了一个继承自Employee类的新类,那么这个新类也可以传递给payEmplyee()。

2)异构集合

多态最常见的应用是创建一个不是同一类型,但是有共同父类的数据集合。不同对象的集合称为异构集合。

例如所有的类都继承object,如果写一个数组为object类型数组,那么就可以装任何的类型对象。

多态总结

从以上示例,我们可以看出:父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,它是无可奈何的;同时,父类中的一个方法只有在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态绑定。也就是说:在多态机制中,是由被引用对象的类型,而不是引用变量的类型,决定了调用谁的成员方法。但是,这个被调用的方法必须是在父类中定义过的,也就是说被子类重写的方法 。

因此,对于多态,我们可以总结它为:

使用父类类型的引用指向子类的对象。

该引用只能调用父类中定义的方法,不能调用子类中独有的方法。

如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法。

在多态中,子类可以调用父类中的所有方法。

在Java中,所有普通方法默认都是动态绑定,要避免动态绑定默认行为的唯一方法是将方法声明为final。声明为final的方法不能被重写,所以JVM不需要沿着继承层次树向下寻找,并试图判断子类是否重写该方法。基于此原因,final方法可以提升性能,因为避免了动态绑定的开销。

抽象

我们在编写类时,通常会在类中定义一些方法,用来描述该类所具有的行为。在类的方法体中,我们编写代码实现该类所要执行的行为。在继承关系中,子类继承父类后,子类也就具有父类所具备的行为。如果子类继承了父类的行为,但是与父类的行为实现方式不同,就需要通过方法重写来覆盖父类的行为。

如果我们不需要类的实例时,就可以将类设计成为一个抽象类。所谓抽象类,是不能被实例化的类。在抽象类中,类的所有其它功能都存在,成员变量、方法、构造器都可以用同样的方式访问。我们只是不能创建抽象类的实例。

2124e77ea429b7e1b33fcd4f6fccc1f0.png

抽象类

在Java中,使用关键字abstract可以声明一个抽象类,该关键字可以出现在类声明时class关键字前的任何地方。

我们注意到类除了声明为abstract外,其它的没有改变。现在,我们不能实例化一个抽象的对象。但是对于它的子类没有任何影响。

c97a72158ac8f369f7c1dd51fa0c8fa4.png

抽象方法

在父类中有的行为我们不需要去具体实现,因为我们永远不会调用它,但是它又是子类必须有的,我们只需要在子类中去对方法进行重写,进行具体的实现。这种情况下,我们就可以用抽象方法了。如果我们想一个类包含一个特定的方法,该方法的实际实现由子类决定,那么我们就可以在父类中将该方法声明为抽象方法。抽象方法只有方法签名,没有方法体。

代码清单展示了声明为抽象的computePay()方法。注意,该方法没有定义部分,并且方法签名后跟一个分号,没有大括号。

/*代码清单  Employee.java

这里,computePay()方法被声明为抽象方法,在类中没有实现

*/

public abstract class Employee{

private String name;

private String address;

private int number;

public abstract double computePay();

//类定义的剩余部分

}

将一个方法声明为抽象方法有两个结果:

类也必须声明为抽象类。如果一个类包含了抽象方法,那么该类也必须是抽象的。

任何子类必须重写抽象方法,除非子类本身也是抽象的。

从设计的角度看,将一个抽象方法放在父类中,可以强制任何子类实现一个特别的行为。继承抽象方法的子类必须重写该方法。如果子类不重写抽象方法,那么子类必须是抽象类,子类的子类必须重写该方法。最终,必须有一个后代类实现抽象方法,否则,我们就有一个不能实例化的抽象类层次。

那么,为什么要使用方法抽象呢?这是因为强制其它类实现某个行为有好处。

使用抽象类类和抽象方法的好处

用抽象类及接口最重要的用处还是在于,使代码实现很方便的扩展,最简单的就是在new对象时,将生成对象定义为接口,在以后需要替换时就很方便。

抽象类及接口,并不只是为了抽象,为了接口面抽象,而接口。在你需要用到一系列可继承自抽象类的子类,或是需要实现共同接口的多个实现类时,才需要考虑。

其实抽象类的一个好处是类不能被实例化,最大的好处就是通过方法的覆盖来实现多态的属性。也就是运行期绑定。

用抽象的型别统一类型,来进行操作,有利于以后的扩展,移植,复用!!

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

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

相关文章

01-几种应用上下文区别

第一次写博客,有点小激动,写的东西很水,仅供自己加深印象??,有人不介意想参考?那我也不介意,??。。。。 Spring中几种常用的应用上下文有: 1. ClassPathXmlApplicationContext 2. FileSyste…

工作394-注册页面学习

注册页面对于小程序中的每个页面,都需要在页面对应的 js 文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。 使用 Page 构造器注册页面简单的页面可以使用 Page() 进行构造。代码示例://index.js Page({data: {text: "…

(搬家文) c++引用深入探讨

(偶然翻起自己的旧博,忽然发现大三的时候写的这篇文章,仔细看看觉得写的还是那么回事,所以赶紧搭救出来) 引用的声明: 基本格式:引用类型 &引用名被引用对象 &运算符:声明运算符& 跟取地址运算符&和位异或运算符&没有任何关系ext…

参数作用域实践

auto参数&#xff0c;申明时可以忽略auto void fun(){int p 1;cout<<"p:"<<p<<endl;for(int i0;i<5;i){int p 10;cout<<"p:"<<p<<endl;}// 此处输出的还是外围作用域定义的p值1cout<<"p:"<<…

工作395-路由选择

初始化 新页面入栈 打开新页面 新页面入栈 页面重定向 当前页面出栈&#xff0c;新页面入栈 页面返回 页面不断出栈&#xff0c;直到目标返回页 Tab 切换 页面全部出栈&#xff0c;只留下新的 Tab 页面 重加载 页面全部出栈&#xff0c;只留下新的页面

phpstudy2018修改php版本,phpstudy的php版本自由修改的方法

作为PHP开发的常用工具&#xff0c;phpstudy具有许多强大的功能&#xff0c;它可以连接到MySQL并检查服务器状态&#xff0c;感兴趣的话就随爱站技术频道小编一起来了解phpstudy的php版本自由修改的方法吧&#xff01;网上有着许多的网站集成搭建软件&#xff0c;比较出名的就有…

Sql字符串函数(1)

--1.截取已知长度的函数 Select S1http://www.163.com-- A.截取从字符串左边开始N个字符 Declare S1 varchar(100) 显示结果: http Select Left(S1,4) Select S1http://www.163.com -- B.截取从字符串右边开始N个字符(例如取字符http://www.163.com/) Declare S1 varchar(100) …

工作397-Wxml

WXMLWXML&#xff08;WeiXin Markup Language&#xff09;是框架设计的一套标签语言&#xff0c;结合基础组件、事件系统&#xff0c;可以构建出页面的结构。要完整了解 WXML 语法&#xff0c;请参考WXML 语法参考。用以下一些简单的例子来看看 WXML 具有什么能力&#xff1a; …

php格式的种子,php读取torrent种子文件内容的方法(测试可用)

本文实例讲述了php读取torrent种子文件内容的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;/*** Class xBEncoder* Author: Angus.Fenying* Version: 0.1* Date: 2014-06-03** This class helps stringify or parse BENC* codes.** All Copyrights 2007 - 2014 …

API网关从入门到放弃

前言 假设你正在开发一个电商网站&#xff0c;那么这里会涉及到很多后端的微服务&#xff0c;比如会员、商品、推荐服务等等。 那么这里就会遇到一个问题&#xff0c;APP/Browser怎么去访问这些后端的服务? 如果业务比较简单的话&#xff0c;可以给每个业务都分配一个独立的域…

BarTender操作遇到OLE DB遇到了错误0x80004005”的问题

在使用BarTender打印条码时操作遇到"OLE DB遇到了错误0x80004005”的问题 在打印时关掉数据库所连接的Excel文件即可转载于:https://www.cnblogs.com/edrp/archive/2010/07/18/1780122.html

工作397-Wx

WXSSWXSS (WeiXin Style Sheets)是一套样式语言&#xff0c;用于描述 WXML 的组件样式。WXSS 用来决定 WXML 的组件应该怎么显示。为了适应广大的前端开发者&#xff0c;WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序&#xff0c;WXSS 对 CSS 进行了扩充以及修改。与…

震惊!垃圾分类居然能用Python搞定!

目录 0 引言 1 环境 2 需求分析 3 代码实现 4 后记 0 引言 纸巾再湿也是干垃圾&#xff1f;瓜子皮再干也是湿垃圾&#xff1f;&#xff1f;最近大家都被垃圾分类折磨的不行&#xff0c;傻傻的你是否拎得清&#xff1f;???自2019.07.01开始&#xff0c;上海已率先实施垃圾分类…

java中 try用法,Java里try catch的简单用法

优质回答 回答者&#xff1a;temps1991Java里try catch的简单用法&#xff1a;1、trycatch程序的流程是&#xff1a;运行到try块中&#xff0c;如果有异常抛出&#xff0c;则转到catch块去处理。然后执行catch块后面的语句扩展部分&#xff1a;1、trycatchfinally程序的流程是&…

免费试用 Mobile Me

曾经尝试着注册过Mobile me&#xff0c;发现居然试用也要提供信用卡&#xff0c;而且地区选项里根本就没有中国&#xff0c;故愤然弃之。 今天忽然想再尝试一把&#xff0c;毕竟把mac、iphone&#xff0c;和即将到来的ipad连在一起是挺有意思的事情。 打开http://www.apple.com…

php call()函数,PHP中__call()方法详解

前面给大家介绍了《__construct()&#xff0c;类的构造函数》《__destruct()&#xff0c;类的析构函数》&#xff0c;下面继续给大家介绍PHP中__call()方法。__call()&#xff0c;在对象中调用一个不可访问方法时调用。该方法有两个参数&#xff0c;第一个参数 $function_name …

工作398-关于e.currentTarget.dataset的取值。

wxjs代码&#xff1a;GetAction: function (e) {var action e.currentTarget.dataset.action;console.log(action); //father}wxml代码&#xff1a;<view data-action"father" bindtap"GetAction"><image src"https://ss0.baidu.com/6ONWsj…

Postman: Test

Tests 参考&#xff1a;Writing Tests Testing examples 这里写测试用例&#xff0c;进行一些判断等等。即处理断言 下面新建了两个测试用例&#xff0c;名字分别是”Status code is 200“ 、”Status code name has string“。 “responseCode.code 200” 返回 True 或者 Fal…

nginx php怎么配置伪静态,nginx rewrite 伪静态配置参数和使用例子

正则表达式匹配&#xff0c;其中&#xff1a;* ~ 为区分大小写匹配* ~* 为不区分大小写匹配* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配文件及目录匹配&#xff0c;其中&#xff1a;* -f和!-f用来判断是否存在文件* -d和!-d用来判断是否存在目录* -e和!-e用来判断是否…

工作399-openType=“getUserInfo“ lang=“zh_CN“ bindgetuserinfo=“getUserInfo“

获取用户信息组件介绍组件变化&#xff1a;open-type 属性增加 getUserInfo &#xff1a;用户点击时候会触发 bindgetuserinfo 事件。新增事件 bindgetuserinfo &#xff1a;当 open-type 为 getUserInfo 时&#xff0c;用户点击会触发。可以从事件返回参数的detail字段中获取到…