问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Java中的抽象类与接口介绍

发布网友 发布时间:2024-09-30 14:15

我来回答

1个回答

热心网友 时间:2024-10-30 21:50

在Java中什么时候应该选择抽象类而不是接口?接受挑战吧!了解这些Java语言元素之间的区别以及如何在你的程序中使用它们。

在Java代码中,甚至在Java开发工具包(JDK)本身中,都有大量的抽象类和接口。每个代码元素都有一个基本的目的:

接口是一种代码契约,必须由一个具体的类来实现。

抽象类与普通类相似,不同的是它们可以包括抽象方法,也就是没有主体的方法。抽象类不能被实例化。

许多开发者认为接口和抽象类是相似的,但它们实际上是完全不同的。让我们来探讨一下它们之间的主要区别。

接口的本质

从本质上讲,接口是一个契约,所以它依赖于一个实现来达到其目的。一个接口永远不可能有状态,所以它不能使用可变的实例变量。一个接口只能使用最终变量。

何时使用接口

接口对于解耦代码和实现多态性非常有用。我们可以在JDK中看到一个例子,就是List 接口:

publicinterfaceList<E>extendsCollection<E>{intsize();booleanisEmpty();booleanadd(Ee);Eremove(intindex);voidclear();}

正如你可能注意到的,这段代码很短,而且描述性很强。我们可以很容易地看到方法的签名,我们将用一个具体的类来实现接口中的方法。

List 接口包含一个契约,可以由ArrayList,Vector,LinkedList, 和其他类来实现。

为了使用多态性,我们可以简单地用List 来声明我们的变量类型,然后选择任何一个可用的实例化。这里有一个例子:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());

下面是这段代码的输出:

classjava.util.ArrayListclassjava.util.LinkedList

在这种情况下,ArrayList,LinkedList, 和Vector 的实现方法都是不同的,这就是使用接口的一个很好的场景。如果你注意到许多类都属于一个父类,其方法动作相同,但行为不同,那么使用接口是个好主意。

接下来,让我们来看看我们可以用接口做的几件事。

重写一个接口方法

记住,接口是一种必须由具体类来实现的契约。接口方法是隐含的抽象的,也需要一个具体类的实现。

这里有一个例子:

publicclassOverridingDemo{publicstaticvoidmain(String[]args){Challengerchallenger=newJavaChallenger();challenger.doChallenge();}}interfaceChallenger{voiddoChallenge();}classJavaChallengerimplementsChallenger{@OverridepublicvoiddoChallenge(){System.out.println("Challengedone!");}}

下面是这段代码的输出:

Challengedone!

注意这个细节,接口方法是隐式抽象的。这意味着我们不需要明确地将它们声明为抽象的。

常量变量

另一条要记住的规则是,一个接口只能包含常量变量。因此,下面的代码是可以的:

publicclassChallenger{intnumber=7;Stringname="JavaChallenger";}

注意,这两个变量都是隐含的final 和static 。这意味着它们是常量,不依赖于一个实例,而且不能被改变。

如果我们试图改变Challenger 接口中的变量,例如,像这样:

Challenger.number=8;Challenger.name="AnotherChallenger";

我们会触发一个编译错误,像这样:

Cannotassignavaluetofinalvariable'number'Cannotassignavaluetofinalvariable'name'缺省方法

当默认方法在Java 8中被引入时,一些开发者认为它们会和抽象类一样。然而这并不正确,因为接口不能有状态。

默认方法可以有一个实现,而抽象方法则不能。默认方法是lambdas和流的伟大创新的结果,但我们应该谨慎使用它们。

JDK中使用默认方法的一个方法是forEach() ,它是Iterable 接口的一部分。我们可以简单地重用forEach 方法,而不是将代码复制到每个Iterable 的实现中:

