首页 > 其他分享 >JDK9新特性说明

JDK9新特性说明

时间:2023-11-28 21:57:00浏览次数:37  
标签:info java JDK module 说明 JDK9 特性 模块 Java

1、Java 模块化

1.1、概念介绍

Java模块化相比是大家听到的最多的,也是JDK9的重大更新之一,关于什么是Java 模块系统?官方是这么解释的:
一个命名的、自我描述的代码和数据集合。
  该模块系统包含了:
  • 一个新的可选阶段,链接时间,它位于编译时间和运行时间之间,在这个阶段,一组模块可以被组装和优化成一个定制的运行时映像;请参阅 Java Platform, Standard Edition Tools Reference 中的 jlink 工具。
  • 往javac jlink java 命令中增加了选项,可以在这些选项中指定模块路径,用于定位模块的定义。
  • 引入了模块化JAR文件,它是一个在其根目录中包含一个文件的JAR文件.module-info.class
  • 引入了JMOD格式,这是一种类似于JAR的打包格式,除了可以包含本地代码和配置文件之外;请参阅jmod工具。
  同时,JDK本身已被划分为一组模块。改变化带来以下改变:
  • 能够将 JDK 的模块组合到各种配置中,包括:
    • 对应于 JRE 和 JDK 的配置。
    • 配置在内容上大致等同于 Java SE 8 中定义的每个 Compact Profile
    • 仅包含一组指定模块及其所需模块的自定义配置。
  • 重新构造了JDK和JRE运行时映像,以适应模块并改善性能、安全性和可维护性。
  • 为在运行时映像中命名模块、类和资源定义了一个新的URI方案,而不会揭示映像的内部结构或格式。
  • 删除了 endorsed-standards override(认可标准覆盖)机制和 extension (扩展)机制。

  • 从Java运行时映像中移除了 rt.jar 和 tools.jar

  • 默认情况下,使 JDK 的大多数内部 API 无法访问,但保留一些关键的、广泛使用的内部 API 可访问,直到它们的所有或大部分功能都存在受支持的替代品。运行 jdeps -jdkinternals 命令以确定您的代码是否使用内部 JDK API。

 

上面这部分大多数人看描述也是一头雾水,接下来让我们通过下面的例子来揭开Java模块化的面纱。  

实战

使用IDEA,创建一个基于jdk9的maven项目

 

  再创建两个module,一个叫做modulea,另外一个叫做moduleb。

 

在modulea中,创建一个类,名字叫做ModuleA

 

moduleb中,也创建一个叫做ModuleB的类

 

此时,假如我们想要早ModuleB这个类中,调用ModuleA的方法,按照jdk9之前的方式,肯定是先设置好pom版本依赖

 

然后在ModuleA中直接引用就行了。

 

运行后打印:

 

看起来好像没啥差别对吧? 确实,因为JDK的版本升级(最大化)保证了低版本的兼容,在JDK9版本下,这种方式定义的module叫做无名模块,用来兼容老版本升级新jdk时,未定义的情况。

无名模块

什么是无名模块呢?
无名模块有一些默认的行为和限制。它无法显示地声明依赖关系,也无法导出任何包。但是,它仍然可以访问其他模块的公共 API。
那怎么样可以把一个module定义为JDK9的module呢?
从 JDK 9 开始,Java 引入了模块化系统,每个模块都需要一个 module-info.java 文件来声明模块的信息。module-info.java 文件是模块的入口点,它包含了模块的名称、依赖关系和导出的包等信息。如果你想在 JDK 9 或更高版本中使用模块化特性,你必须在每个模块中声明一个 module-info.java 文件。

module-info.java结构和限制

