首页 > 解决方案 > 对于其他非模块化项目,如何使 Java 类在其模块之外不可见?

问题描述

最近我发现,如果模块内的包包含公共接口或类,它们会自动导出,因此在接收者代码未模块化时无意中在模块外部可见。

项目结构如下

parent

   sub-donor                      (java-module)
       my/project/first
           Cowboy.java
       module-info.java

   sub-recipient                  (has no module-info)
       my/project/somewhere
           Main.java 

模块信息.java

module my.donor {
  // nothing is exported here
}

牛仔.java

public class Cowboy {    
  public String say() { return "eee-ha"; }
}

主.java

import my.project.first.Cowboy;

public class Main {
  public static void main(String[] args) {
    Cowboy g = new Cowboy();

    System.out.println(g.say());
  }
}

包中的类my.project.first应该my.donor只在模块中使用,并且在模块之外是不可见的。

没想到它在模块外可见,好像有一行,所以可以编译exports my.project.first;该类。Main

限制可见性的方法是制作sub-recipient一个 java 模块,添加module-info.java,然后其中的所有内容都sub-donor按预期隐藏。当然,对于任何其他非模块化项目,my.donor模块中的每个公共类都是可见的。

请在 GitHub 上查看一个最小的工作示例。

我很好奇这是一个错误还是一个有意识的设计。这种方法的目的是什么?

标签: javainterfacevisibilityjava-modulemodule-info

解决方案


TL;DR — Maven 的问题。直接编译javac按预期工作。


长篇大论的版本

„<em>...完整命令只是在父项目上 mvn 编译...</em>“</p>

这就是你的问题。Maven 有一个令人惊讶的特性,它只会将子项目视为 JPMS 模块IFF 所有子项目都有模块描述符。

所以因为只有你的sub-donorMaven 模块有 JPMS 模块描述符,所以你的两个子项目都在类路径上编译……</p>

$ mvn -e -X compile
…
[INFO] Changes detected - recompiling the module!
[DEBUG] Classpath:
[DEBUG]  sample-so-question-61888059-dev/sub-recipient/target/classes
[DEBUG]  sample-so-question-61888059-dev/sub-donor/target/classes
…
[DEBUG] Command line options:
[DEBUG] -d sample-so-question-61888059-dev/sub-recipient/target/classes -classpath sample-so-question-61888059-dev/sub-recipient/target/classes;sample-so-question-61888059-dev/sub-donor/target/classes;…
…

并且因为两者都在类路径上,所以sub-donor子项目的模块描述符被渲染为无效。

如果您自己动手并javac直接运行(假设您已经sub-donor预先编译了项目)......</p>

javac --add-modules my.donor --module-path sample-so-question-61888059-dev/sub-donor/target/classes --class-path sample-so-question-61888059-dev/sub-recipient/target/classes -d sample-so-question-61888059-dev/sub-recipient/target/classes sample-so-question-61888059-dev/sub-recipient/src/main/java/my/somewhere/*.java

那么javac确实会像有意识地设计那样犹豫不决……</p>

sample-so-question-61888059-dev/sub-recipient/src/main/java/my/somewhere/Main.java:3: error: package my.project.first is not visible
import my.project.first.Cowboy;
                 ^
  (package my.project.first is declared in module my.donor, which does not export it)
1 error

推荐阅读