为什么Java 8接口不允许使用`private static`字段?

15

当我尝试编译以下代码时

public interface SomeInterface{
    private static Logger logger = Logger.getLogger();

    public default void someMethod(){
        logger.info("someMethod: default implementation");
    }
}

我遇到了一个错误

Illegal modifier for the interface field SomeInterface.logger; only public, static & final are permitted

当我删除private修饰符时,代码可以编译通过,但我不希望来自包中的其他类能看到这个字段。

为什么Java不允许我这样做,尽管这确实很有道理呢?


如果你覆盖了someMethod方法会怎样? - Stultuske
@Stultuske 我会提供新的实现。如果我不覆盖它呢? - Kamil Jarosz
从逻辑上讲,接口旨在提供一种概括几个不同类行为的方法。也就是说,用户必须控制该类的行为。以汽车(现实生活中)为例:你有方向盘、收音机、刹车、离合器等。你知道这些并学会如何操作它们。但如果接口包含您无法访问的内容-您将如何使用它来控制类的行为?换句话说-接口是您进入世界的门户-使用它们来概括而不是隐藏字段等... - Mackiavelli
@Mackiavelli 但是默认实现需要这个私有字段。接口本来就不应该提供任何实现,但Java 8对此进行了一些改变。 - Kamil Jarosz
我知道有人会说这不正确,但在某种程度上,接口越来越接近于cpp抽象类。为什么?我不知道。但是实现应该注意这一点。实现接口的用户根本不应该看私有内容。 - Mackiavelli
@Mackiavelli “为什么?我不知道”--- 防御方法是实现流API到JDK的有效引入的前提条件。许多接口需要扩展,如果没有防御者,这将是不可能的,因为它会违反Java对向后兼容性的严肃承诺。 - Marko Topolnik
5个回答

20

在Java 8之前的观点中,接口仅用于接口合同,并且私有成员仅用于实现,因此这种限制是完全合理的。

在Java 8之后的世界中,接口可以承载行为(但不包括状态),因此开始合理地询问是否应该将类的其他特性应用于接口。 (但是,仅仅因为某件事可能是“合理的”并不意味着它必须得到支持; 构建世界通常有多种合理的方法。)

在Java 9中,接口中的私有方法将获得支持。


这个答案最好地解释了我的问题 :) 你有Java 9中private成员的一些参考资料吗? - Kamil Jarosz
1
kamil09875:http://openjdk.java.net/jeps/213(第5点);如果您认为这回答了您的问题,您可以[接受](http://stackoverflow.com/help/accepted-answer)这个答案。 - Holger
4
在Java 9中,接口中的私有成员将得到支持。似乎只支持私有方法,而不支持私有静态常量字段。您是否有任何关于为什么忽略私有静态常量字段的信息? - Balder
2
他们从未在场。我应该在上面说“方法”,因为这一直是计划; 把它视为打字错误。(答案已被编辑)。 - Brian Goetz
5
为什么私有静态常量字段被省略? - VimNing

9

接口不是类,它们没有私有状态。即使接口中有公共记录器,也是一种设计上的问题和对接口的滥用。

在接口中使用静态字段的用例主要是为了编译时常量,而不是有状态对象。


是的,我不认为这是“设计异味”。 - Enerccio

0
接口的目标是定义其他类实现的内容。私有字段不定义任何东西,因为它在接口外部不可见。因此,在这个结构中没有任何意义。可能会有一些黑客技巧如何使用它(也许是从接口内部类),但无论如何都不会看起来像一个好的设计。
如果您实际上要实现部分功能,请改用抽象类。

默认实现在接口外部也不可见。 - Kamil Jarosz
在同一包中可见。 - Audrius Meškauskas
它在同一包中如何可见?此外,Java 8接口是不同的,因为它们实际上实现了部分功能。如果它们不是私有静态字段,则根本不需要。 - Kamil Jarosz
@Slaw,那私有字段呢? - Enerccio
@Enerccio 但是接口定义行为,而不是状态。私有方法的存在并不违反这个“原则”,而允许私有字段则会。当然,这只适用于实例字段。也许将来他们会允许接口中有私有静态字段。但我猜测设计者不希望你像使用抽象类一样使用接口。 - Slaw
显示剩余2条评论

0

接口就像任何类的蓝图,您在其中声明成员。实现该接口的任何类都负责其定义。 私有成员只能由同一类成员访问,在接口方面没有意义。 受保护的成员可以被同一类成员和继承类成员访问,但在接口的情况下,我们从不扩展接口,而是实现它。因此,任何接口通常只包含公共方法。


0

public interface SomeInterface {
    public default void someMethod() {
        SomeInterfaceInternal.logger.info("someMethod: default implementation");
    }
}

final class SomeInterfaceInternal {
    protected static final Logger logger = LoggerFactory.getLogger(SomeInterface.class);
}


这个与原始的包私有字段一样存在问题,即来自同一包的类可以访问它。 - Enerccio
@Enerccio,实际上你从来没有一个“包私有字段”。如果你删除接口成员的修饰符,你会得到一个公共成员,而不是一个包私有成员。 - SensorSmith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接