【Java 基础篇】Java 模块化详解
Java 9引入了一项重要的功能:模块化(Module System)。模块化是一种将代码和资源封装到可重用和独立的单元中的方法,它有助于改善代码的可维护性、可重用性和安全性。本文将介绍Java模块化的基本概念、如何创建和使用模块以及一些最佳实践。
什么是Java模块化?
在Java 9之前,Java应用程序是以JAR文件的形式组织的,其中包含了一堆类和资源。这种方式存在一些问题:
- 可维护性差:JAR文件可以包含大量的类和资源,这使得应用程序的结构变得混乱,难以维护。
- 可重用性差:在多个应用程序之间共享代码和资源比较困难。
- 安全性问题:所有的类都在同一个类路径中,这可能导致意外的访问和依赖关系。
Java模块化解决了这些问题。模块是一种新的编程单元,它可以包含类、资源和其他模块的依赖关系。模块化的代码更容易维护,更容易重用,同时也提供了更好的安全性。
模块化的基本概念
在开始使用Java模块化之前,让我们先了解一些基本概念:
1. 模块(Module)
一个模块是一个可重用的单元,它包含了一组相关的类和资源。每个模块都有一个名字,并可以声明自己的依赖关系。
2. 模块声明(Module Declaration)
一个模块声明是一个包含在module-info.java
文件中的文件,它定义了一个模块的名称、依赖关系和其他特性。
3. 模块路径(Module Path)
模块路径是一组目录和JAR文件,其中包含了模块的JMOD文件和module-info.class
文件。模块路径用于告诉JVM哪些模块可用。
4. 模块化 JAR 文件(Modular JAR File)
模块化JAR文件是一种特殊类型的JAR文件,它包含了一个模块的类和资源,以及module-info.class
文件。
5. 自动模块(Automatic Module)
如果一个JAR文件没有module-info.class
文件,它被称为自动模块。自动模块的名称基于JAR文件的文件名,并且具有一些默认的依赖关系。
6. 依赖性(Dependency)
一个模块可以声明对其他模块的依赖关系,以便在编译时和运行时使用其他模块的类和资源。
创建一个简单的模块
让我们从创建一个简单的Java模块开始,以便更好地理解模块化的概念。假设我们有一个应用程序,它有两个模块:一个模块用于处理数据库连接,另一个模块用于处理用户界面。
第一步:创建数据库模块
首先,我们创建一个数据库模块,它包含了一个简单的类DatabaseConnection
:
// DatabaseConnection.java
package com.example.database;public class DatabaseConnection {public void connect() {System.out.println("Connected to the database.");}
}
然后,我们为该模块创建一个module-info.java
文件,声明该模块的名称:
// module-info.java
module databaseModule {
}
这个模块不依赖于其他模块,所以module-info.java
文件中没有声明任何依赖关系。
第二步:创建用户界面模块
接下来,我们创建一个用户界面模块,它包含了一个简单的类UserInterface
:
// UserInterface.java
package com.example.ui;public class UserInterface {public void display() {System.out.println("User interface displayed.");}
}
为该模块创建一个module-info.java
文件,声明该模块的名称和对数据库模块的依赖:
// module-info.java
module uiModule {requires databaseModule;
}
这个模块声明了对databaseModule
的依赖,这意味着它可以使用databaseModule
中的类和资源。
第三步:编译和运行模块
现在,我们可以使用Java 9编译器来编译这两个模块:
javac -d out/database databaseModule/*.java
javac -d out/ui --module-path out databaseModule/*.java uiModule/*.java
然后,我们可以运行UserInterface
类来启动我们的应用程序:
java --module-path out -m uiModule/com.example.ui.UserInterface
这将会输出:
Connected to the database.
User interface displayed.
模块化的更多操作
当您在Java应用程序中使用模块化时,可以执行许多不同的操作,以更好地组织、管理和优化您的代码。以下是一些模块化的更多操作:
-
导出和打包模块:您可以使用
exports
关键字在module-info.java
中声明哪些包可以被其他模块访问。这允许您控制哪些部分的代码对外可见。例如:module myModule {exports com.example.mypackage; }
您还可以使用
opens
关键字导出包,以便其他模块可以反射地访问包中的非公开类型。 -
开放模块:如果您希望模块对所有其他模块开放,可以使用
open
关键字。这对于编写插件或扩展模块很有用。module myModule {open com.example.mypackage; }
-
命令行工具:Java 9引入了一些命令行工具,如
jdeps
,用于分析模块之间的依赖关系,以及jlink
,用于创建自定义运行时映像。 -
运行时图像:您可以使用
jlink
命令将您的模块化应用程序与JRE一起打包成自定义运行时图像。这有助于减小应用程序的大小,因为只包括了应用程序所需的模块。 -
模块路径:模块路径是一个包含模块的目录或JAR文件的集合,它用于在运行时加载模块。您可以使用
--module-path
选项来指定模块路径。 -
自动模块:如果您的应用程序包含非模块化的JAR文件,Java会自动将它们转换为自动模块,以便它们可以与模块一起使用。
-
模块化JAR文件:您可以使用
jar
工具创建模块化的JAR文件,其中包含了模块描述文件(module-info.class
)。 -
模块化库:许多常用的Java库已经进行了模块化,以便更好地与模块化应用程序集成。您可以在模块路径上指定这些库,而无需手动管理它们的依赖关系。
-
模块化测试:使用模块路径和
--module
选项,您可以在单元测试中模拟模块化环境。 -
版本管理:在
module-info.java
中可以使用requires static
关键字来声明可选依赖关系,这些依赖关系只在模块可用时才会生效。
这些是模块化Java应用程序中的一些更多操作。模块化使得Java应用程序更易于维护和扩展,同时提供了更好的封装和可重用性。根据您的项目需求,您可以选择适当的操作来更好地利用模块化的优势。
模块化的最佳实践
以下是一些模块化的最佳实践:
-
模块命名规范:给模块取一个有意义的名字,通常使用逆域名表示法(例如:
com.example.myapp
)。 -
明确的依赖关系:在
module-info.java
文件中明确声明模块的依赖关系,以确保应用程序的模块之间的依赖关系清晰可见。 -
最小依赖原则:尽量减少模块之间的依赖关系,只依赖于真正需要的模块。
-
版本化的依赖关系:如果可能的话,使用版本化的依赖关系来确保模块依赖的是正确的版本。
-
单一责任原则:将每个模块限制为一个特定的功能或领域,以提高可维护性和可重用性。
-
测试和验证:确保模块之间的依赖关系和交互在编译时和运行时都能正常工作。
-
模块路径管理:管理模块路径以确保应用程序能够正确加载和运行。
注意事项
在编写和使用模块化的Java应用程序时,有一些重要的注意事项,以确保您的应用程序正确运行和维护。以下是一些模块化的注意事项:
-
模块依赖关系:仔细考虑您的模块之间的依赖关系。确保模块之间的依赖关系是明确的,避免循环依赖。使用
requires
语句声明依赖关系,并根据需要使用requires transitive
或requires static
。 -
版本管理:了解模块之间的版本管理。Java 9引入了模块化版本的概念,允许模块依赖于特定版本的其他模块。考虑使用
requires static
来声明可选的、仅在特定版本下才有效的依赖关系。 -
模块命名:为您的模块选择合适的名称。模块名称应该唯一且易于理解。遵循Java的包命名约定,使用反向域名(例如
com.example.mymodule
)。 -
模块路径:在运行应用程序时,使用
--module-path
选项指定模块路径。确保正确设置模块路径,以便Java可以找到并加载您的模块。 -
非模块化库:如果您使用了非模块化的JAR文件,将其包装为自动模块或创建模块化的版本。非模块化库的依赖关系可能会引入复杂性。
-
模块化库:考虑使用已经模块化的库,以减少与模块路径和版本管理相关的问题。
-
运行时图像:如果您使用
jlink
创建自定义运行时图像,请确保包括了所有必要的模块,并排除不必要的模块,以减小应用程序的大小。 -
测试:编写单元测试以确保模块化应用程序的正确性。使用模块路径和
--module
选项来模拟模块化环境进行测试。 -
模块描述文件:模块描述文件(
module-info.java
)是模块化应用程序的关键组成部分。确保正确声明依赖关系、导出和打包模块,以及使用其他关键字来管理可见性。 -
模块间通信:模块之间的通信应该在依赖模块的基础上进行。不要尝试绕过模块系统的可见性控制。
-
跨模块访问:如果需要在模块之间共享数据或访问非公开成员,请使用
opens
和opens...to
语句,以允许受信任的模块进行反射操作。 -
性能和内存开销:模块化应用程序的启动时间和内存开销可能会有所增加。在部署和测试应用程序时,要考虑性能方面的因素。
-
迁移:如果您正在迁移现有的应用程序到模块化架构,确保逐步迁移,以减少中断和问题。
-
文档和培训:为开发团队提供关于模块化的文档和培训,以确保所有开发人员都理解和遵守模块化的最佳实践。
-
工具支持:使用Java 9及更高版本,以充分利用模块化系统和相关的工具,如
jdeps
、jlink
和jmod
。
这些注意事项有助于确保您的模块化Java应用程序能够正确运行
结论
Java模块化是一个强大的工具,可以帮助您更好地组织和管理代码,提高可维护性和可重用性。本文介绍了模块化的基本概念,以及如何创建和使用模块。遵循最佳实践,可以使您的Java应用程序更加健壮和可维护。希望本文对您理解Java模块化有所帮助。
作者信息 作者 : 繁依Fanyi CSDN: https://techfanyi.blog.csdn.net 掘金:https://juejin.cn/user/4154386571867191 |
相关文章:

【Java 基础篇】Java 模块化详解
Java 9引入了一项重要的功能:模块化(Module System)。模块化是一种将代码和资源封装到可重用和独立的单元中的方法,它有助于改善代码的可维护性、可重用性和安全性。本文将介绍Java模块化的基本概念、如何创建和使用模块以及一些最…...
【2023面试题大全,都是常问面试题】
JAVA基础 面向对象和面向过程的区别 面向过程:基于步骤的编程方式,用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可 面向对象:基于对象的编程方式,通过定义类来描述对象的属性和行为,面向对…...

Bun 1.0 正式发布,爆火的前端运行时,速度遥遥领先!
文章目录 一、包子1.0二、Bun 是一个一体化工具包为什么包子存在 二、Bun 是一个 JavaScript 运行时Node.js 兼容性速度TypeScript 和 JSX 支持ESM 和 CommonJS 兼容性网络 API热重载插件 一、包子1.0 Bun 1.0终于来了。 Bun 是一个快速、一体化的工具包,用于运行…...
getchar函数设置为非阻塞
一. 前言 我们在学习C语言的时候,getchar都是阻塞的,等待用户输入字符并且输入回车后才返回。但是有时候我们希望把getchar设置为非阻塞,或者说,当我们遇到getchar函数变成非阻塞的了,我们应该怎么解决这个问题&#x…...
【超算作业调度系统--LSF】
集群服务器--LSF作业调度系统使用 0 Introdutction1 命令1.1 bsub--作业提交命令1.1.1 $ bqueues --查看现有队列信息;1.1.2 $lsload --查看各节点运行情况1.1.3 $bhosts --查看各节点空闲情况1.1.4 $busers --查看用户信息1.2 bsub --提交作业1.2.1 bsub OMP_NUM_T…...
L1-011 A-B分数 20
本题要求你计算A−B。不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。 输入格式: 输入在2行中先后给出字符串A和B。两字符串的长度都不超过104,并且保证每个字符…...
PHPword解析内容支撑
因有些功能不支持,所以新增了某些功能,以防后期变动不好变更,手动做个记录 将公式替换成指定的符号,读取到 html 后读取 xml 解析公式,根据标记符号进行替换 文件名PhpOffice\PhpWord\Shared\XMLReader.php public fun…...

回归预测 | MATLAB实现RUN-XGBoost龙格库塔优化极限梯度提升树多输入回归预测
回归预测 | MATLAB实现RUN-XGBoost多输入回归预测 目录 回归预测 | MATLAB实现RUN-XGBoost多输入回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现RUN-XGBoost多输入回归预测(完整源码和数据) 1.龙格库塔优化XGBoost,…...

LLM-TAP随笔——语言模型训练数据【深度学习】【PyTorch】【LLM】
文章目录 3、语言模型训练数据3.1、词元切分3.2、词元分析算法 3、语言模型训练数据 数据质量对模型影响非常大。 典型数据处理:质量过滤、冗余去除、隐私消除、词元切分等。 训练数据的构建时间、噪音或有害信息情况、数据重复率等因素都对模型性能有较大影响。训…...
Linux- open() lseek()
文件描述符 文件描述符(File Descriptor,简称 FD)是 UNIX 和 UNIX-like 系统中用于代表和识别打开的文件或其他I/O资源的一种抽象标识。它是一个非负整数,内部由操作系统进行管理和分配。文件描述符可以代表文件、套接字、管道等…...
Halcon Tuple相关算子(一)
(1) tuple_length( : : Tuple : Length) 功能:返回输入元组中元素的个数。 控制输入参数: Tuple:输入元组; 控制输出参数:length:输入元组中元素的个数。 (2) tuple_find( : : Tuple, ToFind : Indices…...

基于图像形态学处理的路面裂缝检测算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...................................................... %1:从文件夹中读取多个…...

PY32F003F18之窗口看门狗
一、PY32F003F18窗口看门狗特点: 即使窗口看门狗被禁止,窗口看门狗的"递减计数器"也会继续递减计数。 二、窗口看门狗复位的条件: 1、将"控制寄存器WWDG_CR"中的WDGA1,激活"窗口看门狗计数器等于0x3F"时,则产…...

SpingBoot:整合Mybatis-plus+Druid+mysql
SpingBoot:整合Mybatis-plusDruid 一、特别说明二、创建springboot新工程三、配置3.1 配置pom.xml文件3.2 配置数据源和durid连接池3.2.1 修改application.yml3.2.2 新增mybatis-config.xml 3.3 编写拦截器配置类 四、自动生成代码五、测试六、编写mapper.xml&#…...

计算机视觉与深度学习-经典网络解析-VGG-[北邮鲁鹏]
目录标题 VGG参考VGG网络贡献使用尺寸更小的$3 \times 3$卷积串联来获得更大的感受野放弃使用$11 \times 11$和$5 \times 5$这样的大尺寸卷积核深度更深、非线性更强,网络的参数也更少;去掉了AlexNet中的局部响应归一化层(LRN)层。 网络结构主要改进输入…...

入门级制作电子期刊的网站推荐
随着数字化时代的到来,越来越多的人开始尝试制作自己的电子期刊。如果你也是其中的一员,那么这篇文章可以帮助你制作电子期刊。无论是初学者还是有一定经验的制作者,都能快速完成高质量的电子期刊制作 小编经常使用的工具是-----FLBOOK在线制…...

软件测试内容整理
1. 软件测试 1.1. 定义 软件测试(英语:Software Testing),描述一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。换句话说,软件测试是一种实际输出与预期输出之间的审核或者比较过程。 软件测试的经典定…...

UniAccess Agent卸载
异常场景: UniAccess Agent导致系统中的好多设置打不开 例如:ipv4的协议,注册表,host等等 需要进行删除,亲测有效,及多家答案平凑的 借鉴了这位大神及他里面引用的大神的内容 https://blog.csdn.net/weixin_44476410/article/details/121605455 问题描述 这个进…...

【C++】C++11——构造、赋值使用条件和生成条件
移动构造和移动赋值生成条件移动构造和移动赋值调用逻辑强制生成默认函数的关键字default禁止生成默认函数的关键字delete 移动构造和移动赋值生成条件 C11中新增的移动构造函数和移动赋值函数的生成条件为: 移动构造函数的生成条件:没有自己实现的移动…...

【LeetCode热题100】--56.合并区间
56.合并区间 排序: 如果按照区间的左端点排序,那么在排完序的列表中,可以合并的区间一定是连续的,如下图所示,标记为蓝色、黄色和绿色的区间分别可以合并为一个大区间,它们在排完序的列表中是连续的 算法&a…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...