module 模块名称 {         // 导出的包声明         // 依赖关系声明         // 其他模块特定的声明 }
各个声明定义:
  • 导出的包声明(exports):使用 exports 关键字声明模块导出的包,其他模块可以访问这些包下的公共类和接口。
  • 依赖关系声明(requires):使用 requires 关键字声明模块的依赖关系,指定该模块依赖的其他模块。
  • 其他模块特定的声明:还可以在 module-info.java 文件中添加其他模块特定的声明,如使用 provides 和 uses 关键字来实现服务提供者接口。 

module-info.java

同时 module-info.java 也是有一些其他限制
在一个模块中,只能有一个 module-info.java 文件。这个文件定义了模块的名称、依赖关系和其他模块特定的信息。如果在同一个模块中出现多个 module-info.java 文件,编译器将会报错。因此,每个模块只能有一个 module-info.java 文件。   module-info.java 文件应该放在一个名为 "module-name/src/main/java/module-info.java" 的目录中,其中 "module-name" 是模块的名称。   module-info.java还有一些其他的关键字: 1. requires:用于声明一个模块依赖的其他模块。 2. exports:用于声明一个模块导出的包,使其他模块可以访问该包下的公共类和接口。 3. opens:用于声明一个模块开放(暴露)指定的包,允许其他模块访问该包中的类。 4. provides:用于声明一个模块提供的服务接口的实现。 5. uses:用于声明一个模块使用的服务接口。 6. transitive:用于声明一个模块的依赖是传递性的,使依赖当前模块的其他模块也自动依赖当前模块所依赖的模块。
 

改造

根据定义和限制,我们定义好modulea和moduleb的package-info.java文件

 

 

  至此,我们就把module和moduleb定义为一个java 模块了。 但此时,再尝试运行ModuleB的main方法,就无法正常运行了

 

可以看到,报错信息提示虽然 com.gonzo.study.jdk9.modulea 已经定义在模块 study.modulea中,但study.moduleb无法读到它。 当然,idea也很贴心的给出了解决建议,按照建议执行后,回到moduleb的package-info.java,看到加了这么一条。

 

requires study.modulea; 随后继续运行ModuleB的main方法成功:

 

 

思考

通过这个例子,想必大家已经初步理解了模块化的概念,同时也会新增很多疑问,例如:
  • 如果不定义package-info.java,能不能引入定义了package-info.java的模块?
  • 这么定义有什么作用?
  针对第一个问题,通过我的验证,可以从下表中找出答案:
模块 modulea moduleb 是否可以引用到
是否定义了 package-info.java 文件 可以
不可以,报错: Package 'com.gonzo.study.jdk9.modulea' is declared in the unnamed module, but module 'study.moduleb' does not read it
可以
可以,只要在moduleb中生命对modulea的requires
而第二个问题,经过我的资料查找,得到如下的说法:
1. 更好的封装和隔离:模块化系统通过将代码组织成模块,强制实施模块间的明确边界和依赖关系。这样可以更好地封装和隔离代码,减少模块之间的耦合,提高代码的可维护性和可重用性。 2. 显式的依赖管理:模块化系统要求在每个模块中明确声明其依赖关系。这样可以更清晰地了解代码的依赖关系,减少意外的依赖问题,并提供更好的版本管理和冲突解决机制。 3. 更小的运行时环境:模块化系统允许在构建应用程序时只包含所需的模块,从而减少了运行时环境的大小。这可以减少应用程序的启动时间和内存占用,并简化应用程序的部署和分发。 4. 安全性增强:模块化系统通过明确的模块边界和访问控制,提供了更好的安全性。只有明确导出的包才能被其他模块访问,其他模块无法直接访问未导出的包,从而减少了潜在的安全漏洞。 5. 更好的可维护性和可读性:模块化系统鼓励开发者将代码组织成独立的模块,每个模块都有明确的目的和职责。这样可以提高代码的可读性和可维护性,使开发者更容易理解和修改代码。
抛开哪些轱辘话,我觉得第三点是最大的进步。 Java早些时候一直被诟病吃内存,其中一个原因就是因为一个大型项目要依赖的第二、第三方包是不计其数的。但实际上引入一个包可能只需要里面的某一小部分类,在JDK9之前只能全部导入。 但有了模块化之后,可以指定需要的包的导入,这样依赖,针对不需要的包就排除在外了。编译运行时,这些被排除的包节省下来的时间和内存也是很客观的。  

新版本字符串方案

JDK 9 引入了一种新的字符串实现方案,称为Compact Strings(紧凑字符串),与 JDK 8 的字符串实现方案有一些区别。 在 JDK 8 中,Java 字符串由 char 数组和一个 int 字段(offset)组成,用于存储字符串的字符数据和偏移量。这种实现方式在大多数情况下效果很好,但对于包含大量ASCII字符的字符串,会浪费一些内存空间,因为每个字符都需要占用两个字节。 JDK 9 中的 Compact Strings 方案旨在减少这种内存浪费。在 Compact Strings 中,Java 字符串使用 byte 数组来存储字符数据,而不是 char 数组。对于只包含ASCII字符的字符串,每个字符只需要占用一个字节,这样就可以节省一半的内存空间。 这种改进对于许多应用程序来说是透明的,因为它只是在内部对字符串的实现进行了优化。大多数情况下,应用程序的行为和性能不会受到影响。但对于那些处理大量ASCII字符的应用程序,Compact Strings 可能会带来显著的内存节省和性能提升。 需要注意的是,Compact Strings 方案只适用于默认的编码方案(如UTF-16),对于其他编码方案(如UTF-8),仍然使用传统的 char 数组实现。此外,Compact Strings 的具体实现细节可能因不同的JVM实现而有所不同。 总的来说,JDK 9 的 Compact Strings 方案通过优化字符串的内存占用,提供了更高效的字符串表示方式,特别是对于包含大量ASCII字符的字符串。   JDK8的String源码:

  JDK9的String源码:

 

 

Java Shell

简介: 一个交互式命令行工具。 它允许开发人员在命令行中直接执行和测试Java代码片段,而无需编写完整的Java程序。 Java Shell提供了一个交互式的环境,类似于Python的交互式解释器或Ruby的IRB。它可以用于快速验证代码、尝试新的API功能、学习和教学等场景。 使用Java Shell,你可以逐行输入和执行Java代码,立即查看结果。它支持Java的语法和特性,包括变量定义、表达式计算、方法调用等。你还可以在Java Shell中定义和操作变量,以便在后续的代码片段中使用。   使用方式: 打开命令行,输入 jshell,就进入了java shell的运行环境

 

 

简单调试下

 

 

关于其他更多的交互,可以参考java shell的官方文档。  

JVM 部分

  • 将 G1 设为默认垃圾回收器
  • 弃用并发标记扫描 (CMS) 垃圾回收器
  • 删除 JDK 8 中不推荐使用的 GC 组合
    • DefNew + CMS 
    • ParNew + SerialOld 
    • Incremental CMS
  • 并发标记扫描 (CMS) 的“前台”模式也已被删除。删除了以下命令行标志:

    • -Xincgc
    • -XX:+CMSIncrementalMode
    • -XX:+UseCMSCompactAtFullCollection
    • -XX:+CMSFullGCsBeforeCompaction
    • -XX:+UseCMSCollectionPassing

命令行标志不再起作用。ParNew 只能与 CMS 一起使用,而 CMS 需要 ParNew。因此,该标志已被弃用,可能会在将来的版本中删除。-XX:+UseParNewGC-XX:+UseParNewGC

以上就是JDK9新增的主要功能,当然还有很多其他功能,没有一一列出来,具体可以参考官方文档查看更多:

Java Platform, Standard Edition What’s New in Oracle JDK 9, Release 9

   

标签:info,java,JDK,module,说明,JDK9,特性,模块,Java
From: https://www.cnblogs.com/gonzo/p/17863170.html

相关文章

  • 宝锋UV-5R说明书下载
    宝锋UV-5R说明书下载          宝锋UV-5R说明书百度网盘下载地址:   链接:https://pan.baidu.com/s/1QJXEJ2YyO7ovMAQG7Uur4A    提取码:j8d2 ......
  • 系统安装说明书
    1、安装lnmp1、wgethttps://soft.lnmp.com/lnmp/lnmp2.0.tar.gz2、./install.sh2、下载代码gitclonehttps://gitee.com/sdyansong/zycx_system.git3、配置nginx.confserver{listen80default_serverreuseport;#listen[::]:80default_se......
  • dremio 的自服务语义层创建简单说明
    内容来自官方文档,介绍了一些关于dremio的数据语义层的玩法原则分层 通过分层可以确保安全,性能以及可用性,dremio提供了一个对于语义层的最佳实践数据集的注释增强发现以及可理解性 可以通过tag以及文档(wiki)进行数据的描述最佳实践使用1:1的预处理层 此层的数据接近原始数据源......
  • Markdown使用说明
    Markdown使用规范目录Markdown使用规范0、使用VSCode编写Markdown代码1、正文段落2、标记3、分割线4、标题5、引用6、列表有序列表无序列表7、代码段段落内嵌代码代码区块8、插入图片9、插入链接10、公式11、表格12、代办事项13、列出全部标题TOC参考资料和网址0、使用VSCode编......
  • js获取元素特性值+js修改元素特性值
    js获取元素特性值--元素<formclass="layui-formlayui-form-panelayui-form-itemus-form"id="us-form"usdata="{usurl:'/usanaly/roomenergylog/usgetentity',ussurl:'/usanaly/roomenergylog/usupdate',usload:'......
  • 关于ppm.m与molecule/cm2单位转换的说明
    现在想象一个截面积为\(1cm^2\)、长为1m的长方体,内部填充着摩尔质量为\(M_g\)的特殊气体。其柱浓度为Xppm.m,设柱浓度可以表示为Y\(molecule/cm^2\),求Y。假设标准大气压条件,摩尔体积为\(22.4L/mol\),并且\(1mol=6.02*10^{23}molecule(分子数)\)。解答:长方体的体积......
  • JDK版本特性演变
    JDK版本特性演变官网JEP指数Jdk1~8JDK1.0(1996年1月):初版发布。包含了基本的Java开发工具,如编译器(javac)和解释器(java)。JDK1.1(1997年2月):引入了内部类(InnerClasses)。支持JavaBeans组件模型。增加了AWT事件处理模型。引入了RMI(远程方法调用)和JDBC(Java数据库连接......
  • MySQL8.x 中 performance_schema 下 processlist表的说明
    MySQL8.x中performance_schema下processlist表的说明最近在研究一个MySQL数据库的监控相关功能的系统的实现,因此专门研究了一下processlist表。processlist表为MySQL的核心表之一。MySQLprocesslist表示当前由服务器内执行的线程集执行的操作。进程列表表是进程信息的来......
  • Java三大特性:抽象、封装和多态
    Java是一种广泛使用的编程语言,它的三大基本特性是抽象、封装和多态。这些特性是Java的核心,也是理解Java的关键。以下是对这三个特性的详细解释,并通过示例进行说明。一、抽象抽象是Java的一个重要特性,它允许我们定义只展现关键细节的类或接口。抽象有两种形式:隐式抽象和显式抽象。隐......
  • C++11以及17部分特性
    1//1、并发支持2//1.1、C++11内存模型:3//a.原子性(Atomicity):对于原子类型(std::atomic),其成员函数的操作是原子的,不会被其他线程中断。4//b.可见性(Visibility):对于非原子类型,通过使用互斥量或同步操作来确保共享数据的可见性,即在一个线程中对共享数据的......