【问题标题】:Access modifiers in Java compared to c++ [closed]Java中的访问修饰符与c ++相比[关闭]
【发布时间】:2015-05-05 18:12:31
【问题描述】:

我在 StackOverflow 中看到了一些关于这个主题的讨论,但我没有看到有助于我理解以下要点的内容:

我来自 C++ 背景,最近开始学习 Java。 在 C++ 中,当使用 protected 时,只有子类可以访问成员(类似于 Java 中的 Field)。

在 C++ 中,还有“朋友”类可以访问提供“友谊”的类的私有/受保护的成员。 这有点类似于 Java 中的“包”字段修饰符(默认字段修饰符),除了在 C++ 中友谊允许访问所有私有成员,但在 Java 中,来自同一包中的类的访问是特定于类字段的。

我无法理解的是,假设我只想授予对子类的访问权限,我可以在 C++ 中通过在不“给予”友谊的类中声明受保护的成员来做到这一点。

但在 Java 中,我不知道该怎么做,因为通过使用“受保护”字段修饰符 - 我还可以访问包中的所有类。 我发现这样做的唯一方法是声明该字段受保护并将类隔离在其包中。

从这里,我得出的结论是,一个包中的类分组必须基于类之间的“友谊”。 这确实是包分组的主要考虑因素吗?

还有一点我不明白, 在Java中,假设我在A类中有两个字段:b,c。 我想让 B 访问 b 而不是 c, 我想让 C 访问 c 而不是 b。 对于“世界”,我希望 b,c 被隐藏起来。 如何做呢? 我猜B,C应该都和A在同一个包里。 但是通过使用 package 修饰符声明 b,c,我让 B,C 同时访问 b 和 c。 Java 中有没有办法做到这一点?

希望对这个主题有一些解释

【问题讨论】:

  • 一个更好的问题,如果对您不太有用,会更窄更具体。 “Java 和 C++ 中关于隐私的一切以及它们之间的区别”这个一般性问题有点过于宽泛了。您能否针对更具体的问题提出更具体的问题?
  • 我建议删除 C++ 标签,因为您的问题更多是关于 Java 语言而不是 C++ 语言。
  • This table 清楚地说明了 Java 中各种访问级别的范围。

标签: java access-modifiers


【解决方案1】:

在 C++ 中,当使用 protected 时,只有子类可以访问该成员 (类似于 Java 中的 Field)。

访问说明符也适用于成员函数/方法,而不仅仅是成员变量/字段。

在 C++ 中还有可以访问的“朋友”类 给予“友谊”的类的私人/受保护的成员。这 有点类似于 Java 中的“包”字段修饰符(默认 字段修饰符),除了在 C++ 中友谊可以访问所有 私有成员,但在 Java 中,来自同一类中的访问 包是特定于类字段的。

不仅有friend类,还有函数。

Java 的包私有访问确实是类似的,但它不是一个完整的替代品。一个更好的说法是,这两个功能具有它们解决的问题的子集。有些问题可以通过friend 解决,但不能通过package-private 解决,反之亦然。

我无法理解的是,假设我想授予访问权限 仅适用于子类,这是我可以在 C++ 中通过声明 在不“给予”友谊的类中受保护的成员。

但是在Java中,我不知道该怎么做,

答案是:你不能。

因为使用“受保护”字段修饰符 - 我也可以访问 包中的所有类。

没错。

我发现这样做的唯一方法是声明该字段受保护并且 将类隔离在其包中。

从技术上讲,是的。但这会产生其他问题。您的类将不再能够访问其先前包的包私有元素。假设您的BaseClass 曾经在com.example.one 中。你把它移到com.example.two。现在它将不再能够访问com.example.one 的其他包私有类。

这确实是包分组的主要考虑因素吗?

是的,Java 就是这样设计的。您可以尝试与语言规则作斗争,但这在任何编程语言中都是一场失败的战斗。

另一件事我不明白,在 Java 中,假设我有两个字段 在A类:b,c。我想给 B 访问 b 但不给 c,我 想要让 C 访问 c 而不是 b。和我想要的“世界” b,c 被隐藏。怎么办?

