抽象类不允许多继承(什么情况下使用抽象类)

本文目录
什么情况下使用抽象类
在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了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可以有自己的数据成员,也可以有非 abstract的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final 的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的 abstract class。
从编程的角度来看,abstract class和interface都可以用来实现 "design by contract" 的思想。但是在具体的使用上面还是有一些区别的。
首先,abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系(因为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所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。
前面已经提到过,abstract class在Java语言中体现了一种继承关系,要想使得 继承关系合理,父类和派生类之间必须存在"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 Principle),在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 Alarm Door extends Door implements Alarm{
void open(){…}
void close(){…}
void alarm(){…}
}
这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其 实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。
小结
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
7.接口中的方法默认都是 public,abstract 类型的。
结论
abstract class 和 interface 是 Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概 念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细细体会。
我认为他讲的比较到位才复制来的..分可以不要,但是东西对你有用就行了么
JAVA抽象类、接口继承的疑惑
抽象类b实现接口a,他可能没有完全实现a的方法。b可以有自己的新方法。
c类继承接口a,他可以获得a里面所有的抽象方法,常量属性,内部类,枚举等等。
d继承b同时实现c,就是吧上面两个情况综合一下,
如果b实现a的某方法,那么d中调用的就是b实现的这个,如果b中没实现a的方法,d中也可以访问a的这个方法。所以d可以实现a的方法,也可以有b里的新方法。
我说的不太明白,你自己写几个类和接口看一下就知道了
java 抽象类能不能继承接口
可以继承的。接口里的方法没有方法体,而抽象类继承接口后,默认没有实现那个方法,即抽象方法,完全符合逻辑
好像是不能的。抽象类可以被继承(extends),接口可以被实现(implements),但是抽象类不能被实现(implements),接口貌似只能被接口继承(extends)
java中一个接口可以继承几个接口吗
可以,接口是常量值和方法定义的集合,是一种特殊的抽象类,可以继承多个接口。例如:Interface3 Extends Interface0, Interface1, interface……。
java接口解析如下:
在Java中,定义一个接口的形式如下:
interface InterfaceName {
}
接口中可以含有变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量,而方法会被隐式地指定为public abstract方法且只能是public abstract方法,并且接口中所有的方法不能有具体的实现、
也就是说,接口中的方法必须都是抽象方法。
要让一个类遵循某组特地的接口需要使用implements关键字,具体格式如下:
class ClassName implements Interface1,Interface2,{
}
可以看出,允许一个类遵循多个特定的接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。
扩展资料:
java继承接口的特性:
1)一个类如果实现了一个借口,则要实现该接口的所有方法。
2)方法的名字、返回类型、参数必须与接口中完全一致。如果方法的返回类型不是void,则方法体必须至少有一条return语句。
3)因为接口的方法默认是public类型的,所以在实现的时候一定要用public来修饰(否则默认为protected类型,缩小了方法的使用范围)。
百度百科--java接口
抽象类的特点
抽象类的特点:
1. 抽象类不能被实例化,只能被继承;
2. 抽象类可以包含抽象方法和非抽象方法;
3. 抽象类可以定义抽象属性;
4. 抽象类可以被多继承。
拓展:
1. 抽象类可以提供一个通用的骨架,子类可以根据需要实现父类中定义的抽象方法;
2. 抽象类可以提供统一的接口,实现代码的重用,提高了程序的可维护性;
3. 抽象类可以提供默认的行为,子类可以根据需要进行重写;
4. 抽象类继承关系可以多层,但是每一层只能有一个父类。Netname: AbstractThinker
抽象类和接口的相同点与不同点
一、两者相同点
1、不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类里的抽象方法必须全部被子类所实现,子类不能全部实现父类抽象方法,那么该子类还只能是抽象类。一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
二、两者不同点
1、默认的方法实现
抽象类可以有默认的方法实现;接口,Java8规定可以为接口提供默认实现的方法并且不用强。
2、实现
制子类来重写子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要重写抽象类中的抽象方法;接口子类使用关键字implements 来实现接口,它需要重写接口中没有默认。
3、构造器
抽象类可以有构造器,接口不能有构造器。
4、与正常Java类的区别
除了不能实例化抽象类之外,和普通Java类没有任何区别;接口是完全不同的类型外。
5、访问修饰符
抽象方法可有public.protected和default、abstract修饰符。不能用privatestatic.synchronize、 native 修饰;
接口属性默认修饰符是publicstatic final (必须赋初值) ,方法默认修饰符是publicabstract. Java8 开始出现静态方法,多加static关键字。
6、main方法
并且可以运行它;接口没有main方法,因此不能运行它。
7、多继承
抽象类可以继承一个类和实现多个接口;接口只可以继承一个或多个接口。
8、速度
抽象类比接口速度快;接口是稍微有点慢,因为它需要花时间去寻找在类中的实现方法。
9、添加新方法
如果往抽象类中添加新的方法,可以给它提供默认的实现,不需要改变现代码;如果往接口中添加方法,并且该方法没有默认实现,必须改变实现该接口的类。
扩展资料:
抽象类的运用意义
在面向对象方法中,抽象类主要用来进行类型隐藏。构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。
这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。
由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。
为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。
为什么抽象类不能多继承
...因为java就是这么设定的..也许是因为抽象类还不够抽象..这样也更符合个人理解,一个人只能有一个爹..
另外,java中的类允许实现多个接口(也许是因为接口相对于抽象类,更加抽象)..

更多文章:
两张表格vlookup怎么用函数(vlookup函数如何两张表匹配)
2025年11月3日 23:45
available怎么记(availability和available怎么区分怎么用)
2025年10月30日 07:45
instragm(instragm华为手机怎么下载华为应用市场内找不到App,请求大家分享)
2026年3月14日 03:15
access集团待遇怎么样(杭州access集团待遇怎么样)
2025年12月26日 18:15
如何在数据上直接使用round函数(excel中ROUND函数怎么用)
2026年2月17日 20:15
从一段文字中提取日期(excel中的一段文字,我想提取对话中的日期,这个该怎么提取啊 举例:如图)
2026年2月17日 10:00
jdkwin7环境变量配置(Win7系统如何设置添加Java环境变量)
2026年2月17日 05:30
asp网站上传文件大小限制(asp网站的上传文件在本地测试正常,上传到空间后,却上传不了大文件,是空间限制了吗,怎么改谢谢)
2026年8月8日 07:00
三菱plc程序中k0 编写(三菱plc编程ko加线头怎么输入)
2026年1月17日 20:00
vuerouter只能用于vue吗(简单说说如何使用vue-router插件的方法)
2025年10月16日 22:15
closer歌曲简谱(求chainsmokers的closer简谱)
2025年9月24日 04:15










