在接口中受保护

Swa*_*rma 101 java interface

为什么interface定义中的所有方法都是隐含的public?为什么它不允许protected方法?

Rav*_*ine 63

因为界面应该是"你可以从课外看到的东西".添加非公开方法是没有意义的.

  • @Raveline,-1,这引出了一个问题"为什么一个界面应该意味着你能从课外看到什么?" Java 8已经允许接口中的方法体,那么为什么不允许受保护的抽象方法呢? (21认同)
  • 但是为什么没有只有与接口相同的包的成员"可以从课外看到"的功能呢?我有几个用例,我希望这样做. (13认同)
  • @pickypg但是如果实现接口的类已经扩展了另一个类,则不能使它扩展另一个类.对于仅在包内使用的接口,我不会感到困惑. (8认同)
  • @MarkusA.我意识到这已经很晚了,但是你可以创建一个完全"抽象的类",它就是所有的"接口",并指定你想要的任何访问权限.当然,这会失去多个实现的好处,这些实现是"接口"在Java中得到的,但诚实地建立一个遵守某些其他包的限制的合同将是不可测试和混乱的,因为您实际上无法在外部访问您自己的实现方法那个包裹. (5认同)
  • 我经常阅读这个解释,但这是错误的恕我直言.无论是谈论OOP,通信API还是硬件,接口都是一种"标准交换协议".我PC上的USB端口显然是一个公共接口.但是主板上的引脚,即锁钥匙盒后面的引脚,提供对可选USB端口的访问,显然是一个"受保护"的接口.然后我们有BIOS芯片 - 这也是一个标准化的界面,但它从未以任何方式公开,只有少数公司私下知道确切的细节.所以,当然,接口可以有任何可见性!为什么不在OOP? (5认同)

Ste*_*n C 51

虽然经常被引用的原因是"接口定义公共API",但我认为这是一种过度简化.(它也"循环"了循环逻辑.)

  • 嵌套接口可以是受保护的或私有的,如果是这种情况,它根本不定义公共接口.

  • 拥有具有访问修饰符混合的接口并没有意义; 例如,部分公开,部分限制在与界面相同的包中的其他类.事实上,在某些情况下,这可能是非常有用的,IMO.

实际上,我认为使接口成员隐式公开的推理部分它使Java变得更简单:

  • 隐式公共接口成员对于程序员来说更容易处理.你有多少次见过代码访问修饰符的代码(类)看似随意?许多"普通"程序员很难理解如何最好地管理Java抽象边界1.将public/protected/package添加到接口会使它们变得更加困难.

  • 隐式公共接口成员简化了语言规范......因此简化了Java编译器编写者以及实现Reflection API的人员的任务.

这种思路使"接口定义公共API"成为语言设计的结果(或特征)......而不是相反.实际上,这两种思路可能在Java设计者的脑海中并行发展.


1 - 当然,顶级程序员对这些事情没有任何困难,并且可能欢迎更丰富的访问控制功能.但是,当他们的代码被移交给其他人维护时会发生什么?

  • Java 8已经允许接口中的方法体,我不明白为什么它们仍然*如此顽固,拒绝在接口中允许受保护的抽象方法. (16认同)
  • 您可以将接口成员隐式公开,但允许明确声明它们不公开. (4认同)
  • @StephenC,第二点当然是有效的(对于实现者来说很容易),但第一点看起来很可疑:它不会使Java用户的语言界面更简单,因为它限制了我们*限制访问*的能力,是一件坏事.想象一下,被迫将所有抽象类的方法声明为公开! (4认同)

小智 20

我不得不说这个问题已经通过在Java 8中引入默认方法而重新打开了.我现在正在开发的项目,类似于接口的基本性质,意味着从实现中抽象出意图.

在某些情况下,我可以使用"默认保护"方法大幅简化我的代码.事实证明,这实际上并不起作用,因为接口仍然坚持Java 7逻辑.由于上述原因,正常受保护的方法没有任何意义; 但是如果一个默认的公共方法需要一个不太可能改变的低级资源并且可以由受保护的方法提供,那么在我看来,"默认保护"工作不仅可以保持更清晰的代码,还可以保护未来的用户免受意外滥用.

