我在StackOverflow中看到过关于这个主题的一些讨论,但是我没有看到让我理解以下几点的内容:
我来自C ++背景,最近我开始学习Java。 在C ++中,当使用 protected 时,只有子类可以访问该成员(类似于Java中的Field)。
在C ++中,还有“朋友”类可以访问提供“友谊”的类的私有/受保护的成员。 这有点类似于Java中的“package”字段修饰符(默认字段修饰符),除了在C ++中友谊提供对所有私有成员的访问,但在Java中,来自同一包中的类的访问特定于类字段。
我无法理解的是,假设我只想访问子类,我可以在C ++中通过声明受保护的成员不会“给予”友谊来实现这一点。
但是在Java中,我不知道怎么做,因为通过使用“protected”字段修饰符 - 我还可以访问包中的所有类。 我发现这样做的唯一方法是声明受保护的字段并将类隔离在其包中。
从这里,我得出的结论是,一个包中的类的分组必须基于类之间的“友谊”来完成。 这确实是包裹分组中的主要考虑因素吗?
另一件我不明白的事, 在Java中,假设我在A类中有两个字段:b,c。 我想给b访问b而不是c, 我想给C访问c而不是b。 而对于“世界”我想要b,c被隐藏。 怎么做到呢? 我猜B,C应该和A一样。 但是通过使用包修饰符声明b,c我让B,C访问b和c。 Java中有没有办法做到这一点?
希望对此主题有一些解释
答案 0 :(得分:2)
在C ++中,当使用protected时,只有子类可以访问该成员 (类似于Java中的Field)。
访问说明符也适用于成员函数/方法,而不仅仅是成员变量/字段。
在C ++中还有朋友"可以访问的类 私人/受保护的班级成员,给予友谊"。这个 有点类似于"包" Java中的字段修饰符(默认值 字段修饰符),除了在C ++中友谊允许访问所有 私有成员,但在Java中从类中访问相同 包特定于类字段。
不仅有friend
个类,还有函数。
Java的软件包私有访问是类似的,但它不是完全替代品。更好的方法是,这两个功能有一个子集他们解决的问题。有些问题可以通过friend
解决,但不能通过包私有解决,反之亦然。
我无法理解的是,假设我想提供访问权限 只有子类,这是我可以在C ++中通过声明来实现的 成员受到保护的课程没有给予"友谊。
但在Java中,我不知道我该怎么做,
答案是:你做不到。
因为使用" protected"字段修饰符 - 我也可以访问 包中的所有类。
完全。
我发现这样做的唯一方法是声明受保护的字段 将该类隔离在其包中。
技术上,是的。但这会产生其他问题。您的类将无法再访问其先前包的package-private元素。让我们说BaseClass
曾经在com.example.one
。您将其移至com.example.two
。现在它将无法再访问com.example.one
的其他包私有类。
这确实是包装分组中的主要考虑因素吗?
是的,Java就是这样设计的。您可以尝试对抗语言规则,但这在任何编程语言中都是一场失败的战斗。
另一件我不明白的事情,在Java中,假设我有两个字段 在A类:b,c。我希望B访问b而不是c,而我 想要C访问c而不是b。以及#34; World"我想要b,c 隐藏起来。怎么办呢?
它不能以干净的方式完成(通过干净我的意思是:没有任何需要你在运行时检查调用堆栈并抛出异常的黑客攻击)。
如果您因为正在设计公共API而关注这种情况,那么通常可以完美运行的低技术解决方案是创建一个或多个*.internal
包,并清楚地记录这些不应该包含的事实。用于客户端代码。
答案 1 :(得分:1)
这些是很多问题......
但是在Java中,我不知道我该怎么做,因为使用" protected"字段修饰符 - 我还可以访问包中的所有类。
是的,没有办法只允许子类访问,而不能访问同一个包中的类。这是很久以前的设计决定......
我发现这样做的唯一方法是声明受保护的字段并将类隔离在其包中。
这在技术上是正确的,尽管它用处不大。类的打包旨在用于对相关类进行分组,其中相关的类是相关的。表示满足特定关系的类#34;即它们属于同一个用例,属于同一个架构层,负责同一个实体等。
从这里,我得出的结论是,一个包中的课程分组必须基于友谊"课间。这确实是包装分组中的主要考虑因素吗?
我相信我已在上一段中回答过这个问题:打包是指根据某些特定标准对相关类进行分组。
对于具有属性的A,B和C类示例:
我猜B,C应该和A在同一个包中。但是通过使用包修饰符声明b,c我让B,C访问b和c。 Java中有没有办法做到这一点?
答案是否定的,没有简单,干净的方法来做到这一点。你可以通过一些黑客或一些更先进的技术来实现它,但是,这也是很久以前语言设计师所做决定的一部分......
答案 2 :(得分: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;
}
再次,你总是假设同一个包中的类永远不会做坏事。
答案 3 :(得分:0)
简短的回答:没有办法做到这一点。
如果您担心来自客户端的入侵在您的程序包中注入一个类以获取非法访问权限,您可以将敏感代码移到单独的包中,并将包密封在您提供的jar中:{ {3}}