c语言实现java接口_从Java中ArrayList继承的AbstractList类以及实现的List接口我们看到了什么?...

bbe75b5507d0da44d13db5a10ee47f18.png

其实这个话题,

本意没想要单独作为一篇文章来叙述,

咱们在上一篇跟踪java集合源码的时候,

其实是给大家留了个口,

原本是想让同学们提出来,

然后有问有答,

想着怎么也比我一人傻呵呵说效果好,

但这两日我实在等不及啦,

想来也没多少可说的,

索性我就主动点儿,

今天把这事儿给办了...


从何说起

到底咱们上文是留了个什么口呢?

大家是否还有印象,

咱们再说集合的【源码跟踪】的环节时,

ArrayList类举的例子,

(如下图示):

a1ed591d609b38bc41d26945cd4e1df5.png

来看上图红色框框圈起来的位置,

它继承了抽象类AbstractList类 ,

同时实现了List接口,

这无可厚非,

我们继续深入一层,

来看看AbstractList类,

(如下图示):

65b00d3674912f3658f0e7d4064706e2.png

我们发现AbstractList类在继承了AbstractCollection抽象类,

也同样实现了List接口,

子类为什么会重复继承(实现)父级已继承(实现)的接口(抽象类)呢

这不是多余了吗?

我们都知道继承关系有传递性

传递性是啥意思呢?

为了加深理解,

我们先来写一个简单例子,

传递性示例

咱们先创建一个【爷爷】类,

设置一个属性并编写一个方法,

方法很简单,

就是夹带着属性在控制台打印一句话,

(如下图示):

a0e6c5cac0842afc16196fb73f2d6a0a.png

然后创建一个【父】类,

只让它继承【爷爷】类,

类里面啥事儿也不做,

(如下图示):

4e7a30ff9a5cab9b7355d20da8b4f062.png

最后我们再创建一个【儿子】类,

此类里也只继承【父】类,

同样什么也不写,

(如下图示):

89315320eb1137fa3e3f4d727bf05980.png

接下来验证下继承关系的传递性,

我们创建一个main函数,

然后在此函数体内,

实例化【儿子】(son类)并赋值,

(如下图示):

02bc7fcfc72dc9bd7424a90e5168022c.png

从上图我们可以看到,

实例化后的子类可以调用属性和方法,

并且能正确执行并打印出我们想要值,

这就证明继承关系是有传递性的。


举例说明

问题又回到开始,

“ArrayList类的父级AbstractList抽象类已经实现过了List接口,

为什么ArrayList还要再次实现List接口”?

为什么java源码里会重复继承(实现)呢?

要说明这个问题,

首先我们要搞明白

抽象类接口的用法,

我们都知道接口的意义在于,

定义了一种规范,一种标准

不做具体实现,

(当然JDK 1.8及以后的版本,接口有了默认和静态方法,这就另说啦);

所有继承接口的子类都要一 一实现它的所有方法,

这可能就是为什么继承类用关键字“extends”,
继承接口要用“implement”关键字吧?

既然要实现接口的所有方法就存在一个问题,

不是所有要继承接口的子类都能用到接口里的全部方法

对于继承接口那些用不到的方法也需要实现了它,

这不就造成了代码的重复嘛!

那么怎么解决这个问题呢?

我们可以只让一个类去实现这个接口,

然后其他的类继承这个类就好了嘛。

可能有同学联想到模板,

对,这就是抽象类设计时其中的一种定义,

抽象类就是一种模板式的设计

这么说可能太苍白,

理解起来不够直观,

让我们来再写个简单的例子,

示例辅助说明

我们首先创建一个接口,

(如下图示):

5373a7ebdb0dd0216af7d6e59eca30a6.png

再接下来我们在创建一个抽象类,

(如下图示):

c2c42e1fa836e4a71b3fac98ff4d92f9.png

我们在测试类里继承一下,

分别看看效果,

先来继承(implements)下接口,

(如下图示):

b324c79df0f5cdbe44d4ab5e1328f194.png

发现继承接口后程序报错了,

我们将鼠标放到红色波浪线看下错误提示,

需要我们将接口内的方法给实现喽

那我们根据提示将方法salad()实现一下,

(如下图示):

977c1241826c4b1730e33c8b48f98802.png

我们发现报错并未解除,

我们点开提示发现,

(如下图示):

ca0245f241a262e70c1d8d75b83ac3ac.png

根据上图我们看到继承了接口后,

如果不实现接口里方法就会报错,

并提示我们有4个方法待实现,

实现全部方法后的样子,

(如下图示):

10bf208a6c9c330c759e8b8708e6f4da.png

我们发现这个时候异常算是解除啦…

那么抽象接口呢?

(如下图示):

d25438a0dadeea2e5f9a6076987d514f.png

我们它没有报任何错误…

并且我们可以根据我们的需求,

实现我们想要实现的方法即可,

比如我们实现salad()方法,

(如下图示):

43092facc38a703ac7b4cecb32653b15.png

没有任何的问题….

假如我们有个需求,

除了使用TomatoAbstract里的cooking()方法,

还需要使用FruitInterface里的eat()方法,

按照以往的方式,

我们会这么用,

(如下图示):

547aad210fc7f08e2e867226c7f00f10.png

可我们只需要用到(标红)两个方法,

就不得不实现那些我们用不到的方法...


解决问题

我们根据上文的分析可以将代码调整下,

或许能解现在的尴尬问题,

我们先进入到TomatoAbstract抽象类,

做如下改动,

(如下图示):

c69bc20f205ea2bdbac4cb2075de807c.png

将我们不需要使用的方法,

size()、name()等先在抽象类中实现

然后切换到我们需要使用的抽象类的方法中,

继承这个TomatoAbstract模板(抽象)类,

(如下图示):

b5f670fd61e09b94bf41b05eac2983c7.png

我们发现目前必须要实现的方法只有一个eat(),

实现后我们再来看,

(如下图示):

19464dd406c07f06ab9f56373fd6fd15.png

报错的现象已经解除,

并且此方法也是我们需要使用的方法,

这时候你会说我们用到的还有一个cooking()方法呢?

这个时候我们手动将它实现即可,

(如下图示):

54414fc92a443e14875dfe8f55100590.png

改造后代码是不是简洁、优雅多啦,

这样不仅避免了重复代码、耦合性也更低啦;


为什么会重复继承

有同学可能会说,

这也没有说明白JDK源码里为什么要重复继承的问题啊?

其实JDK源码里之所以重复引用

更类似于一种编码规范

为什么这么说呢?

以我们的demo为例,

(如下图示):

200b6bb71736ddc230e0a72ec4da38e3.png

从上图我们只能看到此类继承了抽象类TomatoAbstract,

不能直观的看出eat()方法实现自FruitInterface接口,

所以为了规范我们代码应该改成,

(如下图示):

f581aac77c5ba6b81ed8894e9a0d08d2.png

这样我们就能很容易判断...

以上这两个函数分别继承自FruitInterface 接口和 TomatoAbstract抽象类。

OK啦!!!!

你:就这?

我:就这...

hahahahahaha......

下一篇见…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值