通过之前对模块化的尝试,乍看下来和普通class/jar包引用差不多,这里就看下具体的区别。

模块化的作用

首先来看下模块的定义:

 A module is a named, self-describing collection of code and data. Its code is organized as a set of packages containing types, i.e., Java classes and interfaces; its data includes resources and other kinds of static information.

模块即代码和数据的一个命名且自描述的集合。代码即java类和接口,而数据是资源或静态信息。
其目的是:
通过可靠的配置,来替代易错的类路径机制,并通过程序组件的形式来显示定义互相之间的依赖
强封装,允许组件定义需要暴露的部分

与一般引用的区别

下面来详细看下模块的构成,一个模块代码逻辑和一般java项目一样,不同的是需要定义module-info.java这个文件,这个文件会定义模块的名字,和requires(引入)和exports(导出)。虽然模块名可以随意定义和内部代码无关,但模块名之间不能冲突,所以一般建议使用和package一样的命名方式来命名。可以看到模块定义中并未出现版本信息,这是因为模块并不希望替代构建工具所做的版本控制。

模块也可以构建成jar包,这个和普通jar包的不同也只是在根目录上多了module-info.class。因此它同时可以充当module,也可以用于普通类包引用。将来可能会有新的打包形式专门打包模块。

所有的模块都会默认引用java.base这个模块,其中包含了平台核心的类如java.io、java.lang等,当然还包括java.lang.module模块系统本身。

在module使用时和一般类也有不同,假设有如下两个module

module com.foo.app {
    requires com.foo.bar;
    requires java.sql;
}

module com.foo.bar {
    requires org.baz.qux;
    exports com.foo.bar.alpha;
    exports com.foo.bar.beta;
}

其中java.sql的定义是

module java.sql {
    requires java.logging;
    requires java.xml;
    exports java.sql;
    exports javax.sql;
    exports javax.transaction.xa;
}

通过图来显示就是

深蓝色的线表示显示引用,浅蓝色表示隐式引用。
当模块之间有引用,如com.foo.app可以访问com.foo.bar,但引用不会传递,所以com.foo.app并不能访问org.baz.qux,除非在com.foo.app中再显示requires org.baz.qux;,这是一般类引用所无法控制的。这正是一开始提到的可靠的配置,模块系统保证每个依赖都有唯一的模块来实现,模块是无环的,模块之间不会互相影响。这同时也会提升系统速度,因为缩小了引用范围。

同时就引出一个问题,如果一个模块的返回时另一个模块中的情况下就需要使用方显示require这些模块,这就给编程造成了复杂度,这种情况下可以使用requires public来进行隐式传递,上面的案例中java.sql中 java.sql.Driver就存在如下的方法,

public Logger getParentLogger();

其中返回了java.logging中的类型,其实真正java.sql模块的定义是。

module java.sql {
    requires transitive java.logging;
    requires transitive java.xml;
    exports java.sql;
    exports javax.sql;
    exports javax.transaction.xa;
}

这里java.logging使用的是requires transitive这种情况下就可以免去调用方的显示引用了。
在jdk的文档中transitive会显示在Indirect Exports中
(经测试发现如果单纯只是print对象的话是不会报错的,显示调用了其中的方法,包括toString方法,在编译期就会报模块不存在的错误,但是将对象转换成Object再通过反射可以成功调用方法)
自此依赖图就成为如下形式。com.foo.app有了到java.logging和java.xml的依赖

参考

http://openjdk.java.net/projects/jigsaw/spec/sotms