(这不幸地改变了我仍然需要使用其他不必要的摘要过度复杂化我的代码的事实;但我确实打算在Oracle中添加一个功能请求.)

  • 我100%同意。在引入默认方法之前,抽象类是一个明智的选择。然而,它们对多重继承的限制意味着它们并不完美。在 >= JDK 1.8 的世界中,具有默认方法的接口通常是更好的选择,但由于它们无法存储状态,因此它们依赖于定义其他抽象方法来公开状态,这意味着状态是公开的,而这并不总是公开的你要。 (5认同)

Sea*_*oyd 10

因为接口定义了公共API.任何受保护的内容都是不属于接口的内部细节.

您可以将抽象类与受保护的抽象方法一起使用,但接口仅限于公共方法和公共静态最终字段.

  • 您说"因为接口定义了公共API".那么接口应该只定义`public` API的原因是什么?"内部细节"与"实现细节"之间存在差异,Java中的"protected"绝对不是内部细节,因为它现在是一个公共界面[发布给所有人](http://stackoverflow.com/questions/215497/ in-java-whats-the-difference-public-default-protected-and-private/215579#215579)谁可以继承它,这基本上是整个世界. (4认同)
  • @MarioRossi 对于 Java 9 的私有接口方法来说也不再如此。 (3认同)
  • Java 8 的默认方法不再如此。 (2认同)

sko*_*isa 10

这里的几个答案使用循环推理来解释为什么接口方法不能被保护:因为它们必须是公共的,所以显然它们不能被保护!

这没有任何解释,但幸运的是,几年前有人提出了对接口中受保护方法的增强请求作为 JDK 错误,这对这个问题有所了解:

接口中的受保护方法:跨包共享

由于修饰符在 Java 中受到一些限制,跨包共享方法的方法仅限于公共方法。有时将方法公开是危险的,但由于缺少适当的修饰符而需要公开。我的解决方案克服了这个限制。

Java 语言规范目前不允许对接口方法使用 protected 修饰符。我们可以利用这一事实,并为这个新功能的接口方法使用 protected。

如果接口方法被标记为受保护,并且该接口由另一个包中的类实现,则该方法不需要是公共的,但也可以是私有的或至少是包保护的。该方法是可见的,无论类声明它是什么,并且在接口的源包(和子包?)中也是可见的。

这样我们就可以在众所周知的包中共享某些方法。

这是对该增强请求的响应,该请求以 status 关闭Won't fix

该提议试图以一种增加复杂性和特殊情况的方式来解决问题,而实际收益却很少。解决这个问题的典型方法是拥有一个实现公共接口的私有类。实现方法是公共的,但在私有类中,因此它们保持私有。

从 Java 9 开始,另一种可用的方法是将类和方法公开,但在具有限定导出到特定“朋友”模块而不是导出到公众的模块中。

因此,该错误报告的权威结论是:

  • 目前的情况不会改变;接口不太可能永远支持protected方法。
  • 不支持protected接口中的方法的理由是它“增加了复杂性和特殊情况,而实际收益很小”。
  • 从 Java 9 开始,有一种替代方法可以提供对方法的包级访问。使用Java 平台模块系统 (JPMS)来“使类和方法公开,但在具有限定导出到特定“朋友”模块而不是导出到公众的模块中”。


Ing*_*ngo 7

也许,因为它是一个界面,即它告诉客户他们可以用实例做什么,而不是告诉他们他们不能做什么.

  • 我不明白为什么接口不能告诉子类它们可以做什么而不将该实现暴露给外界。这是在抽象类可以作为完美替代方案时做出的设计决策。但随着接口中默认方法的出现,抽象类现在是一个不完美的替代方案。 (2认同)

Jan*_*n_V 5

接口应被用作外部世界的“合同”。如果要使用受保护的方法,则最好使用抽象类(当然,如果Java中提供了抽象类)。 维基

另外,此帖子可能还会提供一些很好的答案:为什么我不能拥有受保护的接口成员?

  • 如果您的班级还需要扩展其他内容,则此功能不那么有用。 (3认同)

Int*_*ata 5

强烈认为接口应允许使用受保护的方法。谁说界面必须对全世界所有人可见?关于您的观点,这可能会使“普通”(不称职)程序员感到困惑:大量的OOP都是关于正确构造对象,类,程序包等的,如果程序员很难正确地完成所有这些工作,那么他有一个更大的问题。Java是为这种类型的东西而构建的。

  • 这并不能回答问题。 (2认同)