36

前面有关键字和没有关键字的模块有什么区别open?例如:

open module foo {
}

module foo {
}
4

3 回答 3

41

为了提供对模块的反射访问,Java 9 引入了open关键字。

您可以通过在模块声明中使用open关键字来创建一个开放模块。

一个开放的模块将其所有包的反射访问权授予其他模块。

例如,如果你想使用一些严重依赖反射的框架,如 Spring、Hibernate 等,你可以使用这个关键字为其启用反射访问。

您可以使用包声明中的opens语句为模块的指定包启用反射访问:

module foo {
    opens com.example.bar;
}

或者在模块声明中使用open关键字:

open module foo {
}

但请记住,您不能将它们组合起来:

open module foo {
    opens com.example.bar;
}

结果编译时错误。

希望能帮助到你。

于 2017-09-29T05:35:25.407 回答
12

有问题的指令的一些背景知识。打破封装部分中的模块系统状态

有时有必要违反模块系统定义的访问控制边界,并由编译器和虚拟机强制执行,以允许一个模块访问另一个模块的某些未导出类型。这可能是可取的,例如,启用内部类型的白盒测试,或将不受支持的内部 API 暴露给依赖它们的代码。--add-exports可以在编译时和运行时使用该 选项来执行此操作。

命令行选项相当于例如:-

module java.logging {
    exports java.util.logging;
}

--add-exports选项允许访问指定包的公共类型。


虽然此后,

有时需要更进一步,通过核心反射 API 的 setAccessible 方法启用对所有非公共元素的访问。--add-opens可以在运行时使用该选项来执行此操作。

此命令行选项等效于例如:-

module jdk.unsupported  {
   opens sun.misc; 
}

相比之下,普通的命名模块使用模块声明显式定义为:-

module foo { }

这些被称为显式模块。显式模块可以使用上述包上的指令,例如 to export/ openpackages 以提供对其各自公共成员和类的反射访问。


另一方面,OPEN模块是

未声明任何打开包但生成的模块被 视为所有包都打开的模块。

这样它就可以在运行时授予对所有模块包中的类型的访问权限,就好像所有包都已导出一样,这意味着可以使用字节码或反射来访问所有包中的每个包的类或成员。反射 API 具有setAccessibleMethodHandles.privateLookupIn允许深度反射,因此简而言之,您可以对所有包中所有类的所有成员进行反射。这也几乎解释了为什么编译器在模块已经打开时不允许两个打开指令到包的原因。

于 2017-09-29T06:48:03.550 回答
0

假设 'foo' 有两个包,com.example 和 com.example.bar

module foo {
    opens com.example;
}

上面的模块声明允许在运行时对外部“com.example”包内的类型进行反射访问。

但是“com.example”在外部编译时将不可见。

open module foo {
}

这意味着,它隐式打开模块中的所有包以供运行时进行反射访问。

上面的模块声明将等同于以下,

module foo {
    opens com.example;
    opens com.example.bar;
}
于 2021-08-01T17:12:13.497 回答