与 C++ 相比,Java 中的访问修饰符

Access modifiers in Java compared to c++

我在 Whosebug 上看到了一些关于这个主题的讨论,但我没有看到任何有助于我理解以下几点的内容:

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

在 C++ 中,还有 "friend" classes 可以访问 private/protected 的 class 成员,给出 "friendship"。 这有点类似于 Java 中的 "package" 字段修饰符(默认字段修饰符),不同之处在于在 C++ 中,友谊可以访问所有私有成员,但在 Java 中,来自 [=同一包中的 50=]es 特定于 class 字段。

我无法理解的是,假设我只想授予子 classes 访问权限,这是我可以在 C++ 中通过在 class 中声明受保护的成员来实现的那不是 "give" 友谊。

但在 Java 中,我不知道该怎么做,因为通过使用 "protected" 字段修饰符 - 我还授予了对包中所有 classes 的访问权限. 我找到的唯一方法是声明该字段受保护并在其包中隔离 class 。

从这里,我得出的结论是,一个包中class的分组必须在class之间的"friendship"的基础上进行。 这确实是包分组的主要考虑因素吗?

另一件事我不明白, 在 Java 中,假设我在 class A 中有两个字段:b、c。 我想让 B 访问 b 而不是 c, 我想让 C 访问 c 但不访问 b。 对于 "World" 我希望 b,c 隐藏起来。 怎么做到呢? 我想 B,C 应该都和 A 在同一个包里。 但是通过使用 package 修饰符声明 b,c,我让 B,C 访问 b 和 c。 Java有办法吗?

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

这么多问题加在一起...

But in Java, I don't know how can I do it, since by using "protected" field modifier - I also give access to all classes in the package.

是的,在同一个包中无法只授予 sub类 而不是 类 的访问权限。这是很久以前做出的设计决定...

The only way that I find to do it is to declare the field protected and have the class isolated in its package.

这在技术上是正确的,但用处不大。 类的打包是为了对相关的类进行分组,其中'related'表示"classes that fulfil a specific relation",即属于同一个用例,属于同一个架构层,负责同一实体等

From here, what I conclude is that the grouping of classes in one package must be done on basis of "friendship" between the classes. Is this indeed the leading consideration in package grouping?

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

对于您的 A、B 和 C 类 示例,其属性为:

I guess B,C should be both in the same package as A. but by declaring b,c with package modifier I let B,C access both to b and c. Is there a way in Java to do it?

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

简答:没有办法。

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

In C++ when protected is used only a subclass can access the member (the analog to Field in Java).

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

In C++ there is also the "friend" classes that can have access to private/protected mambers of the class that giving "friendship". This is little bit analogous to "package" field modifier in Java (default field modifier), except that in C++ a friendship gives access to all private members, but in Java the access from classes in the same package is specific for a class field.

不仅有friendclass还有功能

确实 Java 的 package-private 访问是相似的,但不是完全替代。更好的表达方式是,这两个特征具有它们解决的问题的 子集 。有些问题可以通过 friend 解决,但不能通过 package-private 解决,反之亦然。

What I couldn't understand is, assuming that I want to give access only to subclasses, this is something I can do in C++ by declaring the members protected in a class that doesn't "give" friendships.

But in Java, I don't know how can I do it,

答案是:你不能。

since by using "protected" field modifier - I also give access to all classes in the package.

完全正确。

The only way that I find to do it is to declare the field protected and have the class isolated in its package.

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

的其他包私有 classes

Is this indeed the leading consideration in package grouping?

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

Another thing I don't understand, In Java, assuming I have two fields in the class A: b,c. I want to give B access to b but not to c, and I want to give C access to c but not to b. and to the "World" I want b,c to be hiden. How can it be done?

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

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

隐含地假设一个包中的所有 class 都是 "know" 彼此(因为它们是由相同的 person/company/organization 编写的)。因此,他们要么不访问 protected 字段,要么即使访问,他们也知道如何正确访问。

假设是 class 同一个包中的 es 彼此之间的关系比父项与派生 class 的关系更密切,因为派生 class 实际上可能写成由其他任何人。所以他们决定 private protected 比 protected 更受限制。

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

如果您有两个字段,您可以将它们设置为内部 classes,以便它们可以访问私有字段(同样,逻辑是:如果 class 在另一个 class,它知道 class) 的语义,并且可以通过受保护的方法将此访问权限公开给它们派生的 classes。

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

所以,最后,按照您在 Java 中所说的进行操作的首选方法是将它们放在同一个包中,或者将 B 和 C 写为 A 的内部 classes,这样他们就可以直接访问 A 的私有成员并将它们暴露给派生的 classes.

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;
}

同样,您总是假设同一个包中的 classes 永远不会做任何坏事。