Bootstrap

Java模块化中的自动模块与包拆分问题

在Java模块化(Java Platform Module System,JPMS)引入后,模块化编程成为Java开发中的一个重要方向。然而,在实际开发中,模块化应用与非模块化库之间的交互可能会引发一些有趣的问题,比如包拆分(split packages)问题。本文将通过一个具体的实例,探讨自动模块(Automatic Modules)和包拆分问题,并分析其解决方案。
一、自动模块的概念
自动模块是指那些没有显式定义module-info.java的JAR文件,当它们被模块化应用依赖时,JAR文件会被视为一个模块。模块的名称通常由JAR文件的名称决定。例如,一个名为core-parser.jar的JAR文件会被视为core.parser模块。
二、实例分析
(一)非模块化库
我们先创建一个非模块化的库core-parser,它包含一个简单的XML解析工具类XmlParserUtil。
core-parser/src/parser/xml/XmlParserUtil.java
java复制
package parser.xml;

public class XmlParserUtil {
public static String parse(String data) {
return "parsed data " + data;
}
}
这个库没有module-info.java,因此它是一个自动模块。
(二)模块化应用
接下来,我们创建一个模块化应用parser-app,它依赖于core-parser库。
parser-app/src/parser/xml/AppMain.java
java复制
package parser.xml;

public class AppMain {
public static void main(String[] args) {
String data = XmlParserUtil.parse(“test data”);
System.out.println(data);
}
}
parser-app/src/module-info.java
java复制
module parser.app {
requires core.parser;
}
在requires子句中,我们使用core.parser作为库模块的名称,这与core-parser.jar的名称相对应。
(三)编译与运行

  1. 编译非模块化库
    bash复制
    D:\split-packages-and-automatic-modules\core-parser>javac -d out src\parser\xml\XmlParserUtil.java
  2. 创建JAR文件
    bash复制
    D:\split-packages-and-automatic-modules>jar --create --file core-parser.jar -C core-parser\out .
  3. 编译模块化应用
    将core-parser.jar移动到parser-app的lib目录下:
    bash复制
    D:\split-packages-and-automatic-modules>mkdir parser-app\lib
    D:\split-packages-and-automatic-modules>move core-parser.jar parser-app\lib\core-parser.jar
    尝试编译模块化应用:
    bash复制
    D:\split-packages-and-automatic-modules\parser-app>javac --module-path lib -d out src\module-info.java src\parser\xml\AppMain.java
    然而,编译失败,报错如下:
    复制
    src\parser\xml\AppMain.java:1: error: package exists in another module: core.parser
    package parser.xml;
    ^
    src\parser\xml\AppMain.java:6: error: cannot find symbol
    String data = XmlParserUtil.parse(“test data”);
    ^
    symbol: variable XmlParserUtil
    location: class AppMain
    2 errors
    这是因为模块化应用和自动模块都定义了相同的包parser.xml,导致了包拆分问题。Java模块化不允许包拆分,即使在自动模块中也是如此。
    (四)解决方案:不使用模块路径
    如果去掉module-info.java,将parser-app作为未命名模块运行,可以避免包拆分问题。
    编译为未命名模块
    bash复制
    D:\split-packages-and-automatic-modules\parser-app>javac --class-path lib\core-parser.jar -d out src\parser\xml\AppMain.java
    运行
    bash复制
    D:\split-packages-and-automatic-modules\parser-app>java --class-path lib\core-parser.jar;out parser.xml.AppMain
    parsed data test data
    可以看到,程序成功运行并输出了结果。
    三、总结
    通过这个实例,我们了解到自动模块和包拆分问题在Java模块化中的复杂性。虽然自动模块为非模块化代码提供了向后兼容性,但在模块化应用中,包拆分仍然是一个需要谨慎处理的问题。如果可能,尽量避免在模块化应用和自动模块中使用相同的包名,或者通过将应用降级为未命名模块来解决包拆分问题。
;