是否应该在子类中显式实现从基类继承的接口?

时间:2008-12-12 13:45:59

标签: java interface contract

我的问题是,如果通过扩展已经实现它的类隐式实现的接口,应该由类显式实现,如果类想要通告该事实,则它满足该接口的契约。

例如,如果你想编写一个类,那就完成了接口java.util.List的约定。您实现了这一点,扩展了已经实现接口java.util.AbstractList的类List。你明确声明你实现了List吗?

public class MyList extends AbstractList implements List

或者您是否使用隐式方式保存输入?

public class MyList extends AbstractList

哪种方式被认为是更好的风格?你有什么理由喜欢这种或那种方式?在哪种情况下,您更喜欢方式1还是方式2?

12 个答案:

答案 0 :(得分:12)

避免冗余。使用方法2.

使用@Override进行覆盖。

答案 1 :(得分:7)

这不是一个“风格”问题。如果要扩展已实现List的AbstractList,则不需要显式实现List。

这不仅仅是一个保存打字的问题。由于额外的“工具列表”是多余的,有人可能会花一些时间试图找出它存在的原因。你本质上是在写一个已经成为语言一部分的保证。

答案 2 :(得分:4)

我问this same question long ago on my blog。如果你有兴趣看到别人的想法,那里也会有很长的讨论。值得注意的是,这两种策略都是在JDK中进行的。

我最终认为对此有一个严格的规则没有意义 - 最好对我想要传达的内容运用最佳判断。

答案 3 :(得分:2)

如果您关心您的类的用户能够通过Class.getInterfaces()获取已实现接口的列表,那么您的类应该在其实现列表中提及所有接口。 Class.getInterfaces()不会返回超类实现的接口。以下程序将打印1然后再打印0。

import java.io.Serializable;

class Test implements Serializable {
    class Inner extends Test {
    }

    public static void main(String[] argv) throws Exception {
        System.out.println(Test.class.getInterfaces().length);
        System.out.println(Inner.class.getInterfaces().length);
    }
}

答案 4 :(得分:1)

我会说更逐字的方式。为什么让其他人阅读您的代码必须查找类实现的内容?它清楚地表明了类的继承功能。但我会尝试保持项目中所有代码的一致性。如果你只在一个地方做这件事会令人困惑,但如果你这样做,他们就会知道冗余。

附注:Java中有很多类,谁知道它们?更重要的是,谁知道每个类实现哪些类?你输入额外的几秒钟可以让一位开发人员节省一两分钟的课程。

答案 5 :(得分:1)

其他评论者说你应该避免裁员,我同意他们的意见。

要回答一般性问题,我能想到的唯一一个案例是,如果你扩展(让我们说)AbstractFrotzer并实现了Frobner,AbstractFrotzer实现了Frobner,但你有理由相信它可能不会在未来。如果AbstractFrotzer是真正抽象的,那么它甚至可能都不会实现Frobner的所有方法本身。这意味着有人可以更改AbstractFrotzer的合同,而无需更改您的课程,或任何其他依赖您的课程成为Frobner的代码。但是,我认为这是一个非常罕见的情况,即使它发生了,你的类只扩展了AbstractFrotzer,也很容易给它一个快速的语义检查,如果有必要,可以在下面添加implements子句。那一点。

答案 6 :(得分:1)

虽然我通常会坚持使用选项2,但我会认为选项1在适用的情况下更适合。

代码可用性和可理解性很重要。我们必须问自己的问题是,使用或看到对此类的引用的开发人员是否会直观地理解该类实现了该接口(因此本质上是一个子类型)。

在典型案例中编写良好的类中,类的名称应该明显表明它实现了接口。添加界面只是一种冗余。

然而,如果类名没有明确表示它实现了什么接口,尽管有气味,这就是事情的方式,这就是卡住的名字,然后添加工具以明确指示接口是有意义的。如果将来某人改变了层次结构,这也是很好的,这可能是在这样的非直观遗传中。

答案 7 :(得分:1)

虽然在子类中实现接口是冗余的,但实现它是一个好习惯。因为有人可能会从超类中删除已实现的接口。

答案 8 :(得分:1)

不需要明确地做,如上面的答案所述。

但有时,您神秘地必须。我有一些带有 JIRA 插件开发类的库,以及类:

public abstract class Condition extends AbstractWebCondition

实现失败,直到我在类声明中明确添加了“实现 com.atlassian.plugin.web.Condition”(尽管 AbstractWebCondition 确实实现了它)。幸运地找到了解决方案 here

我不知道这种行为的起源,但我们知道了。从 JIRA 7.0.0 更新到 JIRA 7.13.18 时观察到。

答案 9 :(得分:0)

当你扩展AbstractList时,MyList已经是'type'List,所以不需要明确地统计(或实现)接口。

答案 10 :(得分:0)

作为一般规则,请使用选项2,而不是选项1.

在绝大多数情况下,选项1不向开发人员或将要维护代码的人员提供任何附加值。

如果有人真的想知道特定类的所有,那么任何IDE都应该能够直截了当地为您完成。 (Eclipse:ctrl + shift + G)

如果AbstractList决定不再实施List怎么办?绝大多数通用类都不会发生这种情况。那些不太明显(不那么值得信赖的)的那些呢?当然可以有例外,但很少(<1%?)

答案 11 :(得分:0)

我以前见过这个,并且在技术上并不正确,正如你们许多人已经指出的那样。我认为这应该是显而易见的,但是如果由于某种原因它不是我认为通过类注释指示继承更有意义,而不是再次明确地实现接口。

如果基类实现多个接口怎么办?那么你是否明确地实现了所有这些接口,并一直支持继承链?显然不是,所以我认为这种方法的不一致证明是错误的。意图可以通过多种方式进行沟通,这不是恕我直言的最佳方法。