Why does Java 8 not allow non-public default methods?
让我们举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public interface Testerface {
default public String example () {
return"Hello";
}
}
public class Tester implements Testerface {
@Override
public String example () {
return Testerface. super. example() +" world!";
}
}
public class Internet {
public static void main (String[] args ) {
System. out. println(new Tester (). example());
}
} |
简单地说,这将打印Hello world!。但是假设我正在使用Testerface#example的返回值执行其他操作,例如初始化数据文件并返回不应离开实现类的敏感内部值。为什么Java不允许在默认接口方法上使用访问修饰符?为什么它们不能被保护/私有,并且可能被子类提升(类似于扩展父类的类如何为重写方法使用更可见的修饰符)?
一个常见的解决方案是移动到一个抽象类,但是在我的特定情况下,我有一个枚举接口,所以这里不适用。我认为它要么被忽视了,要么是因为接口背后的原始想法,即它们是可用方法的"契约",但我想我需要输入有关这方面的内容。
我读过"为什么是"Java 8接口方法中不允许的?,这说明:
The basic idea of a default method is: it is an interface method with a default implementation, and a derived class can provide a more specific implementation
在我看来,能见度不会破坏这一点。
与关联问题一样,由于它看起来很难被解决,在这个问题上权威性的回答会得到赞赏,而不是基于观点的回答。
- 接口中私有方法的含义是什么?
- @njzk2根据问题"但是假设我正在用testerface的返回值做其他事情,例如,初始化一个数据文件并返回一个敏感的内部值,这个值不应该离开实现类"。这是一个枚举的接口,所以虽然它有点复杂,但我不会说有很多更好的方法可以解决我在这个问题之外所做的事情。
- 只能从自己的类调用私有方法。在接口的情况下,它意味着一个不能调用的方法。
- 定义接口时,通常会使用它。提高实现中的可见性不会有任何作用。
- 我认为除了"基于意见的答案"之外,什么都没有。
- 哦,我的道歉@njzk2,我想我是以不同的方式回答你的问题的。除了在其他默认接口方法中进行访问之外,我想不出在我的头上使用private。然而,protected在这里仍然是相关的。
- 用受保护的静态方法为您的默认方法想要使用的东西创建一个私有类,但不能泄漏到世界中。也就是说,这听起来像是糟糕的设计。
- 在某种意义上,对于抽象类,该类中实际上存在非抽象方法或成员。所以当你打电话给super.method()时,你实际上是在打一个真实的电话。但是一个接口的默认方法并不是实际存在的,只是一个在不重写它时使用的默认方法。
- @AJB,但是您可以从子类直接通过Testerface.super.example()调用该方法吗?(在我的例子中看到)
- 六羟甲基三聚氰胺六甲醚。。。我不知道你能做到。我以为这是非法代码。我的错误。
- per@njzk2 private没有意义。protected也不会,因为只有子类可以覆盖受保护的方法。具体的类不会扩展接口——它们会实现它。如果您可以创建一个默认的接口方法protected,它基本上与最终的方法相同。
- @Njzk2(和pmorken):你似乎在遭受想象力的失败。接口中的私有方法可以从接口中的其他方法体(静态或默认)调用,并且与类中的私有方法的使用方式完全相同。
- @但那完全没用。接口定义了类实现的方法,它不适合包含具体的实现(除非非常简单的实现,如default)。如果你需要在你的default中调用一个私有方法,那么你的设计中就有一些异味。(也不能在Java 7的接口中生成静态方法)
- 作为旁注,我们是否意识到这本质上是多重继承?如果我有两个定义相同方法、具有不同默认值的接口,会发生什么?
- "NJZK2,我想你在晚会上迟到了几年:"这些问题在几年前JSR-335的棘手细节中被忽略了。简短的回答是:Java总是有多种类型的继承。默认方法添加多个行为继承。我们现在还没有的是国家的多重继承,这是最棘手的问题(如钻石)的地方。现在你需要去更新你的语言工作模式…
正如我们所看到的,为什么在Java 8接口方法中不允许"同步"的原因?为什么Java语言8接口方法中不允许使用"最终"?扩展接口来定义行为比它最初可能出现的要微妙得多。事实证明,每个可能的修饰符都有自己的故事;这不仅仅是盲目复制类的工作原理。(这在事后看来至少是显而易见的,因为用于单继承的OO建模工具不会自动用于多继承。)
让我们从一个明显的答案开始:接口一直被限制为只具有公共成员,而在Java 8中,我们将默认方法和静态方法添加到接口中,但这并不意味着我们必须改变所有的东西,仅仅是为了"更像"类。
与EDCOX1、0和EDCOX1(1)不同,这将是支持默认方法的严重错误,较弱的可访问性,尤其是私有性,是合理的特征。私有接口方法,无论是静态的还是实例的(请注意,这些方法不会是默认的,因为它们不参与继承),都是一个非常明智的工具(尽管它们很容易被非公共助手类模拟)。
我们实际上考虑了在Java 8中执行私有接口方法;这主要是由于资源和时间限制而从列表底部掉下来的东西。这项功能很可能会在某一天重新出现在待办事项列表中。
然而,打包和保护方法比它们看起来更复杂;多重继承的复杂性和protected真正意义的复杂性将以各种不那么有趣的方式相互作用。所以我不会因此而屏住呼吸。
所以,简短的答案是,私有接口方法是我们在8年就可以做到的,但是我们不能做所有可以做的事情,而且仍然可以发布,所以它被切断了,但可以恢复。
- 接口上缺少私有方法和默认方法是否会鼓励开发人员公开转换器?
- 我认为"鼓励"这个词是错误的。它没有泄气。我们很想在8中将私有方法引入接口,但是在您拥有的时间/资源中,您可以做的事情是有限的。
- 好消息:接口中的私有方法看起来像Java 9。
- @我很幸运遇到了我的一个老问题,谢谢你的更新!
- 尽管Java 8/9中的这些新特性看起来非常有用和方便,但我觉得它有点混乱。在我自己的"接口"的意义上,它的定义更接近于"契约",而不是它已经成为什么。我认为在语言中添加一个表示"没有状态的类"的新实体比增加"接口"实体要漂亮得多。我想的是"混音"。
- @埃格列夫,没有人会感到惊讶,这是广泛辩论之前,这一决定是采取。结论是,创建一个新的顶层抽象(mixin、trait、whatever),几乎但不完全与接口相同,会更加混乱和干扰——而且很可能也达不到人们对mixin/trait意味着什么的预先存在的期望。(很容易说,"这是不完美的,你应该做些别的事情",但人们也必须更深入地思考替代品本身是否可能更糟。)
- @埃格利夫,这实际上是一个很好的观点。我发现自己开始使用默认的方法,直到有一天我做了你所做的准确观察。我不能再同意了。