为啥 Java 中的“protected”修饰符允许访问同一包中的其他类?

Posted

技术标签:

【中文标题】为啥 Java 中的“protected”修饰符允许访问同一包中的其他类?【英文标题】:Why does the "protected" modifier in Java allow access to other classes in same package?为什么 Java 中的“protected”修饰符允许访问同一包中的其他类? 【发布时间】:2010-10-28 12:35:10 【问题描述】:

为什么在Java中,带有“protected”修饰符的成员不仅可以被同一个类和子类访问,而且可以被同一个包中的每个人访问?

我想知道语言设计的原因,而不是实际应用程序(例如,测试)

【问题讨论】:

+1 坦率地说,我也想知道为什么。它总是让我觉得 Java 中最愚蠢的设计决策之一。 @cletus :我考虑的时间越长,我得出的结论是“包私有”是一个没有经过深思熟虑的想法。对于实际工作的“包私有”并提供任何类型的真正保护,需要在单个编译单元中编译包。而且以后应该无法增强它们。 【参考方案1】:

此设计基于包是适当的单元,由一个内部一致的团队维护和发布的想法;继承关系与谁维护和何时发布什么关系不大。

【讨论】:

感谢您的回答。当然实际上是行不通的,因为没有人阻止你将一个包分发到几个 jar 中 - 并且将它分发给多个团队。所以这是另一个没有经过深思熟虑的好主意。 Java 充满了一些东西。【参考方案2】:

基本上,它与将包视为 api 控制单元有关(因此建议使用您的域名启动包 - 保证全局唯一性),因此可见性从私有 -> 包私有 -> 保护增长-> 公开。如果受保护的不是包私有的增加,而是一种不同类型的可见性,则必须有某种方法在需要时将这两种类型的可见性结合起来。

【讨论】:

但是没有人阻止你向一个已经存在的包中添加一个新类。所以“package private”和“protected”只是对程序员的建议。两者都没有为想要/需要调用该方法的恶意/绝望程序员提供任何真正的保护。 ——像 C++ 中的“受保护”至少会强制使用子类——但在 Java 中你甚至不需要这样做。【参考方案3】:

考虑到访问权限的渐进级别,私有、包、受保护和公共,如果它受到保护然后包,这将是不必要的限制,因为这将迫使我允许子类访问以授予同一包的其他成员。然而,直观地说,同一个包中的其他类应该比“外面”的其他类更值得信赖。如此受保护是在包和公共之间,因为它允许更广泛的访问权限。

我认为基本原因依赖于直觉,即同一个包中的类之间存在基本的“信任”水平;您可以合理地期望他们彼此做正确的事情 - 在大多数情况下,软件包将由单个工程师或团队负责,因此应该有一致的设计和谐。

【讨论】:

这就是理论。但在实践中,这只适用于需要在单个编译单元中编译包并且无法在外部进行增强的情况。但事实并非如此,因此,借助精简委托类,任何“包私有”方法都可以公开。对程序员的提示,但不是真正的保护。 @martin:仅当您发布包而不密封它时,该功能可以解决此特定问题。 “密封包装”——从未听说过,但听起来很有趣。 告诉我更多!(几句话帮我google一下就够了) 我自己找到的:docs.oracle.com/javase/tutorial/deployment/jar/sealman.html — 很有趣。应该是默认的 ;-) .【参考方案4】:

修饰符很好地描述了at http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html。从那里我们可以看到这个数字。

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N

从这个设计决定的原因很明显:它有一个很好的对称矩阵。

【讨论】:

@Michael Myers:嗯,不,无论如何它都不是对称的。它是对称的是有原因的。 如果你在protected -> 包的交点处放置一个 N 而不是一个 Y,它仍然是对称的。只是没有那么漂亮。 @MichaelMyers:我不认为矩阵是对称的。但目前是:所有 Y 在对角线上方(和上方),所有 N 在下方。【参考方案5】:

在 Java 1.0 中有第五个访问修饰符:private protected。这是protected,没有默认访问权限。显然,它实际上从未真正正常工作,并在 1.1 中被删除。因此,似乎声称protected 的定义方式与总排序的方式相同,这似乎是虚假的。 (编辑:看来,在 1.1 中删除第五个访问修饰符的至少原因之一是缺少总排序干扰了重载选择规则。)module 访问修饰符Java 7 在这方面有一些设计问题。

考虑到将成员的默认访问修饰符设置为“包私有”是一个好主意,protected 至少应具有此访问级别似乎是合理的。为了我的钱,protected 根本不用语言。

【讨论】:

我从没听说过那个,但我是在 1.1 开始接触 Java 的...谢谢! 而且由于没有人阻止您将更多类添加到不同 jar 文件中的包中,“包私有”也不是那么私有。事实上:除了私有和公共之外的任何东西或多或少都是对程序员的暗示,但没有真正的保护。 一个很晚的问题,但你有这方面的资料吗?我现在想更详细地说明当时失败的原因和原因。 @PieterDeBie 那是凭记忆。大约 22 年前,我将我正在从事的内部项目从 1.0 升级到 1.1。 bugs.sun.com 只给了我“删除了“私人保护”以简化规范的其他部分 - 例如,有关覆盖的规则要求访问保护具有可比性(即严格地弱于或强于彼此。)' @Martin 您可以在清单中将罐子标记为“密封”,这样可以防止任何添加。当然,可以修改 jar 本身 - 包括类文件。除非您对 jar 签名,在这种情况下,您不能将任何类添加到具有不同签名的同一 runtime 包中(假设签名已验证)。此外,来自不同类加载器的任何类都将位于不同的 runtime 包中。【参考方案6】:

Java 本身确实遵循其设计原则。当您尝试减少/缩小子类中公共方法的范围时会发生什么?一个错误。 Java 范围修饰符级别如下:private

包中的所有类都应该是友好的,因为它们一起工作。为了使包中的成员可用,它在默认范围内定义。

子类可能驻留在包之外,再次遵循范围级别: private Java 不违背自己的准则。因此,受保护的成员将在默认范围内可用。另外:类

请不要将修饰符限制为仅可见性,但继承、结构也同时起作用并将它们添加到图片中。如果这是真的:private

【讨论】:

以上是关于为啥 Java 中的“protected”修饰符允许访问同一包中的其他类?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的权限修饰符(protected)

为啥定义接口的方法和属性前面没有修饰符(public、private、protected)? [复制]

java中的public,protected,private权限修饰

详解Java中的访问控制修饰符(public, protected, default, private)

JAVA 中的权限访问修饰符(public,protected,default,private )

为啥受保护的修饰符在 Java 子类中的行为不同?