Java中的非公共顶级类

6

Java中将顶层类设置为非公共的原因是什么?

假设我们有一个 Foo.java 文件,其中可能会存在:

class Foo {
}

或者

public class Foo {
}

我知道在前面的示例中会存在一些类 - 可见性问题(可能会从其他包中不可见)。但无论如何,有没有任何理由让某人像第一个代码示例中那样做?

更新:我在前一个解决方案中看到了什么缺点:没有人关心它是非公共的。该类稍后可以通过同一包中的其他public类简单地扩展,然后,类的非公共部分可能会带来可见性/访问问题。


如果没有必要,为什么要在上面添加额外的代码呢~ - TheOneTeam
5个回答

18

以下是一个例子。 我们的ConcreteDocument存在并不需要让任何人知道。

DocumentIF.java

public interface DocumentIF {
}

ConcreteDocument.java

class ConcreteDocument implements DocumentIF {
}

DocumentFactory.java

public class DocumentFactory {
    public DocumentIF createDocument() {
        return new ConcreteDocument();
    }
}

2
请注意这些类在不同的文件中;) - n0rm1e

6
通常,您会将类设置为包私有,因为不希望类在包外部使用。当顶层类不是public时,它对包是私有的。
例如,假设您有一个包含多个类的包,这些类必须相互通信以传输相同类型的数据。但是,这种数据结构是实现细节,因此不希望用户代码使用它。将传输类设置为包私有可以保持这种包级别的封装性。

5
我了解先前的示例中可能存在类可见性问题(可能无法从其他程序包中看到)。
如果您想将类保留为该程序包私有,则足以使用它。
另外注意到另一个用途!似乎您只能在代码文件中拥有一个公共的顶级类,但是可以拥有任意数量的非公共的顶级类。尚未经过个人验证,但如果真实,这可以非常有用,以防止项目文件夹混乱,并将具有相关功能的类分组,这些类不需要在程序包外使用。

第二点是正确的,但将多个顶级类放在一个文件中是一种不好的做法。想象一下,您决定Alpha.java应该有一个公共的Alpha类和一个非公共的Helper类。然后,您的同事(在同一个包中工作)决定Beta.java应该有一个公共的Beta类和一个非公共的Helper类。碰撞!如果(1)您都将Helper类嵌套在各自的顶级类中(最佳);或者(2)您都将Helper类放在自己的编译单元中(第二个开发人员会立即看到问题),这种碰撞将被避免。 - emory
@emory:这就是为什么我倾向于像Python和类似的语言一样处理事情的方式,每个文件本身都是一个具有自己模块级别命名空间的模块,通常不会出现碰撞的情况,实际上就像你的嵌套方案一样。实际上,我猜你可以通过只使用一个顶层类作为封装需要合并的类而没有任何实际功能来模拟该功能,但我想这也有点违背Java中的良好编程实践。 - JAB
如果这是最糟糕的问题,我认为它并不是什么大问题。开发人员第一次编译时会收到通知,这将是一个容易解决的问题。甚至IDE在此之前也会通知他们。 - MikeKulls

2

没有publicprotected修饰符的类只能在它们所在的包内部可见。如果您考虑到组件接口,那么省略public修饰符是有原因的。假设您有一个publicMyCompontent,它在内部使用其他类,但不想将这些类发布给外部世界(组件的用户),那么省略可见性修饰符是有意义的。


1

将类的可见性保持在最低限度被认为是良好的设计。我能想到的原因有:

  1. 如果外部包没有访问该类,则以后可以轻松更改类而不会导致外部包的故障。在这方面,最好开始是将类作为私有内部类。
  2. 包可见的类不能被外部包中的类扩展。这使得该类更容易更改,而不会导致外部包中的重大变化。如果该类不打算被扩展,那么最好将其设置为final。
  3. 公共可见类成为您库的导出API的一部分。如果您是库设计人员,则最好将导出的API尽可能小,因为您不希望用不必要的类/细节困扰您的消费者。在此情况下,项目1仍然适用。

Josh Bloch的《Effective Java》是关于Java代码和设计的优秀参考书。


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