它不能以干净的方式完成(我的意思是干净:没有任何需要您在运行时检查调用堆栈并抛出异常的黑客行为)。

如果您因为正在设计公共 API 而担心这种情况,那么通常可以完美运行的低技术解决方案是创建一个或多个 *.internal 包并清楚地记录不应该使用的事实在客户端代码中。

【讨论】:

  • 加一。但是你当然可以使用反射来规避一切。
【解决方案2】:

这些都是一堆问题......

但在 Java 中,我不知道该怎么做,因为通过使用“受保护”字段修饰符 - 我还可以访问包中的所有类。

确实,没有办法只授予对子类的访问权,而不授予对同一包中的类的访问权。这是很久以前做出的设计决定......

我发现这样做的唯一方法是声明该字段受保护并将类隔离在其包中。

这在技术上是正确的,尽管它用处不大。类的打包是为了对相关类进行分组,其中“相关”是指“满足特定关系的类”,即它们属于同一个用例,属于同一个架构层,负责同一个实体等。

从这里,我得出的结论是,一个包中的类分组必须基于类之间的“友谊”。这确实是包分组的主要考虑因素吗?

我相信我在上一段中已经回答了这个问题:打包是为了根据一些特定的标准对相关的类进行分组。

对于带有属性的 A、B 和 C 类示例:

我猜 B,C 应该和 A 在同一个包中。但是通过使用包修饰符声明 b,c 我让 B,C 可以访问 b 和 c。 Java中有没有办法做到这一点?

答案是否定的,没有简单、干净的方法可以做到这一点。你可以通过一些 hack 或更高级的技术来实现它,但是,这也是语言设计者很久以前做出的决定的一部分......

【讨论】:

    【解决方案3】:

    隐含地假设包中的所有类都“了解”彼此(因为它们是由同一个人/公司/组织编写的)。所以他们要么不访问protected 字段,要么即使他们访问了,他们也知道如何正确访问。

    假设同一个包中的类之间的相关性比父类与派生类之间的相关性更高,因为派生类实际上可能是由其他任何人编写的。所以他们决定私有保护比受保护更受限制。

    所以,我认为您不应该担心同一个包中的类可以访问彼此的字段的方式。一般来说,我只是不使用这个特性,除非我写迭代器的时候。

    如果你有两个字段,你可以让它们成为内部类,这样它们就可以访问私有字段(同样,逻辑是:如果一个类在另一个类中,它知道那个类的语义)并且可以通过受保护的方法公开对其派生类的访问。

    当然,您可以发明一些复杂的令牌交换协议,只让 B/C 实例可以访问该字段,但这将是一个显着的开销,并且另一个对象仍然可以使用反射来访问所有私有成员,除非您通过安全策略禁用它,通常情况并非如此,但同样,安全策略最终由 JVM 的所有者决定。

    因此,最后,在 Java 中执行您所说的操作的首选方法是将它们放在同一个包中,或者将 B 和 C 编写为 A 的内部类,以便它们可以直接访问 A 的私有成员和将它们暴露给它们的派生类。

    public class A {
      public static abstract class B {
        protected Whatever getWhatever(A a) { return a.b; }
        protected void setWhatever(A a, Whatever value) { a.b = value; }
      }
      public static abstract class C {
        protected Whatever getWhatever(A a) { return a.c; }
        protected void setWhatever(A a, Whatever value) { a.c = value; }
      }
      private Whatever b;
      private Whatever c;
    }
    

    再一次,你总是假设同一个包中的类永远不会做坏事。

    【讨论】:

      【解决方案4】:

      简短回答:没有办法。

      如果您担心客户端在您的包中注入类以获取非法访问权限,您可以将敏感代码移动到单独的包中,并将包密封在您交付的 jar 中:http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html

      【讨论】:

        猜你喜欢
        • 2021-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-20
        • 2015-07-05
        • 2019-04-02
        • 2023-04-03
        • 2013-05-25
        相关资源
        最近更新 更多