从基类继承的接口是否应该在子类中显式实现?
我的问题是,如果通过扩展已经实现它的类来隐式实现的接口,如果该类想要宣传它履行该接口的契约的事实,则应该由该类显式实现。
例如,如果您想编写一个类,它满足接口java.util.List
的约定。 您可以通过扩展已实现接口 List
的类 java.util.AbstractList
来实现此功能。 您是否明确声明您实现了 List?
public class MyList extends AbstractList implements List
还是使用隐式方式来节省打字?
public class MyList extends AbstractList
哪种方式被认为是更好的风格? 您有什么理由选择这种或另一种方式? 在什么情况下您更喜欢方式 1 或方式 2?
My question is, if an interface that is implemented implicitly by extending a class that already implements it, should be explicitly implemented by the class, if the class wants to advertise the fact, that it fulfills the contract of that interface.
For instance, if you want to write a class, that fulfills the contract of the interface java.util.List
. You implement this, extending the class java.util.AbstractList
, that already implements the interface List
. Do you explicitly declare, that you implement List?
public class MyList extends AbstractList implements List
Or do you save typing by using the implicit way?
public class MyList extends AbstractList
Which way is considered better style? What reasons do you have to prefer one way or another? In which situations you would prefer way 1 or way 2?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
避免冗余。 使用方法2。
使用@Override进行覆盖。
Avoid redundancy. Use method 2.
Use @Override for overrides.
这不是一个“风格”问题。 如果您要扩展已实现 List 的 AbstractList,则无需显式实现 List。
这不仅仅是节省打字的问题。 由于附加的“工具列表”是多余的,有人可能会花一些时间试图找出它的存在原因。 你本质上是在写一个已经成为语言一部分的保证。
It is not a "style" question. If you are extending AbstractList which already implements List you do not need to explicitly implement List.
It's not just a question of saving typing. As the additional "implements List" is redundant, someone might spend some time trying to figure out why it's there. You're essentially writing in a guarantee that's already part of the language.
我很久以前在我的博客上问过同样的问题。 如果您有兴趣了解其他人的想法,那里也有一个很长的讨论。 有趣的是,这两种策略都是在 JDK 中采用的。
我最终认为对此制定硬性规定是没有意义的 - 最好对我想要传达的内容使用最佳判断。
I asked this same question long ago on my blog. There is a long discussion there as well if you're interested in seeing some other people's thoughts. It's interesting to note that both strategies are taken within the JDK.
I ultimately decided that a hard rule on this didn't make sense - it's better to use best judgement as to what I wanted to communicate.
如果您关心类的用户能够通过 Class.getInterfaces() 获取已实现接口的列表,那么您的类应该提及其“实现”列表中的所有接口。 Class.getInterfaces() 不会返回超类实现的接口。 以下程序将打印 1,然后打印 0。
If you care about a user of your class being able get a list of implemented interfaces via Class.getInterfaces() then your class should mention all the interfaces in its' implements list. Class.getInterfaces() will not return the interfaces implemented by super classes. The following program will print 1 and then 0.
我会更逐字地说。 为什么要让其他人阅读你的代码必须查找类实现了什么? 它清楚地表明了类的继承功能。 但我会尽力保持项目中所有代码的一致性。 如果你只在一个地方这样做,那会很混乱,但如果你始终如一地这样做,他们就会意识到冗余。
旁注:Java 中有如此多的类,谁知道它们呢? 更重要的是,谁知道每个类是从哪些类实现的? 您多输入几秒钟可以为其他开发人员节省一两分钟的时间来查看课程。
I would say the more verbatim way. Why make others that read your code has to look up what a class implements? It makes it clear of the inherit functionality of your class. But I would try to maintain consistency across all code in the project. It will be confusing if you only do it in one place but if you do it consistently they will be aware of the redundancy.
A Side Note: There are so many classes in Java and who knows them all? Even more so, who knows which classes each class implements from? You typing for an extra couple seconds saves a fellow developer a minute or two looking classes.
其他评论者说你应该避免冗余,我同意他们的观点。
为了回答一般问题,我能想到的说明两者的唯一情况是,如果您扩展(比方说)AbstractFrotzer 并实现了 Frobner,AbstractFrotzer 实现了 Frobner,但您有理由相信将来可能不会。 如果 AbstractFrotzer 确实是抽象的,那么它甚至可能无法实现 Frobner 本身的所有方法。 这意味着有人可以更改 AbstractFrotzer 的契约,而无需更改您的类或依赖于您的类成为 Frobner 的任何其他代码。 然而,我认为这是一种非常罕见的情况,即使发生这种情况并且您的类仅扩展了 AbstractFrotzer,也可以很容易地对其进行快速语义检查,并在必要时向其添加 Implements 子句:那一点。
Other commenters say you should avoid redundancy, and I agree with them.
To answer the general question, the only case I can think of for stating both would be if you extended (let's say) AbstractFrotzer and implemented Frobner, AbstractFrotzer implemented Frobner, but you had reason to believe that it might not in the future. If AbstractFrotzer is truly abstract, then it might not even implement all of Frobner's methods itself. This means it's possible for someone to change the contract for AbstractFrotzer without your having to change your class, or any other code that relied on your class to be a Frobner. I would, however, consider this to be a very rare circumstance, and even if it occurred and your class only extended AbstractFrotzer, it would be sufficiently easy to give it a quick semantic check and, if necessary, add the implements clause to it at that point.
虽然我通常坚持选择 2,但我会冒险认为,选择 1 在适用时实际上在更多情况下是合适的。
代码的可用性和可理解性很重要。 我们必须问自己的问题是,使用或看到对该类的引用的开发人员是否会直观地理解该类实现了该接口(因此本质上是一个子类型)。
在典型情况下,在编写良好的类中,类的名称应该明显表明它实现了接口。 添加接口只是一种冗余。
但是,如果类名没有明确说明它实现的接口,并且尽管有味道,但事情就是这样,并且这个名称将被卡住,那么 添加实现来显式指示接口是有意义的。 这也很好,以防将来有人更改层次结构,这在像这样不直观的继承中是可能的。
While I generally stick with option 2, I will go on a limb and argue that option 1 is actually appropriate in more cases when it is apply.
Code usability and understandability is important. The question that we have to ask ourselves is whether or not a developer using or seeing a reference to this class would intuitively understand that the class implements that interface (and is thus essentially a subtype).
In a well written class in the typical case, the name of the class should make it obvious that it implements the interface. Adding the interface would be just a redundnacy.
However, in cases where the class name does not make it obvious what interfaces it implements, and despite the smell this is the way things are and this is the name that will stuck, then it makes sense to add the implements to indicate the interface explicitly. This is also good in case someone in the future changes the hierarchy, which is possible in unintuitive inheritances like this.
虽然在子类中实现接口是多余的,但实现它是一个很好的实践。 因为有人可能会从超类中删除已实现的接口。
Though it is redundancy to implements the interface in the subclass but it is a good practice to implement it. Because somebody might remove the implemented interface from the super class.
无需明确执行此操作,如上面的答案所述。
但有时,你神秘地不得不。 我有一些包含用于 JIRA 插件开发的类的库,并且 class:
实现失败,直到我在类声明中明确添加“implements com.atlassian.plugin.web.Condition”(尽管如此, AbstractWebCondition 确实实现了它)。 幸运的是找到了解决方案 在这里。
我不知道这种行为的起源,但我们就在这里。 从 JIRA 7.0.0 更新到 JIRA 7.13.18 时观察到了这一情况。
No need to do it explicitely, as stated in answers above.
But sometimes, you mysteriously have to. I have some library with classes for JIRA plugins developing, and class:
implementations failed until I've added " implements com.atlassian.plugin.web.Condition" in class declaration explicitely (though, AbstractWebCondition do implements it). Solution was fortunately found here.
I don't know origins of such behaviour, but here we are. It was observed while updating from JIRA 7.0.0 to JIRA 7.13.18.
当您扩展 AbstractList 时,MyList 已经是“类型”List,因此无需显式地统计(或实现)该接口。
When you extend AbstractList, MyList is of 'type' List already, so there is no need to explicityly stat (or implement) the interface.
作为一般规则,使用选项 2,而不是选项 1。
在绝大多数情况下,选项 1 不会为开发人员或将要维护代码的人提供任何附加值。
如果有人真的想了解所有信息特定类的根源,任何 IDE 都应该能够为您简单地完成此操作。 (Eclipse:ctrl+shift+G)
如果 AbstractList 决定不再实现 List 怎么办? 对于绝大多数普通类来说,这种情况不会发生。 那么其他不太明显(不太值得信赖)的呢? 当然也有例外,但很少(<1%?)
As a general rule, use option 2, not option 1.
Option 1 does not provide any value addition to the developer or someone who is going to maintain the code, in the vast majority of the cases..
If someone really wants to know all the roots of a particular class, any IDE should be able to do it for you, straightforward. (Eclipse: ctrl+shift+G)
What if AbstractList decides not to implement List any longer? This is not going to happen for the vast majority of general classes. What about the other less obvious (less trustworthy) ones? Of course there can be exceptions, but very few (<1% ?)
我以前见过这个,感觉技术上不正确,正如你们许多人已经指出的那样。 我认为这应该是显而易见的,但是如果由于某种原因不是显而易见的,我认为通过类注释指示继承会更有意义,而不是再次显式实现接口。
如果基类实现多个接口怎么办? 然后,您是否显式实现所有这些接口,并一直备份继承链? 显然不是,所以我认为这种方法的不一致证明本身是错误的。 意图可以通过多种方式传达,恕我直言,这不是最好的方法。
I have seen this before and it doesn't feel technically correct, as many of you had already pointed out. I would think it should be obvious, however if for some reason it were not I think it would make more sense to indicate the inheritance through a class comment, rather than explicitly implementing the interface again.
What if the base class implements multiple interfaces? Do you then explicitly implement all of those interfaces, and all the way back up the inheritance chain? Obviously not, so I think the inconsistency of this approach proves itself to be wrong. Intent can be communicated in many ways, and this is not the best approach IMHO.