首页 > 如果类A继承了一个抽象类B(抽象类B已经实现了接口C),为什么还要实现接口C呢?

如果类A继承了一个抽象类B(抽象类B已经实现了接口C),为什么还要实现接口C呢?

1、问题描述
如果类A继承了一个抽象类B(抽象类B已经实现了接口C),为什么还要实现接口C呢?

2、举例
抽象类AbstractMap已经实现了接口Map,HashMap继承了AbstractMap为什么也还要实现接口Map?


public abstract class AbstractMap<K,V> implements Map<K,V> {

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

如果 hashmap 不自己实现 map 接口 abstractmap 因为是抽象类,即使不实现 map接口内的方法 编译也过的去。那么问题来了,如果hashmap 不实现 map接口 , map 接口中的 方法 有可能是不被实现的


Java中ArrayList的继承体系疑惑
这个是我很久之前提得问题,和题主的类似。
和@代码宇宙 的解释(1)差不多

PS:被采纳的答案里面的链接


首先语法上,这么写是没什么问题;
可能作者为了代码阅读方便,直接打开HashMap的定义就能看到其实现了Map接口,而无需要再到AbstractMap里去确认。
另外,即便HashMap又声明一次implements Map,如果有些方法已在AbstractMap里实现,HashMap也无需再重新实现的。


虽然抽象类B implements C.但是,有可能B中的并没有真正实现C接口中的方法--因为B是抽象类,抽象类可以不实现接口中的方法,而是直接用 abstract 修饰。如 abstract void method();
那么,由于A extends B, 而 A不是抽象类,那么A就得完全实现 method()方法了。


看了 牧曦之晨 给出的链接,感觉上面的回答也没有讲清楚这个问题,不过我基本同意这样写是为了清晰这个观点。但是在这里我想补充一点我的想法。

首先,在语法上,无论写不写implements Map<K, V>都是没有问题的,而且效果是一样的。所以剩下的可能性只有2个:

  1. 为了代码上和语义上更加清晰

  2. HashMap的程序员一不小心多加了这么一句

先说结论:我以为,这两种可能性都有,但是(1)的可能性更大一些。

首先来看看(1)。为什么加了这一句才清晰?继承了AbstractMap还不够清晰吗?毕竟后者本身就是实现了Map的啊!

先来看看AbstractMap的文档,在该类文档的第一句就说:

此类提供 Map 接口的骨干实现,以最大限度地减少实现此接口所需的工作。 

也就是说,这个类是一个便捷类,它的存在主要是为了方便使用者,以减少必须的编码工作的。类似的例子还有java.awt.event中的几个XXXAdapter类,但是它们更加纯粹——AbstractMap多少还有点语义,但XXXAdapter仅仅只是为了方便程序员而已(其的方法都是空的)。

另一方面,实现了Map以及Map的子接口的类有很多,包括HashMapTreeMapWeakHashMapConcurrentHashMapLinkedHashMap等等,它们基本上都继承自AbstractMap或其子类,但同时却具有不同的特性。而这些决定了它们的应用场景和适用范围的特性主要并不是来自于AbstractMap,而是来自于它们实现的接口,以及自身的具体实现。

例如HashMap实现的是Map,配合它的名字,我们可以知道这是一个利用哈希表实现的MapTreeMap实现的是NavigableMap,配合它的名字,我们可以知道这是一个利用树实现的可导航的(可遍历的)Map,等等。所以对于这些Map类,我们只需要看它的名字,再看看它们实现的接口,就能大概知道它们采用的数据结构和主要特性。而继承AbstractMap这件事在这种情况下则可以忽略,仅仅将其作为一种减少繁复劳动的手段即可。

再来看看(2)

前面也说了,java.util包下面各种XXXMap类有很多,它们中绝大部分都继承自AbstractMap,同时又实现了Map接口的某个子接口。因此它们大部分都有如下这种共通的格式:

public class XXXMap<K,V>
    extends AbstractMap<K,V>
    implements YYYMap<K,V>, Cloneable, Serializable

作为程序员应该最能理解遇到这种情况时会如何处理了吧:C&P大法好啊!拷贝一下,改改类名和实现接口,多方便,呵呵。

当然前面也说了,这种猜测的可能性是比较小的,至少我是这么认为的。


在 Java 中接口最大的作用是表意,表示这个类拥有哪些方法可以被其他类调用,其次才是接口方法的实现。这里通过显示的标记 Map 接口,其实是为了方便大家了解 HashMap 拥有 Map 接口中所定义的方法,这些明确的标记有时候是通过继承链很难直观体现的。

举个例子,Object 类中就 clone 方法,也就是说 clone 并不需要其他接口来实现,但是所有可以克隆的对象又必须实现 Cloneable 接口,这个接口在定义和实现上来说没有任何必要性,就仅仅是为了表意这个类的对象可以被克隆。与之相似的还有 Serializable 等接口,他们都是没有任何需要实现的方法,仅仅是为了表示类拥有一个特别的属性而已。


基类实现了接口后,子类也就相当于实现了这个接口。

【热门文章】
【热门文章】