深入理解abstract class和interface

轻松理解Java抽象类(Abstract Class) 抽象(Abstract)是Java面对对象编程(OOP)中很重要的一个概念,此文章简明的让读者理解抽象类的概念和简单应用。 阅读详情
abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。

理解抽象类

abstract class和interface在Java语言中都是用来进行抽象类(本文中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢?

在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。

在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。

从语法定义层面看abstract class和interface

在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。

使用abstract class的方式定义Demo抽象类的方式如下:


abstract class Demo {
	abstract void method1();
	abstract void method2();
	…
}

使用interface的方式定义Demo抽象类的方式如下:


interface Demo {
	void method1();
	void method2();
	…
}

在abstract class方式中,Demo可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。

对于abstract class和interface在语法定义层面更多的细节问题,不是本文的重点,不再赘述,读者可以参阅参考文献〔1〕获得更多的相关内容。

从编程层面看abstract class和interface

从编程的角度来看,abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。

首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。

其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。

在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。

同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。

从设计理念层面看abstract class和interface

上面主要从语法定义和编程的角度论述了abstract class和interface的区别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。

前面已经提到过,abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的(参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述,有兴趣的读者可以参考)。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。

考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:

使用abstract class方式定义Door:


	abstract class Door {
		abstract void open();
		abstract void close();
}

使用interface方式定义Door:


interface Door {
		void open();
	void close();
}

其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。

如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的解决方案,并从设计理念层面对这些不同的方案进行分析。

解决方案一:

简单的在Door的定义中增加一个alarm方法,如下:


	abstract class Door {
		abstract void open();
		abstract void close();
		abstract void alarm();
}

或者


interface Door {
		void open();
	void close();
	void alarm();
}

那么具有报警功能的AlarmDoor的定义方式如下:


	class AlarmDoor extends Door {
		void open() { … }
    		void close() { … }
		void alarm() { … }
}

或者


	class AlarmDoor implements Door {
	void open() { … }
    		void close() { … }
		void alarm() { … }
}

这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。

解决方案二:

既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。

显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。

如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。

如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:


	abstract class Door {
		abstract void open();
		abstract void close();
	}
interface Alarm {
	void alarm();
}
class AlarmDoor extends Door implements Alarm {
	void open() { … }
	void close() { … }
   	void alarm() { … }
}

这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。

结论

abstract class和interface是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细细体会。

参考文献
[1] Thinking in Java, Bruce Eckel
[2] Design Patterns Explained: A New Perspective on Object-Oriented Design, Alan Shalloway and James R. Trott
[3] Effective C++: 50 Specific Ways to Improve Your Programs and Design, Scott Meyers

关于作者
邓辉,软件工程师,主要兴趣在OO、Generic Programming。可以通过dhui@263.net联系到作者。
孙鸣,软件工程师,目前在一个大型通信公司从事数据网管的开发,主要兴趣在Java和数据库。可以通过dhui@263.net联系到作者。
抽象类(Abstract Class) 抽象方法是一种没有实现的方法,只有方法签名,子类必须提供具体实现。抽象方法使用abstract关键字定义,并且只能在抽象类中出现。非抽象方法具有具体实现,子类可以继承并使用这些方法,也可以重写它们。// 具体实现。 阅读详情

相关推荐

Revit实战:从零到一,手把手教你用族(Family)搭建一个完整的水闸BIM模型

本文详细介绍了如何使用Revit的族(Family)功能从零开始构建一个完整的水闸BIM模型。通过参数化族设计,实现闸门开度调整自动关联流量计算等智能化功能,提升水利工程BIM模型的工程价值和应用效率。文章涵盖族库规划、核心构件创建、高级技巧及BIM数据深度应用,为水利工程数字化提供实用指南。

weixin_28738165的博客 264

JavaSE16——抽象类(Abstract Class)

使用abstract关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。修饰符 abstract 返回值类型 方法名 (参数列表);抽象类用关键字"abstract"进行声明:在Java中,通过使用关键字"abstract"来声明一个抽象类。抽象类不能被直接实例化,只能作为父类被继承。抽象方法和非抽象方法:抽象类可以包含抽象方法和非抽象方法。抽象方法:没有具体实现的方法,只有方法声明,没有方法体。抽象方法必须使用关键字"abstract"进行声明。

tonyshi1989的博客 1238

3GPP Release与UE Category:无线通信标准演进与终端能力分级全解析

在蜂窝移动通信领域,技术标准的演进与终端设备的能力分级是理解整个产业发展的核心框架。其基本原理由国际标准组织3GPP通过周期性发布的技术规范版本(Release)来定义,每个Release都像一份阶段性的技术蓝图,规定了网络与终端应支持的新功能与性能基线。这种标准化机制的技术价值在于确保了全球设备的互联互通与网络的平滑升级,为从4G LTE到5G NR乃至未来的演进提供了清晰路径。在这一框架下,终端能力分级(如LTE时代的UE Category)是将标准转化为具体设备性能的关键环节,它直接定义了终端在射频和

weixin_34098209的博客 331

接口(Interface)和抽象类(Abstract Class)的区别是什么?

在Java中,接口(Interface)和抽象类(Abstract Class)都是用于定义类的蓝图,并为子类提供方法实现的基础。它们在设计和使用上有一些关键区别。

m0_57083961的博客 4057

2024年捡垃圾指南:E5 V3/V4服务器CPU怎么选?从游戏多开到深度学习,附华南X99主板搭配清单

本文详细解析2024年E5 V3/V4服务器CPU的选购策略,涵盖游戏多开、深度学习等多种应用场景。通过对比E5 V3与V4系列的制程、功耗及性能差异,提供高性价比的CPU型号推荐及华南X99主板搭配方案,帮助用户在有限预算下打造高效能工作站。

weixin_42549451的博客 1583

QT串口通信控制LED上位机开发教程

串口通信是嵌入式系统与PC端交互的基础技术,通过UART协议实现设备间的数据传输。QT框架提供了跨平台的串口编程支持,结合其GUI模块可以快速开发上位机控制程序。在工业自动化和物联网领域,这种上下位机架构广泛应用于设备监控和控制场景。本案例展示了如何使用QT的SerialPort模块实现LED控制功能,包含串口参数配置、指令发送等核心功能实现,为嵌入式GUI开发提供实践参考。

weixin_42598278的博客 582

Abstract Class抽象类

本文内容是抽象类的介绍

qq_68874993的博客 798

Java 类与对象 -- Java 语言的类与对象、构造器、static、final、包和 JAR

本篇文章我们将深入了解 Java 语言中的类与对象,探讨构造器、`static`、`final`、包和 JAR 文件。这些概念是面向对象编程的核心,对于理解和掌握 Java 至关重要。

栗筝i的博客 5037

net_lover(孟子E章) 的个性化书签

依次是正反面

蝈蝈俊.net 2145

《UDS协议从入门到精通》系列——图解0x23:通过地址读取内存

如何读取ECU中指定内存地址的数据?图解UDS 0x23服务带你快速上手!!

车载系统攻城狮 2623

DBC中如何实现报文传输类型属性的配置

AUTOSAR中CAN报文的传输类型主要有三种,周期型,事件型和混合型。周期型:按固定时间间隔自动发送,无需额外的触发条件。事件型:当信号值变化或满足内部条件时立即发送。混合型:默认按周期发送,但事件触发时可提前发送。

sunchengl的博客 304

XMLHTTP.Open Head 检测网络链接是否存在

 要检测链接的存在又不想把链接的文件全部加载过来..XMLHTTP.Open "Head",url,false可以实现。。相关代码:function checkStatus(url){XMLHTTP = new ActiveXObject("Microsoft.XMLHTTP")XMLHTTP.open("HEAD",url,false)XMLHTTP.send()return X

纯净的天空 1154

26届数字IC秋招笔试面试全攻略 - CPU基础架构-数字IC设计专家

本文介绍了CPU基础架构的三大关键技术:流水线、冒险处理和指令集设计。首先解析了经典五级流水线结构(取指、译码、执行、访存、写回)及其性能指标。其次详细阐述了三种流水线冒险(数据、控制、结构)及解决方案,如数据前递、分支预测等。最后对比了RISC与CISC指令集特点,并以RISC-V为例说明指令格式设计原则。全文系统梳理了CPU核心架构知识,为数字IC设计提供重要参考。

2301_79143213的博客 931

XMLHTTP.Open Head 检测网络链接是否存在..

要检测链接的存在又不想把链接的文件全部加载过来..XMLHTTP.Open "Head",url,false可以实现。。相关代码:function checkStatus(url){XMLHTTP = new ActiveXObject("Microsoft.XMLHTTP")XMLHTTP.open("HEAD",url,false)XMLHTTP.send()return XMLH

轻灵自由的珍珠 4382

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

showModalDialog()、showModelessDialog()方法使用详解(net_lover)

Javascript有许多内建的方法来产生对话框,如:window.alert(), window.confirm(),window.prompt().等。 然而IE提供更多的方法支持对话框。如:  showModalDialog() (IE 4+ 支持)  showModelessDialog() (IE 5+ 支持) window.showModalDialog()方法用来创建一个显示

经典草根Blog 707

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

社区英雄榜:谁是真正的技术英雄?

MVP评选开始了,欢迎大家给你心目中最有价值的专家啊投票... 投票地址:http://www.csdn.net/community2006/vote/index.rails?id=2最近和BBS的负责人小谢一起在筹备优快云 社区的风云榜,我们俩一整理就发现优快云的牛人真是不少,邹建第一名总专家分779559分,思归第二名总专家分655789,上十万分以上的专家总共有35个,虽然对我来

产品研习所 1万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Java中抽象类 abstract和interface的区别

abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。 abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于 abstract class和interface的选择显得比较随意。 其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们

Don't Look Down的博客 3308

Java之抽象类(Abstract Class)与抽象方法(Abstract Method)

抽象类(Abstract Class)抽象类        在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。        抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。       由于抽象类不能实例化对象,所以抽象类必...

PythonGo 5万+

抽象类(abstract class)

若父类是抽象类,且子类不想成为抽象类,则子类必须将父类中的所有抽象方法重写为带方法体的普通方法,否则子类仍必须是抽象类。不论抽象类是否含抽象方法,其都不允许实例化,即不能创建抽象类的对象,因为其描述的是抽象概念。它只能作为其他类的基类。抽象方法:通过abstract关键字将getArea方法修饰为抽象的,此时的方法称为抽象方法。抽象类可以包含抽象方法,这些方法将在具体的子类中实现。抽象方法是出现在基类中的一种方法,但要求在派生类中被重写。抽象类可以含零至多个普通方法,也可以含零至多个抽象方法。

2303_76659931的博客 523

浅谈Java中抽象类(abstract class)的使用

抽象是Java语言一个很重要的特性,可以通过两种方式来体现,其中一种方式就是抽象类。在Java类中,如果一个类没有包含足够的信息来描绘一个具体的对象,那么这样的类就是抽象类。本文根据对Java面向对象的学习理解,浅谈了抽象类定义及使用,然后给出一个代码案例来说明,最后做出总结。

m0_68181332的博客 3734

Java——抽象类

abstract class 抽象类名{//数据成员//构造方法[访问权限} 返回值类型 方法名 {形参列表}{ //普通方法//方法体[return返回值][访问权限] abstract 返回值类型 方法名 {形参列表};//抽象方法,无方法体Java程序对抽象类的要求如下。(1)抽象类中可以有零个或多个抽象方法,也可以包含非抽象方法。下面代码段,定义抽象类Person、普通方法talk()和抽象方法worrkOn()。抽象方法workOn()仅有声明,而没有方法体。

2301_81768120的博客 1089

使用abstract修饰的抽象类

使用abstract修饰的抽象类

qq_60030399的博客 563

abstract class php,php中abstract class和interface定义和用法详解

一、抽象类abstract class1.抽象类是指在class前加了abstract关键字且存在抽象方法(在类方法function关键字前加了abstract关键字)的类。2.抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。子类可以通过继承抽象类并通过实现抽象类中的所有抽象方法,使抽象类具体化。3.如果子类需要实例化,前提是它实现了抽象类中的所有抽象方法。如果子类没有全部实现...

weixin_39578516的博客 324

【Java第21集】java抽象类(Abstract Class)详解

abstract class 类名 {// 可以包含成员变量、构造方法、具体方法和抽象方法abstract void 抽象方法名();// 抽象方法没有方法体抽象类通过抽象方法定义一组子类的共同行为契约,要求子类必须实现这些方法。示例// 抽象方法:所有动物必须实现的接口// 具体方法:所有动物共享的行为抽象方法必须使用abstract关键字修饰,且没有方法体(即没有{}抽象方法的访问权限不能是private,因为子类无法继承私有方法。抽象方法不能是static。

学不可以已,活到老,学到老。 2189

接口(Interface)和抽象类(Abstract Class)的区别和用法

接口(Interface)和抽象类(Abstract Class)是面向对象编程中的两个概念,用于实现多态性和封装性。它们有一些相似之处,但也有一些关键的区别。在这个例子中,接口Drawable定义了一个draw方法,Circle和Rectangle类分别实现了这个接口,并提供了各自的draw方法的具体实现。在Main类中,我们可以创建Circle和Rectangle对象,并调用它们的draw方法。在这个例子中,抽象类Shape定义了一个抽象的draw方法和一个具体的方法。Circle和。

m0_68856746的博客 991

抽象类与抽象方法详解

本文围绕 Java 中的抽象类与抽象方法展开。抽象类用 abstract 关键字修饰,不能实例化,可含抽象与具体方法,目的是为子类提供通用模板和结构。抽象方法也用 abstract 修饰,无方法体,必须在子类中重写。通过示例展示了抽象类和抽象方法的用法,以及在游戏、交通工具等场景的应用。对比抽象类与接口,在继承实现方式、方法类型、成员变量、构造方法、访问修饰符、设计语义、典型用途等方面存在差异。同时指出抽象类使用时需注意构造方法调用、静态方法不可重写等事项。强调抽象类和抽象方法能构建灵活可扩展的代码结构,符

m0_73941339的博客 2303
下一篇: 当前流行的J2EE WEB应用架构分析
samsummer
博客等级 码龄22年 0粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值