在接口中受保护

时间:2011-03-21 11:25:34

标签: java interface

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

17 个答案:

答案 0 :(得分:58)

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

答案 1 :(得分:49)

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

  • 嵌套接口可以是受保护的,也可以是私有接口,如果是这样,它根本不会定义公共接口。

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

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

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

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

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


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

答案 2 :(得分:19)

我不得不说这个问题已经通过在Java 8中引入默认方法而重新打开了。我现在正在研究的项目,类似于接口的基本性质,意在从实施

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

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

答案 3 :(得分:9)

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

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

答案 4 :(得分:7)

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

答案 5 :(得分:5)

界面旨在用作外部世界的“合同”。如果你想使用受保护的方法,你可能最好使用抽象类(当然,如果在Java中可用)。 Wiki

此外,这篇文章也可能有一些很好的答案:Why can't I have protected interface members?

答案 6 :(得分:4)

强烈认为接口应该允许受保护的方法;谁说接口必须让全世界的每个人都能看到?至于你的观点,它可能会混淆“普通”(阅读:无能)程序员:OOP的大部分内容都是关于正确构造对象,类,包等,如果程序员很难完成所有这些,他有一个更大的问题。对于那种类型的东西,Java是内置的

答案 7 :(得分:3)

由于实现类必须实现接口中声明的所有方法,如果您的实现类位于不同的包中会发生什么?

答案 8 :(得分:2)

接口如果你想使用你所描述的东西继续使用抽象类或嵌套接口。

关于接口变量的Code Style的一个exerpt,但仍然适用于方法:

 接口变量是隐式公开的,因为接口旨在提供一个应用程序编程接口(API),Java程序员可以完全访问它以在自己的应用程序中引用和实现。由于接口可以在与自己不同的Java包中使用,因此公共可见性可确保程序代码可以访问变量。

答案 9 :(得分:2)

只有当子类扩展基类时,子类才能访问受保护的方法。

在接口的情况下,子类永远不会扩展接口。它实现了接口。

受保护的方法可通过扩展访问,而不是通过工具访问。

答案 10 :(得分:1)

唯一有意义的情况是,您希望限制对同一个包的可见性。 protected的所有其他用途均不适用。具体而言,protected方法通常用于提供对后代的较低级别实现的一些细节的访问。但是声明在接口中没有意义,因为没有较低级别的实现可以公开。

甚至包方案也不是真正的接口。

要实现您可能需要的功能,您需要两个接口,一个用于内部使用,另一个在公共API中公开。 (内部的可能,但不一定扩展公共的。)或者,正如其他人指出的那样,是一个抽象的超类。

答案 11 :(得分:1)

声明内部子接口是一个很好的实践,但在技术上,您不能在Java的接口中将内部方法声明为protected

当然,您可以创建另一个内部使用的接口来扩展公共接口:

public interface YourPublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

    interface Internal extends YourPublicInterface {

        void doAnyInternalThing1();

        void doAnyInternalThing2();

    }

}

您可以在包中使用Internal接口,但是您应该接受YourPublicInterface的任何子类型(在公共方法中):

public class AClassInYourPackage {

    public void someMethod(YourPublicInterface param) {
        if (param instanceof YourPublicInterface.Internal) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

在软件包之外,用户可以毫无问题地使用YourPublicInterface

在一般实践中,程序员在类似情况下创建抽象类。但是,在这种情况下,我们失去了多重继承的好处。

答案 12 :(得分:1)

public 成员通常由public 成员使用。例如,AbstractList.removeRange(int, int) 使用 AbstractList.clear(),覆盖它会提高 clear 的性能。

如果接口中允许使用 protected 方法,则意味着大多数 public default 实现将依赖于这些方法。如果子类不需要 default 实现并覆盖所有 public 方法,则所有非 public 方法将不再有用。如果它们是 abstract,我们仍然需要覆盖它们,这会使子类变得复杂。

答案 13 :(得分:0)

很好的问题,如果被问到,为什么开发人员将接口属性设为公共而不受保护,...?

允许受保护将违反接口的策略/属性,“无论您提供什么抽象,都应无条件访问任何地方,但不允许对其进行更改。(例如:实例var的值)”

要使用这种用例,应该避免使用界面。

答案 14 :(得分:0)

接口旨在将方法公开给外部世界。因此,这些方法本质上是公开的。但是,如果要在同一类家族中引入抽象,则可以通过在接口和实现类(即抽象类)之间创建另一个抽象级别来实现。下面是一个示例。

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}

答案 15 :(得分:0)

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

这没有任何解释,但幸运的是,someone raised an enhancement request for protected methods in interfaces as a JDK bug是几年前的事,这为我们提供了一些启示:

  

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

     

由于修饰符在Java中有点局限,是一种共享方法的方法   跨包仅限于公共方法。有时候是   公开方法很危险,但这必须是因为   缺乏适当的修饰语。我的解决方案克服了这一限制。

     

Java语言规范当前不允许受保护   接口方法的修饰符。我们可以利用这一事实   为该新功能使用接口方法的保护。

     

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

     

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

这是对该增强请求的响应,该请求以状态Won't fix被关闭:

  

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

     

从Java 9开始可用的替代方法是创建类和   公共方法,但在具有合格出口的模块中   特定的“朋友”模块,而不是导出到常规模块   公开的。

因此,该错误报告中的权威要点是:

  • 目前的状况不会改变;接口不太可能支持protected方法。
  • 在接口中不支持protected方法的理由是,它“ 增加了复杂性和特殊情况,几乎没有实际收获”。
  • 自Java 9以来,存在另一种方法,可提供对方法的包级访问。使用the Java Platform Module System (JPMS)“将类和方法公开,但在一个具有合格导出到特定“朋友”模块的模块中,而不是导出到公众的模块中。
  • ”。 >

答案 16 :(得分:-1)

接口成员总是在其自身之外(在类或结构中)进行修改/实现,因此它们是隐式公共的,并且不允许使用任何访问修饰符。 即使是界面成员也是公开实施的。 但是,如果您希望在提供其实现的类中将成员设为私有,那么您需要显式实现该接口。

interface IMyIF {
int MyMeth(int x);
}
//then it is legal to implement IMyIF as shown here:
class MyClass : IMyIF {
int IMyIF.MyMeth(int x) {
return x / 3;
}
}

显式实现为您提供了一种实现接口方法的方法,使其不是提供实现的类的公共成员。