与 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.
不仅有friend
class还有功能
确实 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 永远不会做任何坏事。
我在 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.
不仅有friend
class还有功能
确实 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
.
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 永远不会做任何坏事。