defaultvoidforEach(Consumer<?superT>action){//Codeimplementationhere…

任何Iterable 实现都可以使用forEach() 方法,而不需要新的方法实现。然后,我们可以用一个默认方法来重用代码。

让我们来创建我们自己的默认方法:

publicclassDefaultMethodExample{publicstaticvoidmain(String[]args){Challengerchallenger=newJavaChallenger();challenger.doChallenge();}}classJavaChallengerimplementsChallenger{}interfaceChallenger{defaultvoiddoChallenge(){System.out.println("Challengerdoingachallenge!");}}

下面是输出结果:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());0

关于默认方法,需要注意的是,每个默认方法都需要一个实现。默认方法不能是静态的。

现在,让我们继续讨论抽象类。

抽象类的本质

抽象类可以有实例变量的状态。这意味着一个实例变量可以被使用和变异。这里有一个例子:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());1

下面是输出结果:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());2抽象类中的抽象方法

就像接口一样,抽象类可以有抽象方法。抽象方法是一个没有主体的方法。与接口不同,抽象类中的抽象方法必须明确地声明为抽象的。这里有一个例子:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());3

试图声明一个没有实现的方法,而且没有abstract 关键字,像这样:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());4

导致了一个编译错误,像这样:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());5什么时候使用抽象类

当你需要实现可改变状态时,使用抽象类是一个好主意。作为一个例子,Java集合框架包括AbstractList类,它使用变量的状态。

在你不需要维护类的状态的情况下,通常使用一个接口更好。

实践中的抽象类

设计模式中的模板方法是使用抽象类的好例子。模板方法模式在具体方法中操作实例变量。

抽象类和接口的区别

从面向对象编程的角度来看,接口和抽象类的主要区别是,接口不能有状态,而抽象类可以用实例变量来有状态。

另一个关键区别是,类可以实现一个以上的接口,但它们只能扩展一个抽象类。这是一个基于多重继承(扩展一个以上的类)会导致代码死锁的设计决定。Java的工程师们决定要避免这种情况。

另一个区别是,接口可以被类实现,也可以被接口扩展,但类只能被扩展。

还需要注意的是,lambda表达式只能用于功能接口(指只有一个方法的接口),而只有一个抽象方法的抽象类不能使用lambdas。

接受Java代码挑战吧!

让我们通过一个Java代码挑战来探索接口和抽象类的主要区别。我们在下面提供了代码挑战,你也可以用视频的形式观看抽象类与接口的挑战。

在下面的代码中,同时声明了一个接口和一个抽象类,而且代码中还使用了lambdas:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());6

你认为当我们运行这段代码时,会发生什么?请从下列选项中选择一个。

选项AListlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());7选项BListlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());8选项CListlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());9选项Dclassjava.util.ArrayListclassjava.util.LinkedList0选项Eclassjava.util.ArrayListclassjava.util.LinkedList1Java代码挑战视频

你为这个挑战选择了正确的输出吗?请观看视频或继续阅读以了解答案。

了解接口和抽象类及方法

这个Java代码挑战展示了许多关于接口、抽象方法等的重要概念。逐行浏览代码会让我们了解到输出中发生的很多事情。

代码挑战的第一行包括Zombie 接口的lambda表达式。请注意,在这个lambda中,我们正在增加一个静态字段。实例字段在这里也可以使用,但在lambda之外声明的局部变量就不行了。因此,到目前为止,这段代码可以正常编译。还要注意的是,lambda表达式还没有执行,所以nemesisRaids 字段还不会被递增。

在这一点上,我们将打印nemesisRaids 字段,它没有被增加,因为λ表达式还没有被调用,只是被声明。因此,这一行的输出将是:

classjava.util.ArrayListclassjava.util.LinkedList2

这个Java代码挑战中另一个有趣的概念是,我们正在使用一个匿名的内层类。这基本上意味着任何将实现Nemesis 抽象类的方法的类。我们并没有真正实例化Nemesis 抽象类,因为它实际上是一个匿名的类。还要注意的是,第一个具体的类在扩展它们的时候总是有义务实现抽象的方法。

在Zombie 接口里面,我们用一个lambda表达式声明了zombie static Zombie 接口。因此,当我们调用zombie shoot 方法时,我们会打印以下内容:

