16

由于Jigsaw项目的核心是 Java 模块系统,因此最好能够限制对特定模块内特定程序元素(类、方法和字段)的访问。

当模块中有一些元素对于这个模块本质上是公共的,但不应该在这个模块之外访问时,它会很有帮助。

所以我说的是“package-local”之后的下一个访问级别,可以命名为“module-local”。

然而,对Jigsaw 规则和早期规范的简要了解并没有帮助我找到这种功能。更具体地说,本Modifier规范不包含任何新元素。

那么在未来的 Java 9 中还有其他可能性吗?

4

2 回答 2

16

非导出包中的public元素(类、接口、方法或字段)实际上是“本地模块”。模块中的所有其他代码都可以访问它,但不能从模块外部访问。

无法在导出的包中声明模块本地元素。导出包的public元素可以从模块外部访问,包私有元素仍然是包私有的,这两种模式之间没有元素级访问模式。我们可以定义一个新的这样的模式,但是我们很少看到有说服力的用例,此外,在 JVM 中以比导出包更精细的粒度实现模块化访问控制会带来巨大的性能成本。

于 2016-08-12T17:54:33.723 回答
8

简答

当模块中有一些元素对于这个模块本质上是公共的,但不应该在这个模块之外访问时,它会很有帮助。

这是不可能的。(仅使用模块系统 - 有一种解决方法。)

长答案

解释在于术语Accessibility

Java 编译器和虚拟机认为只有当第一个模块可以被第二个模块读取时,一个模块中的包中的公共类型才能被其他模块中的代码访问,在上面定义的意义上,并且第一个模块导出该包. [...]

以这种方式无法访问的跨模块边界引用的类型不可用,就像私有方法或字段不可用一样:任何尝试使用它都会导致编译器报告错误,或者IllegalAccessError抛出Java 虚拟机,或者IllegalAccessException由反射运行时 API 抛出。[...]

跨模块边界引用的方法或字段是可访问的,如果它的封闭类型在这个意义上是可访问的,并且如果成员本身的声明也允许访问。

虽然有不同的方式可以准确地导出包的方式和对象,但一旦编译器/JVM 认为类型可访问,则不会应用其他机制。它的成员与 Jigsaw 之前一样易于访问。

这意味着没有办法让可访问类型的成员在模块内可见(这将需要public)但在模块外部不可见(因为可访问类型的公共成员是可访问的)。

解决方法

那么在未来的 Java 9 中还有其他可能吗?

是的。:)

您可以在导出的包中拥有一个公共接口,该接口Global定义了您想要导出到世界的方法。Local然后扩展一个接口或一个类Global并添加所有你想要的成员。关键是Local不能导出的包中!

现在,如果您的模块的 API 只返回Global-s 但从不接受它们作为方法参数,那么您就可以开始了。只要确保在内部你总是使用 - 并且可能转换为 - Local

如果您也接受Global-s 您必须清楚地证明这些只能是您的 API 返回的实例(即不允许用户创建自己的实现)。这听起来可能令人望而却步,但如果您仔细考虑您的原始请求,它将具有相同的特征。

于 2016-08-11T16:37:38.843 回答