为什么调用 `Blah.class.getModule()` 会得到未命名的模块,而不是BlahModule?

后端开发 2026-07-09

简而言之,我有一个BlahModule,为它做了一个module-info.java,而这个模块中的一个类被叫做Blah。所以,当同一个模块中的另一个类调用Blah.class.getModule()时,我期望得到BlahModule,但结果却是未命名模块。

下面是我的一些研究工作。

查看 Class.getModule() 的文档时,关于模块它是这样说的。

如果这个类处于未命名模块中,则返回该类的类加载器的未命名模块。

Ok, 当点击关于未命名模块的链接时,它把我带到 Java Language Specification on Unnamed Modules (7.7.5),其说如下。

An observable ordinary compilation unit that the host system does not associate with a named module (§7.3) is associated with an unnamed module.

一个可观察的普通编译单元,若宿主系统不将其与命名模块关联(§7.3),则与未命名模块相关联。

Ok, it appears that the association must be explicit. Following the link to 7.3 brings me to the following.

Each observable compilation unit may be associated with a module, as follows:

  • The host system may determine that an observable ordinary compilation unit is associated with a module chosen by the host system, except for (i) the ordinary compilation units in the predefined package java and its subpackages lang and io, which are all associated with the java.base module, and (ii) any ordinary compilation unit in an unnamed package, which is associated with a module as specified in §7.4.2.
  • The host system must determine that an observable modular compilation unit is associated with the module declared by the modular compilation unit。

每个可观察的编译单元可按下列方式与一个模块相关联:

  • 宿主系统可以确定一个可观察的普通编译单元与宿主系统选择的模块相关联,除了(i)在预定义包java及其子包lang与 io中的普通编译单元,它们都与java.base模块相关联,以及(ii)未命名包中的任何普通编译单元,它们与 §7.4.2指定的模块相关联。
  • 宿主系统必须确定一个可观察的模块化编译单元与其在模块化编译单元中声明的模块相关联。

Ok, 那些是允许或否定将模块与编译单元关联的规则,但没有关于如何将模块与编译单元关联的说明。

Ok, 浏览了一会儿,我落在7.2上,它说如下。

The host system is free to determine that a compilation unit which contains a module declaration is not, in fact, observable, and thus is not associated with the module declared therein. This enables a compiler to choose which directory on a modulesourcepath is "really" the embodiment of a given module. However, if the host system determines that a compilation unit which contains a module declaration is observable, then §7.4.3 mandates that the compilation unit must be associated with the module declared therein, and not with any other module.

宿主系统有自由决定,包含模块声明的编译单元实际上并不可观察,因此与其中声明的模块不相关联。这使编译器能够选择在模块源路径上哪一个目录才是某个模块的“真正实现”。然而,如果宿主系统确定包含模块声明的编译单元是可观察的,则 §7.4.3要求该编译单元必须与其中声明的模块相关联,且不能与任何其他模块相关联。

Ok, 所以模块与编译单元之间的关联行为是由对编写中的模块声明的可观察性来严格决定的。

Ok, what does it mean to be observable?

那么,什么才算是可观察?

Well, 7.3 (which I looked at part of above) lists some stuff, but nothing that explicitly explains HOW to know when something is or is not observable. It sounds like the host system can determine that, but how is not clear to me.

好,7.3(上面部分我也看过)列出了一些东西,但没有明确解释到底如何判断某物是可观察的还是不可观察的。听起来像是宿主系统可以判断,但具体的“如何”对我来说并不清楚。

So this is more or less where I am lost. I don't really see where else to look from here. I could probably do a Ctrl+F search of the whole JLS, but I figured I would make this post before doing so.

大致就是我卡在这儿。现在也看不出还该从哪里查起。我也许可以对整本JLS做一次Ctrl+F搜索,但我想在动手前先发这篇帖子。


And to reiterate, all of this research is merely to answer the question -- what is required in order for Blah.class.getModule() to return my BlahModule instead of the Unnamed Module?

再次强调,这些研究仅为回答一个问题——要让 Blah.class.getModule() 返回我的 BlahModule,而不是返回未命名模块,需要满足哪些条件?

解决方案

The host system is free to determine...

"Free" is the keyword here. The Java Language Specification leaves it up to the implementation to determine how this is done.

宿主系统有自由来决定……这里的关键词就是“自由”。Java语言规范把它交给实现来决定如何完成这件事。

The javac compiler has the --module-source-path option to let you specify where your modules are. javac would look for module-info.java files and the modules declared therein would be considered "observable".

javac 编译器有 --module-source-path 选项 来让你指定你的模块放在哪里。javac 将查找 module-info.java 文件,里面声明的模块将被视为“可观察的”。

Here is an example project structure

下面是一个示例项目结构

project
└── mymodule
    ├── com
    │   └── example
    │       └── foo
    │           └── Main.java
    └── module-info.java

You can compile this like this:

你可以这样编译:

cd project
javac --module-source-path . -d out mymodule/com/example/foo/Main.java

Here I used . as the module source path, and javac will find ./mymodule/module-info.java. This file should be a ModularCompilationUnit as the JLS calls it. e.g.

在这里我使用 . 作为模块源路径,javac 将找到./mymodule/module-info.java。这个文件应该是JLS所说的一个 ModularCompilationUnit。例如:

module mymodule {

}

To run the output binary, use the --module-path option instead.

要运行输出的二进制,请改用 --module-path 选项。

java --module-path out -m mymodule/com.example.foo.Main

Now printing Main.class.getModule() will produce module mymodule.

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章