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

6
我看到了一些有关这个主题的StackOverflow讨论,但我没有看到什么帮助我理解以下问题的内容:
我来自C ++背景,并且最近开始学习Java。 在C ++中,当使用 protected 时,只有子类可以访问成员(Java中的字段的类比)。
在C ++中,还有“friend”类,可以访问给定“友谊”的类的私有/受保护成员。这与Java中的“package”字段修饰符(默认字段修饰符)有点相似,不同之处在于,在C ++中,友谊赋予对所有私有成员的访问权限,而在Java中,来自同一包中的类的访问权限是特定于类字段的。
我无法理解的是,假设我想只授予子类访问权限,那么这是我可以通过在不“授予”友情的类中声明受保护的成员来完成的。
但在Java中,我不知道如何做到这一点,因为使用“protected”字段修饰符-我还向该包中的所有类授权访问。 我发现唯一的方法是声明受保护的字段并将类隔离在其包中。
从这里,我的结论是将类分组到一个包中必须基于类之间的“友谊”。 这确实是包组合中的主要考虑因素吗? 还有一件事我不明白, 在Java中,假设类A中有两个字段:b,c。 我想给B访问权限b,但不适用于c, 我想给C访问c的权限,但不适用于b。 并且对于“World”,我希望b,c被隐藏。 怎么做呢? 我猜B,C应该都在A的同一个包中。 但是通过使用 package 修饰符声明b,c,我让B,C都可以访问b和c。 在Java中是否有一种方法可以做到这一点?

11
如果对您不那么有用,但更具针对性和特定性的问题会更好。关于“Java和C++隐私方面的一切及其差异”的广泛问题太过笼统。您能否提出一个更具体的问题,涉及一个更具体的问题? - Yakk - Adam Nevraumont
2
我建议删除C++标签,因为你的问题更多地涉及Java语言而不是C++语言。 - Thomas Matthews
这个表格清晰地说明了Java中各种访问级别的作用范围。 - aioobe
4个回答

3
在C++中,当使用protected时,只有子类可以访问成员(与Java中的Field相似)。
访问限定符也适用于成员函数/方法,而不仅仅是成员变量/字段。
在C++中还有"friend"类,它可以访问给定"友情"类的私有/受保护的成员。这与Java中的“package”字段修饰符(默认字段修饰符)有点相似,但在C++中,友谊关系可以访问所有私有成员,而在Java中,来自同一包中的类的访问对于类字段是特定的。
不仅有“friend”类,还有函数。
Java的包级私有访问确实相似,但它并非完全替代。更好的说法是,这两个功能具有它们解决的问题的子集。有些问题可以通过“friend”解决,但无法通过包级私有解决,反之亦然。
如果我想要仅授予子类访问权限,那么在不提供“友情”关系的类中声明成员为protected就可以在C++中实现。但是在Java中,我不知道该如何做到这一点,因为使用“protected”字段修饰符也会向包中的所有类提供访问权限。
技术上说,是的。但是这会创建其他问题。您的类将不再能够访问其以前包的包级私有元素。假设您的BaseClass曾经在com.example.one中,您将其移动到com.example.two中。现在它将无法访问com.example.one的其他包级私有类。
是的,Java是这样设计的。您可以尝试与语言规则抗争,但这在任何编程语言中都是徒劳无功的。
在Java中,假设我在类A中有两个字段:b和c。我想让B访问b但不访问c,我想让C访问c但不访问b。并且对于“World”,我希望b、c被隐藏。这不能以干净的方式完成(通过清洁,我的意思是:没有任何需要在运行时检查调用堆栈并引发异常的黑客)。

如果您因为设计公共API而担心此情况,一个通常完美运作的低技术方案是创建一个或多个*.internal包,并清楚地记录这些包不应在客户端代码中使用。


加一。但是你当然可以使用反射来规避所有问题。 - Bathsheba

1
假定同一个包中的所有类“互相了解”(因为它们都是由同一人/公司/组织编写的)。因此,它们要么不访问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;
}

你总是假设同一包中的类永远不会出问题。


1

这是一堆问题...

但在Java中,我不知道如何做到这一点,因为使用“protected”字段修饰符-我也允许包中的所有类访问。

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

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

从技术上讲,这是正确的,但几乎没有用处。类的打包应该用于分组相关的类,其中“相关”意味着“属于同一个用例,属于同一架构层,负责同一实体等类之间具有特定关系。”

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

我认为我已经在前面的段落中回答了这个问题:根据某些特定标准,打包旨在将相关类分组。

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

我猜测B、C应该和A在同一个包中。但是通过使用包修饰符声明b、c,我让B、C都可以访问b和c。在Java中有没有一种方法可以做到这一点呢?
答案是否定的,没有简单、干净的方法来实现它。你可以通过某些技巧或更高级的技术来实现它,但这又是语言设计师很久以前做出的决定的一部分...

0

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