classjava.util.ArrayListclassjava.util.LinkedList3

下一行代码调用了我们在开始时创建的lambda表达式。因此,nemesisRaids 这个变量将被递增。然而,由于我们使用的是后增量运算符,它将只在这条代码语句之后被增量。接下来的输出将是:

classjava.util.ArrayListclassjava.util.LinkedList4

现在,我们将从nemesis 中调用shoot 方法,这将改变其shoots 实例变量为23 。 注意,这部分代码展示了接口和抽象类之间的最大区别。

最后,我们打印nemesis.shoots 和nemesisRaids 的值。因此,输出结果将是:

classjava.util.ArrayListclassjava.util.LinkedList5

综上所述,正确的输出是选项C:

Listlist=newArrayList();System.out.println(list.getClass());Listlist=newLinkedList();System.out.println(list.getClass());9
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
光猫的注册灯一直闪没有网是怎么回事 ...PSP3000播放不起MP4格式的视频 我是6.60系统,PPA也放不起。还有就... AVC无法播放 PSP的电影,我放在相应的文件夹里,播放器也有.怎么还不行? psp ppa 无法播放 S1铁路啥意思 农历八月十五出生男孩名字 T-46轻型坦克参数资料(取自坦克世界) 美丽加芬有卸妆液吗 为什么股票涨跌很快 微信理财通收益计算 epson r230怎样换墨盒呀? 一台EPSONSTYLUS230打印机可以同时更换两种墨盒吗? 华为荣耀7桌面的文件夹总是冒出那些要你下载的APP,删除了又有,怎么回... 刚到手的华为荣耀7,桌面上的图标怎么这么难看,灰蒙蒙的感觉,可以设置吗... 华为荣耀7为什么密码设置完以后,再次使用的时候怎么自动进入主页面_百 ... qq音乐哪有人工客服qq音乐人工服务在哪 how New York become America's largest city 全文翻译 纽约east 2nd street,new york,new york,united states 在哪_百度... 怎样联系QQ音乐人工客服解决问题? 根据所给的英文提示,比较两个城市,写一篇英语短文,词数50左右、 qq音乐找人工客服怎么找? New York is ___ the east coast of America. A. on B. in C. to D... New York is in the east of Amreica是什么意思 孩子玩手机如何控制时长,有没有什么办法? 男人就是得舍得花钱,才能够赚到更多的钱? 一副扑克去小王与大王,任取1张拿到红桃可能性( )拿到10可能性( )拿到... 一副扑克牌,其排列顺序是:第一张是大王,第二张是小王,然后是按A,2,3... 淘宝买家给了差评.卖家已经给了评价,还能不能改这个差评 为什么基金要偷吃 SpringBootMongo自增长ID有序规则 collection是什么意思中文翻译 为什么老是做梦,梦见我女朋友嫁给别人了? 波斯王子3的安装方法,求2高手帮忙,我不会啊 波斯王子3安装后怎样运行? 波斯王子3PC版迅雷下载压缩包后解压了安装了又说要虚拟光驱又说要模拟... 波斯王子3安装问题 道路交通法律法规手册目录 发生交通事故后如何定损 以太网无法连接internet,我就重置了网络,结果wifi和以太网都没有了... ...+影驰GTS450黑将+金士顿DDR3 1333 4G 请问需要配多少大的电源... ...但后来变得很红,很大的包,剧痒,又不敢抓,求救~ ...为什么现在卖霪的到处都是,那些扫黄大队的是不是拿着国家公务员的工... ...酒店。 今天早上联系不上了,看了监控是被扫黄大队的带走了,可是_百 ... 我是94年开始从教,96年办理教师资格证没我的,为什么? 什么是弹道导弹和洲际导弹啥是弹道导弹和洲际导弹 免费的logo设计 如何在相机里面加入自定义水印? ai怎么添加自己名字的水印ai怎么设计名片 未到期的三年劳动合同可以辞职吗?