前言

JDK9引入的Java模块化系统(Java Platform Module System ,JPMS)是 对Java技术的一次重要升级,除了像之前JAR包那样充当代码的容器之外,还包括:

  • 依赖其他模块的列表。
  • 导出的包列表,即其他模块可以使用的列表。
  • 开放的包列表,即其他模块可反射访问模块的列表。
  • 使用的服务列表。
  • 提供服务的实现列表。

模块化系统

可配置的封装隔离机制解决了原来类路径上跨文件的public类的可访问性的问题。public类型不再意味着所有地方代码都可以访问它们,未导出未开放的类是不能够被外部使用。

举例说明:

新创建一个maven工程,并创建两个module。

在每个module的Language level 和 SDK 设置成JDK9

然后在每个module的顶层目录中创建module-info.java

在ExampleOne中创建两个不同package下的类,ExampleFirstExampleOne

package com.jimoer.jdkmoduleOne.test;

public class ExampleFirst {

    private int id;

    private String name;

    private String sex;

    public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public String toString() {
return "ExampleFirst{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
package com.jimoer.jdkmoduleOne;

public class ExampleOne {

    private int id;

    private String name;

    private String arg;

    public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getArg() {
return arg;
} public void setArg(String arg) {
this.arg = arg;
} @Override
public String toString() {
return "ExampleOne{" +
"id=" + id +
", name='" + name + '\'' +
", arg='" + arg + '\'' +
'}';
}
}

然后在ExampleOne的module-info.java中声明导出包的路径。

module exampleOne {

     // 导出包路径
exports com.jimoer.jdkmoduleOne.test; }

在ExampleTwo中声明requires为引入包

module exampleTwo {
requires exampleOne;
}

然后在ExampleTwo中使用ExampleOne中的类

ublic class ExampleTwo {

    public static void main(String[] args) {

        ExampleFirst first = new ExampleFirst();

        first.setId(1);
first.setName("余欢水");
first.setSex("男"); System.out.println(first);
}
}

运行结果:

ExampleFirst{id=1, name='余欢水', sex='男'}

但是当在ExampleTwo中引用ExampleOne中非导出包下的类时就会编译出错。



如上图提示,所有不被导出的包默认都被封装在模块里面。

模块的兼容性

为了使可配置的封装隔离机制能够兼容传统的类路径查找机制,JDK9提出了与“类路径”(ClassPath)相对应的“模块路径”(ModulePath)的概念。只要放在类路径上的JAR文件,都会被当作传统的JAR包来对待;相应地,只要放在模块路径上的JAR文件,即使没有使用JMOD后缀,甚至不包含module-info.class文件,也仍然会被当作一个模块来对待。

为了保证Java应用升级到JDK9之后依然使用传统的类路径,不会受到影响,制定了三条规则来保证兼容性。

  • JAR文件在类路径的访问规则:所有类路径下的JAR文件及其他资源文件,都被视为自动打包在一个匿名模块(Unnamed Module)里,这个匿名模块几乎是没有任何隔离的,它可以看到和使用类路径上所有的包、JDK模块中所有的导出包,以及模块路径是哪个所有模块中导出的包。
  • 模块在模块路径的访问规则:模块路径下的具名模块(Named Module)只能访问到她依赖定义中列明依赖的模块和包,匿名模块里所有的内容对具名模块来说都是不可见的,即具名模块看不见传统JAR包的内容。
  • JAR文件在模块路径的访问规则:如果把一个传统的、不包含模块定义的JAR文件放置到模块路径中,它就会变成一个自动模块(Automatic Module)。

模块化下的类加载器

JDK9为了保证兼容性,依然保持了三层类加载器架构以及双亲委派模型。但是为了模块化系统的顺利实施,还是对类加载器做了一些改动。

  • 首先,扩展类加载器(Extension Class Loader)被平台类加载器(Platform Class Loader)取代。因为模块化天然的支持扩展,自然不需要在存在扩展类加载器了。
  • 其次,平台类加载器和应用类加载器都不再派生自java.net.URLClassLoader,如果有程序直接依赖了这种继承关系,或者依赖了URLClassLoader类特定方法,那代码很可能会在JDK9及更高版本的JDK中崩溃。
  • 最后,JDK9中虽然仍然维持着三层类加载器和双亲委派架构,但类加载的委派关系也发生了变动。当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责哪个模块的加载器完成加载,这可以算是对双亲委派的第四次破坏。

    JDK9前后三层类加载器的架构图对比如下:

深入理解JVM(③)Java的模块化的更多相关文章

  1. 深入理解JVM—Java 6 JVM参数配置说明

    原文地址:http://yhjhappy234.blog.163.com/blog/static/316328322011119111014657/ 使用说明< xmlnamespace pre ...

  2. 深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略

    身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级.融会贯通则为高级 作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理 近期在看深入理解java虚拟机 ...

  3. 深入理解JVM : Java垃圾收集器

    如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都可能会有很大差 ...

  4. 深入理解JVM - Java内存模型与线程 - 第十二章

    Java内存模型 主内存与工作内存 Java内存模型主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节.此处的变量(Variable)与Java编程中 ...

  5. 深入理解JVM - Java内存区域与内存溢出异常 - 第二章

    一 运行时数据区域 JVM在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间. 程序计数器 程序计数器(Program Counter ...

  6. 深入理解JVM内幕:从基本结构到Java 7新特性

    转自:http://www.importnew.com/1486.html 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境 ...

  7. 深入理解JVM内幕:从基本结构到Java 7新特性[转]

    英文原文:cubrid,编译:ImportNew - 朱伟杰 译文链接:http://www.importnew.com/1486.html [如需转载,请在正文中标注并保留原文链接.译文链接和译者等 ...

  8. Java工程师学习指南第6部分:深入理解JVM虚拟机

    本文整理了微信公众号[Java技术江湖]发表和转载过的JVM虚拟机相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. JVM原理分析,看了都说好 JVM 深入学习:Java 解析 Cl ...

  9. 深入理解JVM虚拟机11:Java内存异常原理与实践

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

  10. 从JAVA内存到垃圾回收,带你深入理解JVM

    摘要:学过Java的程序员对JVM应该并不陌生,如果你没有听过,没关系今天我带你走进JVM的世界.程序员为什么要学习JVM呢,其实不懂JVM也可以照样写出优质的代码,但是不懂JVM有可能别被面试官虐得 ...

随机推荐

  1. 看不见远程新建git分支

    再网页上新建了一个git分支.然后在本地跑git branch -r(查看远程分支)/ git branch -a(查看所有分支)两个命令,都没有看到新建的那个分支.这是为啥呢??? 原因是因为:gi ...

  2. Java实现 蓝桥杯 算法训练 求平方和

    试题 算法训练 求平方和 问题描述 请用函数重载实现整型和浮点习型的两个数的平方和计算 输入格式 测试数据的输入一定会满足的格式. 2 2(2行2列,第1行整型,第2行浮点型) 输出格式 要求用户的输 ...

  3. Java实现 LeetCode 638 大礼包(阅读理解题,DFS)

    638. 大礼包 在LeetCode商店中, 有许多在售的物品. 然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品. 现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单.请输 ...

  4. Java实现 LeetCode 820 单词的压缩编码(字典树)

    820. 单词的压缩编码 给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A. 例如,如果这个列表是 ["time", "me", & ...

  5. Java实现 LeetCode 524 通过删除字母匹配到字典里最长单词(又是一道语文题)

    524. 通过删除字母匹配到字典里最长单词 给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到.如果答案不止一个,返回长度最长且字典顺序最小的字符 ...

  6. RocketMQ系列(二)环境搭建

    RocketMQ的基本概念在上一篇中给大家介绍了,这一节将给大家介绍环境搭建.RocketMQ中最基础的就是NameServer,我们先来看看它是怎么搭建的. NameServer RocketMQ要 ...

  7. 运用Navicat for MySQL进行MSSQL数据转移MYSQL

    当前不同数据库进行数据转移已经不是一件麻烦事情,特别是有很多很方便的工具,而最近我在搜集各种数据时候,也需要进行大量的数据转移,并且数据库和所转移的数据库表都不同,这次给大家介绍个最简单的方法,就是使 ...

  8. sqlite使用dbexpress时数据库不存在自动建立数据库

    在发布使用delphi dbexpress编写的基于SQLITE的程序时,需要在运行时判断某个数据库是否存在,如果不存在,则自动建立. 方法有2,其中之一是判断数据库文件是否存在,如果不存在,则创建一 ...

  9. Vue-Cli4.x配置文件路径别名

    一.目录结构 二.配置方法 提示:和package.json同级新建vue.config.js文件(可选文件,默认没有创建). const path = require('path');//引入pat ...

  10. 09.Django-信号

    目录 Django中的信号及其用法 Django中内置的signal 内置信号的使用 自定义信号 Django中的信号及其用法 Django中提供了"信号调度",用于在框架执行操作 ...