为什么interface
定义中的所有方法都是隐式的public
?为什么不允许使用protected
方法?
protected
method,则所有实现类都将被视为接口的子类型。所有这些类都可以访问受保护的方法。它会使protected
方法上的关键字无效吗?只要我们没有任何方法来限制谁实现此接口 ,方法上的protected关键字是无用的。如我错了请纠正我!
为什么interface
定义中的所有方法都是隐式的public
?为什么不允许使用protected
方法?
protected
method,则所有实现类都将被视为接口的子类型。所有这些类都可以访问受保护的方法。它会使protected
方法上的关键字无效吗?只要我们没有任何方法来限制谁实现此接口 ,方法上的protected关键字是无用的。如我错了请纠正我!
Answers:
因为接口应该表示“您可以在课堂外看到的东西”。添加非公共方法是没有道理的。
abstract class
,这是所有interface
s为,并指定你想要的任何访问。这样做会失去interface
Java中实现的多个实现的好处,但是老实地建立一个遵守其他程序包限制的合同将是不可测试的并且令人困惑,因为您实际上无法在该程序包之外访问自己的实现方法。
尽管经常引用的原因是“接口定义了公共API”,但我认为这过于简单了。(它也“闻”到循环逻辑。)
具有混合了访问修饰符的接口并不是没有意义的。例如部分公开,部分限制为与接口相同的包中的其他类。实际上,在某些情况下,这可能是非常有用的,IMO。
实际上,我认为隐式公开接口成员的部分原因在于它使Java语言更简单:
隐式地,公共接口成员对于程序员来说更简单。您看过多少次看似随机选择方法访问修饰符的代码(类)?许多“普通”程序员都难以理解如何最好地管理Java抽象边界1。向接口添加public / protected / package-private会使它们更加困难。
隐式地,公共接口成员简化了语言规范,从而简化了Java编译器作者和实现Reflection API的人员的工作。
“接口定义公共API”的思路可以说是简化语言设计决策的结果(或特征)……而不是相反。但实际上,这两种思路可能是在Java设计人员的思想中并行发展的。
无论如何,对JDK-8179193中 RFE的官方回应清楚地表明,Java设计团队决定2允许protected
接口增加了复杂性,却没有什么实际好处。感谢@skomisa 查找证据。
RFE中的证据解决了这个问题。这是为什么没有添加的正式原因。
1-当然,顶尖的程序员在处理这些事情上没有困难,并且可能会欢迎使用更丰富的访问控制功能。但是,当他们的代码移交给其他人维护时会发生什么呢?
2-您可能不同意他们的决定或他们陈述的理由,但是那是没有根据的。
我必须说,通过在Java 8中引入默认方法,这个问题已经重新出现。我现在正在从事的项目类似于接口的基本性质,旨在从实现中抽象意图。
在几种情况下,我可以使用“默认保护”方法彻底简化代码。事实证明,这实际上不起作用,因为接口仍然遵循Java 7逻辑。由于上述原因,普通的受保护方法没有任何意义。但是,如果默认的公共方法需要不会更改的低级资源并且可以由受保护的方法提供,那么在我看来,拥有“默认受保护”的工作不仅会维护更干净的代码,而且还会保护未来的用户意外虐待。
(这可悲地改变了我仍然需要用其他不必要的摘要来使我的代码过于复杂的事实;但是我确实打算在Oracle中提出功能请求。)
因为接口定义了公共API。任何受保护的内容都是内部细节,不属于接口。
您可以将抽象类与受保护的抽象方法一起使用,但接口仅限于公共方法和公共静态最终字段。
public
API 的原因是什么?protected
在Java中,“内部细节”与“实现细节”之间是有区别的,因为Java现在绝对是一个内部接口,它公开给所有可以继承它的人,而这个接口基本上是整个世界。
这里有几个答案使用循环推理来解释为什么接口方法不能被保护:这是因为它们必须是公共的,因此显然它们不能被保护!
这没有任何解释,但是幸运的是,几年前有人提出了对接口中受保护方法的增强请求,这是JDK的错误,它为您揭示了这个问题:
接口中受保护的方法:跨包共享
由于Java中的修饰符有些限制,因此跨包共享方法的方法仅限于公共方法。有时将方法公开是很危险的,但这必须是因为缺少适当的修饰符。我的解决方案克服了这一限制。
Java语言规范当前不允许接口方法使用protected修饰符。我们可以利用这一事实,并为该新功能将protected用于接口方法。
如果接口方法被标记为受保护并且该接口是由另一个程序包中的类实现的,则该方法将不必是公共的,但也可以是私有的或至少受程序包保护。该方法是可见的,无论该类声明了什么,并且在接口的源包(和子包?)中还可见。
这样,我们可以在知名软件包之间共享某些方法。
这是对该增强请求的响应,该请求已通过status关闭Won't fix
:
该建议试图以增加实际复杂度和特殊情况的方式解决问题。解决此问题的一种典型方法是拥有一个实现公共接口的私有类。实现方法是公共的,但在私有类中,因此它们保持私有。
从Java 9开始可用的替代方法是将类和方法公开,但在一个模块中,该模块具有合格导出到特定“朋友”模块的功能,而不是导出到普通大众的模块。
因此,该错误报告的权威之处在于:
protected
方法。protected
在接口中不支持方法的理由是,它“ 增加了复杂性和特殊情况,却很少获得实际收益 ”。声明内部子接口是一个好习惯,但是从protected
技术上讲,您不能像在Java接口中那样声明内部方法。
当然,您可以创建另一个供内部使用的接口,以扩展公共接口:
package yourpackage;
public interface PublicInterface {
public void doThing1();
public void doThing2();
public void doThing3();
}
package yourpackage;
interface InternalInterface extends PublicInterface {
void doAnyInternalThing1();
void doAnyInternalThing2();
}
您可以使用InternalInterface
包内的接口,但是您应该接受PublicInterface
(在公共方法中)的任何子类型:
package yourpackage;
public class SomeClass {
public void someMethod(PublicInterface param) {
if (param instanceof InternalInterface) {
// run the optimized code
} else {
// run the general code
}
}
}
外包装,用户可以PublicInterface
毫无问题地使用。
通常,程序员在类似的情况下创建抽象类。但是,在这种情况下,我们失去了多重继承的好处。
YourPublicInterface.Internal
。接口中的所有内容(包括嵌套接口)都是公共的,而与public
关键字的存在与否无关。
唯一有意义的情况是您想限制对同一程序包的可见性。的所有其他用途protected
均不适用。具体而言,protected
通常使用方法为后代提供对较低级别实现的某些详细信息的访问。但是在接口中声明是没有意义的,因为没有要公开的较低级别的实现。
甚至包方案也不是真正的接口。
要实现您可能想要的功能,您需要两个接口,一个接口供内部使用,一个接口在公共API中公开。(内部有可能,但不一定扩展公共的。)或者,正如其他人指出的那样,抽象超类。
仅当子类扩展了基类时,子类始终可以访问受保护的方法。
对于接口,子类从不扩展接口。它实现了接口。
受保护的方法可以通过extend访问,而不能通过Implement访问。
接口旨在将方法公开给外部世界。因此,这些方法本质上是公开的。但是,如果要在同一个类家族中引入抽象,则可以通过在接口和实现类之间创建另一个抽象级别(即抽象类)来实现。下面演示一个示例。
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
}
}