• jdk9模块化--特性


    通过之前对模块化的尝试,乍看下来和普通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

  • 相关阅读:
    【秒懂Java】【01_初识Java】04_学习资料
    【秒懂Java】【01_初识Java】03_Java简介
    【秒懂Java】【01_初识Java】02_软件开发
    【秒懂Java】【01_初识Java】01_编程语言
    Apriori算法
    Java并发编程--ThreadLocal内存泄漏原因
    Java并发编程--锁
    Java并发编程--wait/notify/notifyAll 方法的使用
    Java并发编程--线程的生命周期
    Java虚拟机--垃圾收集器--G1收集器
  • 原文地址:https://www.cnblogs.com/resentment/p/8047093.html
Copyright © 2020-2023  润新知