协慌网

登录 贡献 社区

Java 中的 public,protected,package-private 和 private 有什么区别?

在 Java 中,是否有明确的规则来确定何时使用每个访问修饰符,即默认(包私有), publicprotectedprivate ,同时创建classinterface以及处理继承?

答案

官方教程可能对你有用。

│ Class │ Package │ Subclass │ Subclass │ World
            │       │         │(same pkg)│(diff pkg)│ 
────────────┼───────┼─────────┼──────────┼──────────┼────────
public      │   +   │    +    │    +     │     +    │   +     
────────────┼───────┼─────────┼──────────┼──────────┼────────
protected   │   +   │    +    │    +     │     +    │         
────────────┼───────┼─────────┼──────────┼──────────┼────────
no modifier │   +   │    +    │    +     │          │    
────────────┼───────┼─────────┼──────────┼──────────┼────────
private     │   +   │         │          │          │    

+ : accessible
blank : not accessible

(警告:我不是 Java 程序员,我是 Perl 程序员. Perl 没有正式的保护,这也许是我理解这个问题的原因:))

私人的

就像你想的那样,只有声明它的才能看到它。

包私人

只能被声明它的看到和使用。这是 Java 中的默认值(有些人认为是错误的)。

受保护

Package Private + 可以通过子类或包成员看到。

上市

每个人都可以看到它。

发布时间

在我控制的代码外面可见。 (虽然不是 Java 语法,但对于此讨论非常重要)。

C ++ 定义了一个名为 “friend” 的附加级别,你知道的越少越好。

你什么时候应该用什么?整个想法是隐藏信息的封装。您希望尽可能隐藏用户完成某些操作的详细信息。为什么?因为那样你可以在以后更改它们而不会破坏任何人的代码。这使您可以优化,重构,重新设计和修复错误,而无需担心有人正在使用您刚刚彻底检查过的代码。

因此,经验法则是使事物只能像它们必须一样可见。从私有开始,只根据需要添加更多可见性。只公开那些对用户来说绝对必要的信息,你公开的每一个细节都会让你重新设计系统。

如果您希望用户能够自定义行为,而不是将内部公开,以便他们可以覆盖它们,那么将这些内容推入对象并使该接口公开通常是一个更好的主意。这样他们就可以简单地插入一个新对象。例如,如果您正在编写 CD 播放器并希望 “查找有关此 CD 的信息” 位可自定义,而不是将这些方法公开,您可以将所有功能放入其自己的对象中并使公共 getter / setter 成为公共对象。以这种方式吝啬暴露你的胆量鼓励良好的成分和关注点的分离

就个人而言,我坚持只是 “私人” 和 “公共”。许多 OO 语言就是这样。 “受保护” 可以派上用场,但这真的是一种骗局。一旦界面不仅仅是私人的,它就在你的控制之外,你必须去寻找其他人的代码才能找到用途。

这就是 “已发布” 的概念所在。更改界面(重构它)需要您找到使用它的所有代码并进行更改。如果界面是私有的,那么没问题。如果它受到保护,你必须找到你所有的子类。如果它是公开的,你必须找到使用你的代码的所有代码。有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,那么如果接口是公共的则无关紧要。您可以从公司存储库中获取所有代码。但是如果一个界面被 “发布”,如果有代码在你的控制范围之外使用它,那么你就被软管了。您必须支持该接口或冒险破坏代码。甚至受保护的接口也可以被认为是已发布的(这就是我不打扰受保护的原因)。

许多语言发现公共 / 受保护 / 私有的等级性质太过限制而不符合现实。为此,有一个特质类的概念,但这是另一个节目。

这是表格的更好版本。 (模块专栏的未来证明。)

Java Access Modifiers

说明

  • 私有成员只能在声明的同一个类中访问。

  • 没有访问修饰符的成员只能在同一个包中的类中访问。

  • 受保护的成员可以在同一个包中的所有类中以及其他包中的子类中访问。

  • 所有类都可以访问公共成员(除非它驻留在不导出声明的包的模块中)。


选择哪种修饰符?

访问修饰符是一种帮助您防止意外破坏封装的工具(*) 。问问自己,您是否希望该成员成为类,包,类层次结构内部的内容,或者根本不是内部成员,并相应地选择访问级别。

例子:

  • 字段long internalCounter应该是私有的,因为它是可变的和实现细节。
  • 只应在工厂类(在同一个包中)实例化的类应具有包受限制的构造函数,因为不应该直接从包外部调用它。
  • 在渲染之前调用并在子类中用作钩子的内部void beforeRender()方法应该受到保护。
  • 从 GUI 代码调用的void saveGame(File dst)方法应该是公共的。

(*) 什么是封装?